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);
}
/* }}} */