]> granicus.if.org Git - php/commitdiff
Forbid use of <?= as a semi-reserved identifier
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 19 Jun 2020 07:27:19 +0000 (09:27 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 19 Jun 2020 07:29:58 +0000 (09:29 +0200)
One of the weirdest pieces of PHP code I've ever seen. In terms
of tokens, this gets internally translated to

    use x as y; echo as my_echo;

On master it crashes because this "echo" does not have attached
identifier metadata. Make sure it is added and then reject the
use of "<?=" as an identifier inside zend_lex_tstring.

Fixes oss-fuzz #23547.

Zend/tests/short_echo_as_identifier.phpt [new file with mode: 0644]
Zend/zend_language_parser.y
Zend/zend_language_scanner.h
Zend/zend_language_scanner.l

diff --git a/Zend/tests/short_echo_as_identifier.phpt b/Zend/tests/short_echo_as_identifier.phpt
new file mode 100644 (file)
index 0000000..7fc1684
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+<?= cannot be used as an identifier
+--FILE--
+<?php
+trait T {
+    public function x() {}
+}
+class C {
+    use T {
+        x as y?><?= as my_echo;
+    }
+}
+?>
+--EXPECTF--
+Parse error: Cannot use "<?=" as an identifier in %s on line %d
index f930cf0e5d897e7ad872defbfc03ecb6b77fe3fc..8ec740a05c47dadbf6dbe4523f76b1cb68c19695 100644 (file)
@@ -296,7 +296,7 @@ identifier:
                T_STRING { $$ = $1; }
        |       semi_reserved  {
                        zval zv;
-                       zend_lex_tstring(&zv, $1);
+                       if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; }
                        $$ = zend_ast_create_zval(&zv);
                }
 ;
@@ -852,7 +852,8 @@ trait_alias:
                trait_method_reference T_AS T_STRING
                        { $$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, $3); }
        |       trait_method_reference T_AS reserved_non_modifiers
-                       { zval zv; zend_lex_tstring(&zv, $3);
+                       { zval zv;
+                         if (zend_lex_tstring(&zv, $3) == FAILURE) { YYABORT; }
                          $$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, zend_ast_create_zval(&zv)); }
        |       trait_method_reference T_AS member_modifier identifier
                        { $$ = zend_ast_create_ex(ZEND_AST_TRAIT_ALIAS, $3, $1, $4); }
index 35d4d0269e55d19b6d8cf316506047ea2569a4d2..c15f11af2e51b484a1d749b34fa24da7f2b62e58 100644 (file)
@@ -78,7 +78,7 @@ ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state);
 ZEND_API int zend_prepare_string_for_scanning(zval *str, const char *filename);
 ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, const zend_encoding *old_encoding);
 ZEND_API int zend_multibyte_set_filter(const zend_encoding *onetime_encoding);
-ZEND_API void zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref);
+ZEND_API int zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref);
 
 END_EXTERN_C()
 
index 7b5a8ab1c87375accbe64f1ccc976586240236f4..ffb515893888ea68194c768e3b7e9b149c6f6f1b 100644 (file)
@@ -306,15 +306,21 @@ ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle)
        }
 }
 
-ZEND_API void zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref)
+ZEND_API int zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref)
 {
        char *ident = (char *) SCNG(yy_start) + ident_ref.offset;
        size_t length = ident_ref.len;
+       if (length == sizeof("<?=")-1 && memcmp(ident, "<?=", sizeof("<?=")-1) == 0) {
+               zend_throw_exception(zend_ce_parse_error, "Cannot use \"<?=\" as an identifier", 0);
+               return FAILURE;
+       }
+
        if (SCNG(on_event)) {
                SCNG(on_event)(ON_FEEDBACK, T_STRING, 0, ident, length, SCNG(on_event_context));
        }
 
        ZVAL_STRINGL(zv, ident, length);
+       return SUCCESS;
 }
 
 #define BOM_UTF32_BE   "\x00\x00\xfe\xff"
@@ -2149,7 +2155,8 @@ string:
 <INITIAL>"<?=" {
        BEGIN(ST_IN_SCRIPTING);
        if (PARSER_MODE()) {
-               RETURN_TOKEN(T_ECHO);
+               /* We'll reject this as an identifier in zend_lex_tstring. */
+               RETURN_TOKEN_WITH_IDENT(T_ECHO);
        }
        RETURN_TOKEN(T_OPEN_TAG_WITH_ECHO);
 }