From 55afe8bd9b82dcfad246856dcf5b620c204c9a6b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:09:42 +0100 Subject: [PATCH] Implement GH-15680: Enhance zend_dump_op_array to Properly Represent Non-Printable Characters in String Literals Replaces GH-15730 as that PR became stale. But instead of introducing a new helper, reuse smart_str_append_escaped(), this also removes the dependency on ext/standard. Closes GH-15730. Closes GH-17277. --- NEWS | 2 ++ Zend/Optimizer/zend_dump.c | 24 +++++++++++++++++++----- ext/opcache/tests/match/002.phpt | 6 ++---- ext/opcache/tests/opt/dce_009.phpt | 6 ++---- ext/opcache/tests/opt/sccp_032.phpt | 3 +-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index f1ff08ccd50..d4770dca4a4 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ PHP NEWS Volker Dusch) . Use `clock_gettime_nsec_np()` for high resolution timer on macOS if available. (timwolla) + . Implement GH-15680 (Enhance zend_dump_op_array to properly represent + non-printable characters in string literals). (nielsdos, WangYihang) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c index b788b652979..4e46b38a8eb 100644 --- a/Zend/Optimizer/zend_dump.c +++ b/Zend/Optimizer/zend_dump.c @@ -23,7 +23,7 @@ #include "zend_func_info.h" #include "zend_call_graph.h" #include "zend_dump.h" -#include "ext/standard/php_string.h" +#include "zend_smart_str.h" void zend_dump_ht(HashTable *ht) { @@ -66,13 +66,27 @@ void zend_dump_const(const zval *zv) case IS_DOUBLE: fprintf(stderr, " float(%g)", Z_DVAL_P(zv)); break; - case IS_STRING:; - zend_string *escaped_string = php_addcslashes(Z_STR_P(zv), "\"\\", 2); + case IS_STRING: { + smart_str escaped_string = {0}; + smart_str_append_escaped(&escaped_string, Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + smart_str_0(&escaped_string); - fprintf(stderr, " string(\"%s\")", ZSTR_VAL(escaped_string)); + fprintf(stderr, " string(\""); - zend_string_release(escaped_string); + /* Also escape '"' */ + for (size_t i = 0; i < ZSTR_LEN(escaped_string.s); i++) { + if (ZSTR_VAL(escaped_string.s)[i] == '"') { + fprintf(stderr, "\\\""); + } else { + putc(ZSTR_VAL(escaped_string.s)[i], stderr); + } + } + + fprintf(stderr, "\")"); + + smart_str_free_ex(&escaped_string, false); break; + } case IS_ARRAY: fprintf(stderr, " array(...)"); break; diff --git a/ext/opcache/tests/match/002.phpt b/ext/opcache/tests/match/002.phpt index 8e7102d5391..005c2689d1b 100644 --- a/ext/opcache/tests/match/002.phpt +++ b/ext/opcache/tests/match/002.phpt @@ -44,16 +44,14 @@ test: ; (lines=2, args=0, vars=0, tmps=0) ; (after optimizer) ; %s -0000 ECHO string("No match -") +0000 ECHO string("No match\n") 0001 RETURN null test2: ; (lines=2, args=0, vars=0, tmps=0) ; (after optimizer) ; %s -0000 ECHO string("No match -") +0000 ECHO string("No match\n") 0001 RETURN null No match No match diff --git a/ext/opcache/tests/opt/dce_009.phpt b/ext/opcache/tests/opt/dce_009.phpt index f9c10074fb6..996825cf96e 100644 --- a/ext/opcache/tests/opt/dce_009.phpt +++ b/ext/opcache/tests/opt/dce_009.phpt @@ -50,10 +50,8 @@ Loop::test: ; (lines=3, args=0, vars=0, tmps=0) ; (after optimizer) ; %sdce_009.php:4-10 -0000 ECHO string("Start -") -0001 ECHO string("Done -") +0000 ECHO string("Start\n") +0001 ECHO string("Done\n") 0002 RETURN null Loop::test2: diff --git a/ext/opcache/tests/opt/sccp_032.phpt b/ext/opcache/tests/opt/sccp_032.phpt index dac09a75527..6ee4a837ecd 100644 --- a/ext/opcache/tests/opt/sccp_032.phpt +++ b/ext/opcache/tests/opt/sccp_032.phpt @@ -36,8 +36,7 @@ $_main: 0004 INIT_FCALL 1 %d string("var_export") 0005 SEND_VAR CV0($x) 1 0006 DO_ICALL -0007 ECHO string(" -") +0007 ECHO string("\n") 0008 JMP 0003 0009 FE_FREE V1 0010 RETURN int(1)