From c234f059cb7c990f212e36a9b2f21cd44616ba5b Mon Sep 17 00:00:00 2001 From: PurHur Date: Tue, 30 Jun 2026 02:24:06 +0000 Subject: [PATCH] =?UTF-8?q?Fix=20token=5Fget=5Fall()=20bare=20$=20before?= =?UTF-8?q?=20NUL=20=E2=80=94=20literal=20dollar=20not=20T=5FVARIABLE=20(#?= =?UTF-8?q?13896)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When $ is not followed by a variable label start, emit a literal '$' token matching php-src zend_language_scanner.l (e.g. $\0 = 1;). Co-authored-by: Cursor --- ext/tokenizer/LanguageScanner.php | 8 +++++++ .../cases/stdlib/token_get_all_null_byte.phpt | 12 +++++++++++ ...maintainer_gap_token_get_all_null_byte.php | 21 +++++++++++++++++++ test/unit/VmTokenizerNativeTest.php | 18 ++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 test/compliance/cases/stdlib/token_get_all_null_byte.phpt create mode 100644 test/repro/maintainer_gap_token_get_all_null_byte.php diff --git a/ext/tokenizer/LanguageScanner.php b/ext/tokenizer/LanguageScanner.php index dacaf1de6fa..c061baef522 100644 --- a/ext/tokenizer/LanguageScanner.php +++ b/ext/tokenizer/LanguageScanner.php @@ -433,6 +433,14 @@ private function scanVariable(): void return; } + // php-src zend_language_scanner.l: bare '$' when not followed by a variable label start. + if ($this->pos >= $this->len || !$this->isLabelStart($this->source[$this->pos])) { + $this->pos = $start; + $this->pushChar('$'); + ++$this->pos; + + return; + } while ($this->pos < $this->len && $this->isLabelContinue($this->source[$this->pos])) { ++$this->pos; } diff --git a/test/compliance/cases/stdlib/token_get_all_null_byte.phpt b/test/compliance/cases/stdlib/token_get_all_null_byte.phpt new file mode 100644 index 00000000000..38ead1c9f47 --- /dev/null +++ b/test/compliance/cases/stdlib/token_get_all_null_byte.phpt @@ -0,0 +1,12 @@ +--TEST-- +stdlib token_get_all() null byte after $ — literal dollar + T_BAD_CHARACTER (#13896, ext/tokenizer/tokenizer.c) +--FILE-- + +--EXPECT-- +dollar +bad_char diff --git a/test/repro/maintainer_gap_token_get_all_null_byte.php b/test/repro/maintainer_gap_token_get_all_null_byte.php new file mode 100644 index 00000000000..2eb1b22dd44 --- /dev/null +++ b/test/repro/maintainer_gap_token_get_all_null_byte.php @@ -0,0 +1,21 @@ +returnVar->toString()); } + public function test_issue_13896_null_byte_after_dollar(): void + { + $src = "