From c006610419ff31bce24e13325d47bed4ca65610b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:46:34 +0100 Subject: [PATCH 1/6] Use %S formatter where possible for undefined variables --- .../warning_during_heredoc_scan_ahead.phpt | 2 +- Zend/zend.c | 14 +++++++++++ Zend/zend.h | 1 + Zend/zend_compile.c | 10 ++++---- Zend/zend_execute.c | 4 ++-- Zend/zend_vm_def.h | 8 +++---- Zend/zend_vm_execute.h | 24 +++++++++---------- ext/opcache/jit/zend_jit_helpers.c | 8 +++---- ext/opcache/jit/zend_jit_ir.c | 8 +++---- 9 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Zend/tests/warning_during_heredoc_scan_ahead.phpt b/Zend/tests/warning_during_heredoc_scan_ahead.phpt index a0becbb782a6d..cc6951a075861 100644 --- a/Zend/tests/warning_during_heredoc_scan_ahead.phpt +++ b/Zend/tests/warning_during_heredoc_scan_ahead.phpt @@ -16,4 +16,4 @@ Warning: Octal escape sequence overflow \400 is greater than \377 in %s on line Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead in %s on line %d -Warning: Undefined variable $ in %s on line %d +Warning: Undefined variable $%0 in %s on line %d diff --git a/Zend/zend.c b/Zend/zend.c index fb0af12f9e510..f0811c7a18829 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1650,6 +1650,20 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * abort(); } +ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...) +{ + zend_string *filename; + uint32_t lineno; + va_list args; + + get_filename_lineno(type, &filename, &lineno); + va_start(args, format); + zend_error_va_list(type, filename, lineno, format, args); + va_end(args); + /* Should never reach this. */ + abort(); +} + ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message) { #ifdef HAVE_STRERROR_R diff --git a/Zend/zend.h b/Zend/zend.h index d60da5f83ac11..8d23f1b86288a 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -345,6 +345,7 @@ extern ZEND_API void (*zend_post_shutdown_cb)(void); ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...); /* For custom format specifiers like H */ ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...); /* If filename is NULL the default filename is used. */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 73ba58998865f..c82f2be771215 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4970,7 +4970,7 @@ static void zend_compile_static_var(zend_ast *ast) /* {{{ */ } if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) { - zend_error_noreturn(E_COMPILE_ERROR, "Duplicate declaration of static variable $%s", ZSTR_VAL(var_name)); + zend_error_noreturn_unchecked(E_COMPILE_ERROR, "Duplicate declaration of static variable $%S", var_name); } zend_eval_const_expr(&ast->child[1]); @@ -7245,8 +7245,8 @@ static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval)); if (!value) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot use variable $%s twice", ZSTR_VAL(var_name)); + zend_error_noreturn_unchecked(E_COMPILE_ERROR, + "Cannot use variable $%S twice", var_name); } CG(zend_lineno) = zend_ast_get_lineno(var_name_ast); @@ -7378,8 +7378,8 @@ static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */ int i; for (i = 0; i < op_array->last_var; i++) { if (zend_string_equals(op_array->vars[i], var_name)) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot use lexical variable $%s as a parameter name", ZSTR_VAL(var_name)); + zend_error_noreturn_unchecked(E_COMPILE_ERROR, + "Cannot use lexical variable $%S as a parameter name", var_name); } } } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6311aacb420ca..de9226c3519e3 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -272,7 +272,7 @@ static zend_never_inline ZEND_COLD zval* zval_undefined_cv(uint32_t var EXECUTE_ { if (EXPECTED(EG(exception) == NULL)) { zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var)); - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv)); + zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv); } return &EG(uninitialized_zval); } @@ -3788,7 +3788,7 @@ static zend_never_inline void zend_fetch_this_var(int type OPLINE_DC EXECUTE_DAT Z_ADDREF_P(result); } else { ZVAL_NULL(result); - zend_error(E_WARNING, "Undefined variable $this"); + zend_error_unchecked(E_WARNING, "Undefined variable $this"); } break; case BP_VAR_IS: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f731653a24813..2d12dfbb95649 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1755,8 +1755,8 @@ ZEND_VM_C_LABEL(fetch_this): /* Keep name alive in case an error handler tries to free it. */ zend_string_addref(name); } - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); } else { @@ -1778,8 +1778,8 @@ ZEND_VM_C_LABEL(fetch_this): } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { ZVAL_NULL(retval); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 41ef6b821d55e..c48df8191efa2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -10109,8 +10109,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad /* Keep name alive in case an error handler tries to free it. */ zend_string_addref(name); } - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); } else { @@ -10132,8 +10132,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { ZVAL_NULL(retval); } else { @@ -17954,8 +17954,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad /* Keep name alive in case an error handler tries to free it. */ zend_string_addref(name); } - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); } else { @@ -17977,8 +17977,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { ZVAL_NULL(retval); } else { @@ -48342,8 +48342,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad /* Keep name alive in case an error handler tries to free it. */ zend_string_addref(name); } - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); } else { @@ -48365,8 +48365,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined %svariable $%s", - (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + zend_error_unchecked(E_WARNING, "Undefined %svariable $%S", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name); if (type == BP_VAR_RW && !EG(exception)) { ZVAL_NULL(retval); } else { diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index f439a7572f452..dab251056ba18 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -95,7 +95,7 @@ static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call(zval *object) if (Z_TYPE_P(object) == IS_UNDEF && opline->op1_type == IS_CV) { zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)]; - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv)); + zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv); if (UNEXPECTED(EG(exception) != NULL)) { return; } @@ -340,7 +340,7 @@ static int ZEND_FASTCALL zend_jit_undefined_op_helper(uint32_t var) const zend_execute_data *execute_data = EG(current_execute_data); zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)]; - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv)); + zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv); return EG(exception) == NULL; } @@ -354,7 +354,7 @@ static int ZEND_FASTCALL zend_jit_undefined_op_helper_write(HashTable *ht, uint3 if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { GC_ADDREF(ht); } - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv)); + zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv); if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) { if (!GC_REFCOUNT(ht)) { zend_array_destroy(ht); @@ -2418,7 +2418,7 @@ static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, cons if (Z_TYPE_P(container) == IS_UNDEF && opline->op1_type == IS_CV) { zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)]; - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv)); + zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv); } if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 6c17f932f6271..cca3d4b8b0ec0 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -4646,7 +4646,7 @@ static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t o if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF); ir_IF_FALSE_cold(if_def); - // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); + // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))); ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var)); jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL); @@ -5588,7 +5588,7 @@ static int zend_jit_long_math_helper(zend_jit_ctx *jit, if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF); ir_IF_FALSE_cold(if_def); - // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); + // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))); ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var)); ref2 = jit_EG(uninitialized_zval); @@ -5604,7 +5604,7 @@ static int zend_jit_long_math_helper(zend_jit_ctx *jit, if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF); ir_IF_FALSE_cold(if_def); - // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)))); + // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var))); ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var)); ref2 = jit_EG(uninitialized_zval); @@ -5980,7 +5980,7 @@ static int zend_jit_simple_assign(zend_jit_ctx *jit, jit_SET_EX_OPLINE(jit, opline); ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL); - // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); + // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))); ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr))); if (check_exception) { From b02076f38527f8d51c2def12eba305f07c82a453 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:46:53 +0100 Subject: [PATCH 2/6] Make php_verror compatible with strings containing \0 --- main/main.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/main/main.c b/main/main.c index 6633689d85d1d..a5ad3eea10430 100644 --- a/main/main.c +++ b/main/main.c @@ -944,11 +944,10 @@ static zend_string *escape_html(const char *buffer, size_t buffer_len) { */ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int type, const char *format, va_list args) { - zend_string *replace_buffer = NULL, *replace_origin = NULL; - char *buffer = NULL, *docref_buf = NULL, *target = NULL; + zend_string *replace_origin = NULL; + char *docref_buf = NULL, *target = NULL; char *docref_target = "", *docref_root = ""; char *p; - int buffer_len = 0; const char *space = ""; const char *class_name = ""; const char *function; @@ -958,18 +957,16 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ int is_function = 0; /* get error text into buffer and escape for html if necessary */ - buffer_len = (int)vspprintf(&buffer, 0, format, args); + zend_string *buffer = vstrpprintf(0, format, args); if (PG(html_errors)) { - replace_buffer = escape_html(buffer, buffer_len); - efree(buffer); + zend_string *replace_buffer = escape_html(ZSTR_VAL(buffer), ZSTR_LEN(buffer)); + zend_string_free(buffer); if (replace_buffer) { - buffer = ZSTR_VAL(replace_buffer); - buffer_len = (int)ZSTR_LEN(replace_buffer); + buffer = replace_buffer; } else { - buffer = ""; - buffer_len = 0; + buffer = zend_empty_string; } } @@ -1091,15 +1088,15 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ } /* display html formatted or only show the additional links */ if (PG(html_errors)) { - message = zend_strpprintf(0, "%s [%s]: %s", origin, docref_root, docref, docref_target, docref, buffer); + message = zend_strpprintf_unchecked(0, "%s [%s]: %S", origin, docref_root, docref, docref_target, docref, buffer); } else { - message = zend_strpprintf(0, "%s [%s%s%s]: %s", origin, docref_root, docref, docref_target, buffer); + message = zend_strpprintf_unchecked(0, "%s [%s%s%s]: %S", origin, docref_root, docref, docref_target, buffer); } if (target) { efree(target); } } else { - message = zend_strpprintf(0, "%s: %s", origin, buffer); + message = zend_strpprintf_unchecked(0, "%s: %S", origin, buffer); } if (replace_origin) { zend_string_free(replace_origin); @@ -1110,11 +1107,7 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ efree(docref_buf); } - if (replace_buffer) { - zend_string_free(replace_buffer); - } else { - efree(buffer); - } + zend_string_free(buffer); zend_error_zstr(type, message); zend_string_release(message); From beb4670347434e281997c0f43f038ad4431c91df Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:47:08 +0100 Subject: [PATCH 3/6] Let compact() use %S --- ext/standard/array.c | 2 +- main/main.c | 9 +++++++++ main/php.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index 388b15a0879bb..3241d6e0f4768 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2608,7 +2608,7 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data); } } else { - php_error_docref(NULL, E_WARNING, "Undefined variable $%s", ZSTR_VAL(Z_STR_P(entry))); + php_error_docref_unchecked(NULL, E_WARNING, "Undefined variable $%S", Z_STR_P(entry)); } } else if (Z_TYPE_P(entry) == IS_ARRAY) { if (Z_REFCOUNTED_P(entry)) { diff --git a/main/main.c b/main/main.c index a5ad3eea10430..2d64efa9eb7cd 100644 --- a/main/main.c +++ b/main/main.c @@ -1124,6 +1124,15 @@ PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char php_verror(docref, "", type, format, args); va_end(args); } + +PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format, ...) +{ + va_list args; + + va_start(args, format); + php_verror(docref, "", type, format, args); + va_end(args); +} /* }}} */ /* {{{ php_error_docref1 */ diff --git a/main/php.h b/main/php.h index 79b73b68d1fc3..b10ded010d129 100644 --- a/main/php.h +++ b/main/php.h @@ -328,6 +328,7 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ /* PHPAPI void php_error(int type, const char *format, ...); */ PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format, ...); PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, int type, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5); PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format, ...) From fd98afac0144d141b49917f7d873a4d8c458790a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:47:30 +0100 Subject: [PATCH 4/6] Add test for GH-13142 --- Zend/tests/gh13142.phpt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Zend/tests/gh13142.phpt diff --git a/Zend/tests/gh13142.phpt b/Zend/tests/gh13142.phpt new file mode 100644 index 0000000000000..fb0a111b43806 --- /dev/null +++ b/Zend/tests/gh13142.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-13142 (Undefined variable name is shortened when contains \0) +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $test%0test in %s on line %d + +Warning: compact(): Undefined variable $a%0b in %s on line %d From 07ed57a8212ee75298c9ca4d3172b65fbd8a8a98 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 13:43:08 +0100 Subject: [PATCH 5/6] Extra test --- Zend/tests/gh13142.phpt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Zend/tests/gh13142.phpt b/Zend/tests/gh13142.phpt index fb0a111b43806..15285824ee2ad 100644 --- a/Zend/tests/gh13142.phpt +++ b/Zend/tests/gh13142.phpt @@ -5,11 +5,25 @@ GH-13142 (Undefined variable name is shortened when contains \0) $a = "test\0test"; $$a; +$a = "\0test"; +$$a; +$a = "test\0"; +$$a; compact("a\0b"); +compact("\0ab"); +compact("ab\0"); ?> --EXPECTF-- Warning: Undefined variable $test%0test in %s on line %d +Warning: Undefined variable $%0test in %s on line %d + +Warning: Undefined variable $test%0 in %s on line %d + Warning: compact(): Undefined variable $a%0b in %s on line %d + +Warning: compact(): Undefined variable $%0ab in %s on line %d + +Warning: compact(): Undefined variable $ab%0 in %s on line %d From 3163b43eb8db0b133a87e8d2d0ea90866f9c4eda Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 20 Jan 2024 17:49:40 +0100 Subject: [PATCH 6/6] Try to avoid duplicate function bodies --- Zend/zend.c | 62 ++++++++++++++++++++++------------------------------- main/main.c | 19 ++++++++-------- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index f0811c7a18829..a13884e5516ab 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1597,26 +1597,22 @@ ZEND_API ZEND_COLD void zend_error_at( va_end(args); } -ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) { - zend_string *filename; - uint32_t lineno; - va_list args; +#define zend_error_impl(type, format) do { \ + zend_string *filename; \ + uint32_t lineno; \ + va_list args; \ + get_filename_lineno(type, &filename, &lineno); \ + va_start(args, format); \ + zend_error_va_list(type, filename, lineno, format, args); \ + va_end(args); \ + } while (0) - get_filename_lineno(type, &filename, &lineno); - va_start(args, format); - zend_error_va_list(type, filename, lineno, format, args); - va_end(args); +ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) { + zend_error_impl(type, format); } ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...) { - zend_string *filename; - uint32_t lineno; - va_list args; - - get_filename_lineno(type, &filename, &lineno); - va_start(args, format); - zend_error_va_list(type, filename, lineno, format, args); - va_end(args); + zend_error_impl(type, format); } ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn( @@ -1636,32 +1632,26 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn( abort(); } +#define zend_error_noreturn_impl(type, format) do { \ + zend_string *filename; \ + uint32_t lineno; \ + va_list args; \ + get_filename_lineno(type, &filename, &lineno); \ + va_start(args, format); \ + zend_error_va_list(type, filename, lineno, format, args); \ + va_end(args); \ + /* Should never reach this. */ \ + abort(); \ + } while (0) + ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) { - zend_string *filename; - uint32_t lineno; - va_list args; - - get_filename_lineno(type, &filename, &lineno); - va_start(args, format); - zend_error_va_list(type, filename, lineno, format, args); - va_end(args); - /* Should never reach this. */ - abort(); + zend_error_noreturn_impl(type, format); } ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...) { - zend_string *filename; - uint32_t lineno; - va_list args; - - get_filename_lineno(type, &filename, &lineno); - va_start(args, format); - zend_error_va_list(type, filename, lineno, format, args); - va_end(args); - /* Should never reach this. */ - abort(); + zend_error_noreturn_impl(type, format); } ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message) diff --git a/main/main.c b/main/main.c index 2d64efa9eb7cd..b09e9bb997005 100644 --- a/main/main.c +++ b/main/main.c @@ -1116,22 +1116,21 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ /* {{{ php_error_docref */ /* Generate an error which links to docref or the php.net documentation if docref is NULL */ +#define php_error_docref_impl(docref, type, format) do {\ + va_list args; \ + va_start(args, format); \ + php_verror(docref, "", type, format, args); \ + va_end(args); \ + } while (0) + PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format, ...) { - va_list args; - - va_start(args, format); - php_verror(docref, "", type, format, args); - va_end(args); + php_error_docref_impl(docref, type, format); } PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format, ...) { - va_list args; - - va_start(args, format); - php_verror(docref, "", type, format, args); - va_end(args); + php_error_docref_impl(docref, type, format); } /* }}} */