Skip to content

Commit b03cafd

Browse files
committed
Fix bug #77966: Cannot alias a method named "namespace"
This is a bit tricky: In this cases we have "namespace as", which means that we will only recognize "namespace" as an identifier when the lookahead token is already at the "as". This means that zend_lex_tstring picks up the wrong identifier. We solve this by actually assigning the identifier as the semantic value on the parser stack -- as in almost all cases we will not actually need the identifier, this is just an (offset, size) reference, not a copy of the string. Additionally, we need to teach the lexer feedback mechanism used by tokenizer TOKEN_PARSE mode to apply feedback to something other than the very last token. To that purpose we pass through the token text and check the tokens in reverse order to find the right one. Closes GH-5668.
1 parent 08518b1 commit b03cafd

10 files changed

+310
-179
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ PHP NEWS
2929
extensions). (cmb)
3030
. Implemented FR #72089 (require() throws fatal error instead of exception).
3131
(Nikita)
32+
. Fixed bug #77966 (Cannot alias a method named "namespace"). (Nikita)
3233

3334
- BZ2:
3435
. Fixed bug #71263 (fread() does not report bzip2.decompress errors). (cmb)

Zend/tests/bug77966.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Bug #77966: Cannot alias a method named "namespace"
3+
--FILE--
4+
<?php
5+
6+
trait A {
7+
function namespace() {
8+
echo "Called\n";
9+
}
10+
}
11+
12+
class C {
13+
use A {
14+
namespace as bar;
15+
}
16+
}
17+
18+
$c = new C;
19+
$c->bar();
20+
$c->namespace();
21+
22+
?>
23+
--EXPECT--
24+
Called
25+
Called

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ static int zend_add_const_name_literal(zend_string *name, zend_bool unqualified)
653653
void zend_stop_lexing(void)
654654
{
655655
if (LANG_SCNG(on_event)) {
656-
LANG_SCNG(on_event)(ON_STOP, END, 0, LANG_SCNG(on_event_context));
656+
LANG_SCNG(on_event)(ON_STOP, END, 0, NULL, 0, LANG_SCNG(on_event_context));
657657
}
658658

659659
LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);

Zend/zend_compile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,17 @@ typedef struct _zend_file_context {
117117
HashTable seen_symbols;
118118
} zend_file_context;
119119

120+
typedef struct {
121+
uint32_t offset;
122+
uint32_t len;
123+
} zend_lexer_ident_ref;
124+
120125
typedef union _zend_parser_stack_elem {
121126
zend_ast *ast;
122127
zend_string *str;
123128
zend_ulong num;
124129
unsigned char *ptr;
130+
zend_lexer_ident_ref ident;
125131
} zend_parser_stack_elem;
126132

127133
void zend_compile_top_stmt(zend_ast *ast);

Zend/zend_globals.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ struct _zend_php_scanner_globals {
311311
int scanned_string_len;
312312

313313
/* hooks */
314-
void (*on_event)(zend_php_scanner_event event, int token, int line, void *context);
314+
void (*on_event)(
315+
zend_php_scanner_event event, int token, int line,
316+
const char *text, size_t length, void *context);
315317
void *on_event_context;
316318
};
317319

Zend/zend_language_parser.y

Lines changed: 82 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,84 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
9696
%token <ast> T_STRING_VARNAME "variable name (T_STRING_VARNAME)"
9797
%token <ast> T_NUM_STRING "number (T_NUM_STRING)"
9898

99+
%token <ident> T_INCLUDE "include (T_INCLUDE)"
100+
%token <ident> T_INCLUDE_ONCE "include_once (T_INCLUDE_ONCE)"
101+
%token <ident> T_EVAL "eval (T_EVAL)"
102+
%token <ident> T_REQUIRE "require (T_REQUIRE)"
103+
%token <ident> T_REQUIRE_ONCE "require_once (T_REQUIRE_ONCE)"
104+
%token <ident> T_LOGICAL_OR "or (T_LOGICAL_OR)"
105+
%token <ident> T_LOGICAL_XOR "xor (T_LOGICAL_XOR)"
106+
%token <ident> T_LOGICAL_AND "and (T_LOGICAL_AND)"
107+
%token <ident> T_PRINT "print (T_PRINT)"
108+
%token <ident> T_YIELD "yield (T_YIELD)"
109+
%token <ident> T_YIELD_FROM "yield from (T_YIELD_FROM)"
110+
%token <ident> T_INSTANCEOF "instanceof (T_INSTANCEOF)"
111+
%token <ident> T_NEW "new (T_NEW)"
112+
%token <ident> T_CLONE "clone (T_CLONE)"
113+
%token <ident> T_EXIT "exit (T_EXIT)"
114+
%token <ident> T_IF "if (T_IF)"
115+
%token <ident> T_ELSEIF "elseif (T_ELSEIF)"
116+
%token <ident> T_ELSE "else (T_ELSE)"
117+
%token <ident> T_ENDIF "endif (T_ENDIF)"
118+
%token <ident> T_ECHO "echo (T_ECHO)"
119+
%token <ident> T_DO "do (T_DO)"
120+
%token <ident> T_WHILE "while (T_WHILE)"
121+
%token <ident> T_ENDWHILE "endwhile (T_ENDWHILE)"
122+
%token <ident> T_FOR "for (T_FOR)"
123+
%token <ident> T_ENDFOR "endfor (T_ENDFOR)"
124+
%token <ident> T_FOREACH "foreach (T_FOREACH)"
125+
%token <ident> T_ENDFOREACH "endforeach (T_ENDFOREACH)"
126+
%token <ident> T_DECLARE "declare (T_DECLARE)"
127+
%token <ident> T_ENDDECLARE "enddeclare (T_ENDDECLARE)"
128+
%token <ident> T_AS "as (T_AS)"
129+
%token <ident> T_SWITCH "switch (T_SWITCH)"
130+
%token <ident> T_ENDSWITCH "endswitch (T_ENDSWITCH)"
131+
%token <ident> T_CASE "case (T_CASE)"
132+
%token <ident> T_DEFAULT "default (T_DEFAULT)"
133+
%token <ident> T_BREAK "break (T_BREAK)"
134+
%token <ident> T_CONTINUE "continue (T_CONTINUE)"
135+
%token <ident> T_GOTO "goto (T_GOTO)"
136+
%token <ident> T_FUNCTION "function (T_FUNCTION)"
137+
%token <ident> T_FN "fn (T_FN)"
138+
%token <ident> T_CONST "const (T_CONST)"
139+
%token <ident> T_RETURN "return (T_RETURN)"
140+
%token <ident> T_TRY "try (T_TRY)"
141+
%token <ident> T_CATCH "catch (T_CATCH)"
142+
%token <ident> T_FINALLY "finally (T_FINALLY)"
143+
%token <ident> T_THROW "throw (T_THROW)"
144+
%token <ident> T_USE "use (T_USE)"
145+
%token <ident> T_INSTEADOF "insteadof (T_INSTEADOF)"
146+
%token <ident> T_GLOBAL "global (T_GLOBAL)"
147+
%token <ident> T_STATIC "static (T_STATIC)"
148+
%token <ident> T_ABSTRACT "abstract (T_ABSTRACT)"
149+
%token <ident> T_FINAL "final (T_FINAL)"
150+
%token <ident> T_PRIVATE "private (T_PRIVATE)"
151+
%token <ident> T_PROTECTED "protected (T_PROTECTED)"
152+
%token <ident> T_PUBLIC "public (T_PUBLIC)"
153+
%token <ident> T_VAR "var (T_VAR)"
154+
%token <ident> T_UNSET "unset (T_UNSET)"
155+
%token <ident> T_ISSET "isset (T_ISSET)"
156+
%token <ident> T_EMPTY "empty (T_EMPTY)"
157+
%token <ident> T_HALT_COMPILER "__halt_compiler (T_HALT_COMPILER)"
158+
%token <ident> T_CLASS "class (T_CLASS)"
159+
%token <ident> T_TRAIT "trait (T_TRAIT)"
160+
%token <ident> T_INTERFACE "interface (T_INTERFACE)"
161+
%token <ident> T_EXTENDS "extends (T_EXTENDS)"
162+
%token <ident> T_IMPLEMENTS "implements (T_IMPLEMENTS)"
163+
%token <ident> T_NAMESPACE "namespace (T_NAMESPACE)"
164+
%token <ident> T_LIST "list (T_LIST)"
165+
%token <ident> T_ARRAY "array (T_ARRAY)"
166+
%token <ident> T_CALLABLE "callable (T_CALLABLE)"
167+
%token <ident> T_LINE "__LINE__ (T_LINE)"
168+
%token <ident> T_FILE "__FILE__ (T_FILE)"
169+
%token <ident> T_DIR "__DIR__ (T_DIR)"
170+
%token <ident> T_CLASS_C "__CLASS__ (T_CLASS_C)"
171+
%token <ident> T_TRAIT_C "__TRAIT__ (T_TRAIT_C)"
172+
%token <ident> T_METHOD_C "__METHOD__ (T_METHOD_C)"
173+
%token <ident> T_FUNC_C "__FUNCTION__ (T_FUNC_C)"
174+
%token <ident> T_NS_C "__NAMESPACE__ (T_NS_C)"
175+
99176
%token END 0 "end of file"
100-
%token T_INCLUDE "include (T_INCLUDE)"
101-
%token T_INCLUDE_ONCE "include_once (T_INCLUDE_ONCE)"
102-
%token T_EVAL "eval (T_EVAL)"
103-
%token T_REQUIRE "require (T_REQUIRE)"
104-
%token T_REQUIRE_ONCE "require_once (T_REQUIRE_ONCE)"
105-
%token T_LOGICAL_OR "or (T_LOGICAL_OR)"
106-
%token T_LOGICAL_XOR "xor (T_LOGICAL_XOR)"
107-
%token T_LOGICAL_AND "and (T_LOGICAL_AND)"
108-
%token T_PRINT "print (T_PRINT)"
109-
%token T_YIELD "yield (T_YIELD)"
110-
%token T_YIELD_FROM "yield from (T_YIELD_FROM)"
111177
%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
112178
%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
113179
%token T_MUL_EQUAL "*= (T_MUL_EQUAL)"
@@ -131,7 +197,6 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
131197
%token T_SPACESHIP "<=> (T_SPACESHIP)"
132198
%token T_SL "<< (T_SL)"
133199
%token T_SR ">> (T_SR)"
134-
%token T_INSTANCEOF "instanceof (T_INSTANCEOF)"
135200
%token T_INC "++ (T_INC)"
136201
%token T_DEC "-- (T_DEC)"
137202
%token T_INT_CAST "(int) (T_INT_CAST)"
@@ -141,70 +206,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
141206
%token T_OBJECT_CAST "(object) (T_OBJECT_CAST)"
142207
%token T_BOOL_CAST "(bool) (T_BOOL_CAST)"
143208
%token T_UNSET_CAST "(unset) (T_UNSET_CAST)"
144-
%token T_NEW "new (T_NEW)"
145-
%token T_CLONE "clone (T_CLONE)"
146-
%token T_EXIT "exit (T_EXIT)"
147-
%token T_IF "if (T_IF)"
148-
%token T_ELSEIF "elseif (T_ELSEIF)"
149-
%token T_ELSE "else (T_ELSE)"
150-
%token T_ENDIF "endif (T_ENDIF)"
151-
%token T_ECHO "echo (T_ECHO)"
152-
%token T_DO "do (T_DO)"
153-
%token T_WHILE "while (T_WHILE)"
154-
%token T_ENDWHILE "endwhile (T_ENDWHILE)"
155-
%token T_FOR "for (T_FOR)"
156-
%token T_ENDFOR "endfor (T_ENDFOR)"
157-
%token T_FOREACH "foreach (T_FOREACH)"
158-
%token T_ENDFOREACH "endforeach (T_ENDFOREACH)"
159-
%token T_DECLARE "declare (T_DECLARE)"
160-
%token T_ENDDECLARE "enddeclare (T_ENDDECLARE)"
161-
%token T_AS "as (T_AS)"
162-
%token T_SWITCH "switch (T_SWITCH)"
163-
%token T_ENDSWITCH "endswitch (T_ENDSWITCH)"
164-
%token T_CASE "case (T_CASE)"
165-
%token T_DEFAULT "default (T_DEFAULT)"
166-
%token T_BREAK "break (T_BREAK)"
167-
%token T_CONTINUE "continue (T_CONTINUE)"
168-
%token T_GOTO "goto (T_GOTO)"
169-
%token T_FUNCTION "function (T_FUNCTION)"
170-
%token T_FN "fn (T_FN)"
171-
%token T_CONST "const (T_CONST)"
172-
%token T_RETURN "return (T_RETURN)"
173-
%token T_TRY "try (T_TRY)"
174-
%token T_CATCH "catch (T_CATCH)"
175-
%token T_FINALLY "finally (T_FINALLY)"
176-
%token T_THROW "throw (T_THROW)"
177-
%token T_USE "use (T_USE)"
178-
%token T_INSTEADOF "insteadof (T_INSTEADOF)"
179-
%token T_GLOBAL "global (T_GLOBAL)"
180-
%token T_STATIC "static (T_STATIC)"
181-
%token T_ABSTRACT "abstract (T_ABSTRACT)"
182-
%token T_FINAL "final (T_FINAL)"
183-
%token T_PRIVATE "private (T_PRIVATE)"
184-
%token T_PROTECTED "protected (T_PROTECTED)"
185-
%token T_PUBLIC "public (T_PUBLIC)"
186-
%token T_VAR "var (T_VAR)"
187-
%token T_UNSET "unset (T_UNSET)"
188-
%token T_ISSET "isset (T_ISSET)"
189-
%token T_EMPTY "empty (T_EMPTY)"
190-
%token T_HALT_COMPILER "__halt_compiler (T_HALT_COMPILER)"
191-
%token T_CLASS "class (T_CLASS)"
192-
%token T_TRAIT "trait (T_TRAIT)"
193-
%token T_INTERFACE "interface (T_INTERFACE)"
194-
%token T_EXTENDS "extends (T_EXTENDS)"
195-
%token T_IMPLEMENTS "implements (T_IMPLEMENTS)"
196209
%token T_OBJECT_OPERATOR "-> (T_OBJECT_OPERATOR)"
197210
%token T_DOUBLE_ARROW "=> (T_DOUBLE_ARROW)"
198-
%token T_LIST "list (T_LIST)"
199-
%token T_ARRAY "array (T_ARRAY)"
200-
%token T_CALLABLE "callable (T_CALLABLE)"
201-
%token T_LINE "__LINE__ (T_LINE)"
202-
%token T_FILE "__FILE__ (T_FILE)"
203-
%token T_DIR "__DIR__ (T_DIR)"
204-
%token T_CLASS_C "__CLASS__ (T_CLASS_C)"
205-
%token T_TRAIT_C "__TRAIT__ (T_TRAIT_C)"
206-
%token T_METHOD_C "__METHOD__ (T_METHOD_C)"
207-
%token T_FUNC_C "__FUNCTION__ (T_FUNC_C)"
208211
%token T_COMMENT "comment (T_COMMENT)"
209212
%token T_DOC_COMMENT "doc comment (T_DOC_COMMENT)"
210213
%token T_OPEN_TAG "open tag (T_OPEN_TAG)"
@@ -216,8 +219,6 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
216219
%token T_DOLLAR_OPEN_CURLY_BRACES "${ (T_DOLLAR_OPEN_CURLY_BRACES)"
217220
%token T_CURLY_OPEN "{$ (T_CURLY_OPEN)"
218221
%token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)"
219-
%token T_NAMESPACE "namespace (T_NAMESPACE)"
220-
%token T_NS_C "__NAMESPACE__ (T_NS_C)"
221222
%token T_NS_SEPARATOR "\\ (T_NS_SEPARATOR)"
222223
%token T_ELLIPSIS "... (T_ELLIPSIS)"
223224
%token T_COALESCE "?? (T_COALESCE)"
@@ -268,6 +269,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
268269
%type <ptr> backup_lex_pos
269270
%type <str> backup_doc_comment
270271

272+
%type <ident> reserved_non_modifiers semi_reserved
273+
271274
%% /* Rules */
272275

273276
start:
@@ -293,7 +296,7 @@ identifier:
293296
T_STRING { $$ = $1; }
294297
| semi_reserved {
295298
zval zv;
296-
zend_lex_tstring(&zv);
299+
zend_lex_tstring(&zv, $1);
297300
$$ = zend_ast_create_zval(&zv);
298301
}
299302
;
@@ -847,7 +850,8 @@ trait_alias:
847850
trait_method_reference T_AS T_STRING
848851
{ $$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, $3); }
849852
| trait_method_reference T_AS reserved_non_modifiers
850-
{ zval zv; zend_lex_tstring(&zv); $$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, zend_ast_create_zval(&zv)); }
853+
{ zval zv; zend_lex_tstring(&zv, $3);
854+
$$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, zend_ast_create_zval(&zv)); }
851855
| trait_method_reference T_AS member_modifier identifier
852856
{ $$ = zend_ast_create_ex(ZEND_AST_TRAIT_ALIAS, $3, $1, $4); }
853857
| trait_method_reference T_AS member_modifier

Zend/zend_language_scanner.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ typedef struct _zend_lex_state {
5050
const zend_encoding *script_encoding;
5151

5252
/* hooks */
53-
void (*on_event)(zend_php_scanner_event event, int token, int line, void *context);
53+
void (*on_event)(
54+
zend_php_scanner_event event, int token, int line,
55+
const char *text, size_t length, void *context);
5456
void *on_event_context;
5557

5658
zend_ast *ast;
@@ -76,7 +78,7 @@ ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state);
7678
ZEND_API int zend_prepare_string_for_scanning(zval *str, const char *filename);
7779
ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, const zend_encoding *old_encoding);
7880
ZEND_API int zend_multibyte_set_filter(const zend_encoding *onetime_encoding);
79-
ZEND_API void zend_lex_tstring(zval *zv);
81+
ZEND_API void zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref);
8082

8183
END_EXTERN_C()
8284

0 commit comments

Comments
 (0)