From e0d1a02544f1f7bb933445e767ae4c4bb9354c37 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Thu, 12 Nov 2026 16:17:03 +0100 Subject: [PATCH] Fix AST export treating 0x7f as a valid name character --- NEWS | 1 + Zend/tests/ast/ast_export_del_in_names.phpt | 57 +++++++++++++++++++++ Zend/zend_ast.c | 4 +- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/ast/ast_export_del_in_names.phpt diff --git a/NEWS b/NEWS index 191b829f6f9c..1086a7b10c4e 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,7 @@ PHP NEWS . Fixed AST export of by-reference property hooks. (Jorg Sowa) . Fixed AST export of property hook parameter lists and attributes. (Jorg Sowa) + . Fixed AST export treating 0x7f as a valid name character. (Jorg Sowa) - Curl: . Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire) diff --git a/Zend/tests/ast/ast_export_del_in_names.phpt b/Zend/tests/ast/ast_export_del_in_names.phpt new file mode 100644 index 000000000000..65faea1509c5 --- /dev/null +++ b/Zend/tests/ast/ast_export_del_in_names.phpt @@ -0,0 +1,57 @@ +--TEST-- +AST export of names containing 0x7f +--EXTENSIONS-- +zend_test +--FILE-- +{"\x7f"}; +$o?->{"\x7f"}; +$o->{"\x7f"}(); +$o?->{"\x7f"}(); +C::${"\x7f"}; +"x{${"\x7f"}}y"; +"x{$o->{"\x7f"}}y"; +"{$a}\x7f"; +C::{"\x80"}; +${"\xff"}; +$o->{"a\x80"}; +"{$a}\x80"; +PHP; + +$export = zend_test_compile_to_ast($code); +echo addcslashes($export, "\x7f..\xff"); +eval("return;\n$export"); + +?> +--EXPECT-- +C::{'\177'}; +C::{'a\177'}; +C::{'\177a'}; +$o::{'\177'}; +C::{'\177'}(); +$o::{'\177'}(); +${'\177'}; +${'a\177'}; +$o->{'\177'}; +$o?->{'\177'}; +$o->{'\177'}(); +$o?->{'\177'}(); +C::${'\177'}; +"x{${'\177'}}y"; +"x{$o->{'\177'}}y"; +"{$a}\177"; +C::\200; +$\377; +$o->a\200; +"{$a}\200"; diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index e884ba897d86..a12073cfbcad 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1875,14 +1875,14 @@ static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len) return false; } c = (unsigned char)s[0]; - if (c != '_' && c < 127 && + if (c != '_' && c < 128 && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { return false; } for (i = 1; i < len; i++) { c = (unsigned char)s[i]; - if (c != '_' && c < 127 && + if (c != '_' && c < 128 && (c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) {