diff options
| author | Nikita Popov <nikita.ppv@gmail.com> | 2020-06-05 16:55:20 +0200 |
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-06-08 12:55:14 +0200 |
| commit | b03cafd19c01db57b89727ce77cc89a7d816077c (patch) | |
| tree | b8e39eeca2edf8fbb74e4b3fb7e2979470b959c0 /ext/tokenizer/tokenizer.c | |
| parent | 08518b18b2095b8c5158e272b4fe6c339f0eb1b7 (diff) | |
| download | php-git-b03cafd19c01db57b89727ce77cc89a7d816077c.tar.gz | |
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.
Diffstat (limited to 'ext/tokenizer/tokenizer.c')
| -rw-r--r-- | ext/tokenizer/tokenizer.c | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/ext/tokenizer/tokenizer.c b/ext/tokenizer/tokenizer.c index db57323223..901e609d2d 100644 --- a/ext/tokenizer/tokenizer.c +++ b/ext/tokenizer/tokenizer.c @@ -420,11 +420,33 @@ struct event_context { zend_class_entry *token_class; }; -void on_event(zend_php_scanner_event event, int token, int line, void *context) +static zval *extract_token_id_to_replace(zval *token_zv, const char *text, size_t length) { + zval *id_zv, *text_zv; + ZEND_ASSERT(token_zv); + if (Z_TYPE_P(token_zv) == IS_ARRAY) { + id_zv = zend_hash_index_find(Z_ARRVAL_P(token_zv), 0); + text_zv = zend_hash_index_find(Z_ARRVAL_P(token_zv), 1); + } else if (Z_TYPE_P(token_zv) == IS_OBJECT) { + id_zv = OBJ_PROP_NUM(Z_OBJ_P(token_zv), 0); + text_zv = OBJ_PROP_NUM(Z_OBJ_P(token_zv), 1); + } else { + return NULL; + } + + /* There are multiple candidate tokens to which this feedback may apply, + * check text to make sure this is the right one. */ + ZEND_ASSERT(Z_TYPE_P(text_zv) == IS_STRING); + if (Z_STRLEN_P(text_zv) == length && !memcmp(Z_STRVAL_P(text_zv), text, length)) { + return id_zv; + } + return NULL; +} + +void on_event( + zend_php_scanner_event event, int token, int line, + const char *text, size_t length, void *context) { struct event_context *ctx = context; - HashTable *tokens_ht; - zval *token_zv; switch (event) { case ON_TOKEN: @@ -435,19 +457,22 @@ void on_event(zend_php_scanner_event event, int token, int line, void *context) } else if (token == T_ECHO && LANG_SCNG(yy_leng) == sizeof("<?=") - 1) { token = T_OPEN_TAG_WITH_ECHO; } - add_token(ctx->tokens, token, - LANG_SCNG(yy_text), LANG_SCNG(yy_leng), line, ctx->token_class, NULL); + add_token( + ctx->tokens, token, (unsigned char *) text, length, line, ctx->token_class, NULL); break; - case ON_FEEDBACK: - tokens_ht = Z_ARRVAL_P(ctx->tokens); - token_zv = zend_hash_index_find(tokens_ht, zend_hash_num_elements(tokens_ht) - 1); - ZEND_ASSERT(token_zv); - if (Z_TYPE_P(token_zv) == IS_ARRAY) { - ZVAL_LONG(zend_hash_index_find(Z_ARRVAL_P(token_zv), 0), token); - } else { - zend_update_property_long(php_token_ce, token_zv, "type", sizeof("type")-1, token); - } + case ON_FEEDBACK: { + HashTable *tokens_ht = Z_ARRVAL_P(ctx->tokens); + zval *token_zv, *id_zv = NULL; + ZEND_HASH_REVERSE_FOREACH_VAL(tokens_ht, token_zv) { + id_zv = extract_token_id_to_replace(token_zv, text, length); + if (id_zv) { + break; + } + } ZEND_HASH_FOREACH_END(); + ZEND_ASSERT(id_zv); + ZVAL_LONG(id_zv, token); break; + } case ON_STOP: if (LANG_SCNG(yy_cursor) != LANG_SCNG(yy_limit)) { add_token(ctx->tokens, T_INLINE_HTML, LANG_SCNG(yy_cursor), |
