Skip to content

Commit fe064d7

Browse files
committed
Fix phpGH-13142: Undefined variable name is shortened when contains \0
Uses the new %S formatter and introduces the necessary changes and helpers.
1 parent a651ae8 commit fe064d7

14 files changed

+118
-80
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Core:
77
Solaris and Haiku. (David Carlier)
88
. Enabled ifunc checks on FreeBSD from the 12.x releases. (Freaky)
99
. Changed the type of PHP_DEBUG and PHP_ZTS constants to bool. (haszi)
10+
. Fixed bug GH-13142 (Undefined variable name is shortened when contains \0).
11+
(nielsdos)
1012

1113
Curl:
1214
. Deprecated the CURLOPT_BINARYTRANSFER constant. (divinity76)

Zend/tests/gh13142.phpt

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-13142 (Undefined variable name is shortened when contains \0)
3+
--FILE--
4+
<?php
5+
6+
$a = "test\0test";
7+
$$a;
8+
$a = "\0test";
9+
$$a;
10+
$a = "test\0";
11+
$$a;
12+
13+
compact("a\0b");
14+
compact("\0ab");
15+
compact("ab\0");
16+
17+
?>
18+
--EXPECTF--
19+
Warning: Undefined variable $test%0test in %s on line %d
20+
21+
Warning: Undefined variable $%0test in %s on line %d
22+
23+
Warning: Undefined variable $test%0 in %s on line %d
24+
25+
Warning: compact(): Undefined variable $a%0b in %s on line %d
26+
27+
Warning: compact(): Undefined variable $%0ab in %s on line %d
28+
29+
Warning: compact(): Undefined variable $ab%0 in %s on line %d

Zend/tests/warning_during_heredoc_scan_ahead.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ Warning: Octal escape sequence overflow \400 is greater than \377 in %s on line
1616

1717
Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead in %s on line %d
1818

19-
Warning: Undefined variable $ in %s on line %d
19+
Warning: Undefined variable $%0 in %s on line %d

Zend/zend.c

+29-25
Original file line numberDiff line numberDiff line change
@@ -1597,26 +1597,22 @@ ZEND_API ZEND_COLD void zend_error_at(
15971597
va_end(args);
15981598
}
15991599

1600-
ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) {
1601-
zend_string *filename;
1602-
uint32_t lineno;
1603-
va_list args;
1600+
#define zend_error_impl(type, format) do { \
1601+
zend_string *filename; \
1602+
uint32_t lineno; \
1603+
va_list args; \
1604+
get_filename_lineno(type, &filename, &lineno); \
1605+
va_start(args, format); \
1606+
zend_error_va_list(type, filename, lineno, format, args); \
1607+
va_end(args); \
1608+
} while (0)
16041609

1605-
get_filename_lineno(type, &filename, &lineno);
1606-
va_start(args, format);
1607-
zend_error_va_list(type, filename, lineno, format, args);
1608-
va_end(args);
1610+
ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) {
1611+
zend_error_impl(type, format);
16091612
}
16101613

16111614
ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...) {
1612-
zend_string *filename;
1613-
uint32_t lineno;
1614-
va_list args;
1615-
1616-
get_filename_lineno(type, &filename, &lineno);
1617-
va_start(args, format);
1618-
zend_error_va_list(type, filename, lineno, format, args);
1619-
va_end(args);
1615+
zend_error_impl(type, format);
16201616
}
16211617

16221618
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(
@@ -1636,18 +1632,26 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(
16361632
abort();
16371633
}
16381634

1635+
#define zend_error_noreturn_impl(type, format) do { \
1636+
zend_string *filename; \
1637+
uint32_t lineno; \
1638+
va_list args; \
1639+
get_filename_lineno(type, &filename, &lineno); \
1640+
va_start(args, format); \
1641+
zend_error_va_list(type, filename, lineno, format, args); \
1642+
va_end(args); \
1643+
/* Should never reach this. */ \
1644+
abort(); \
1645+
} while (0)
1646+
16391647
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...)
16401648
{
1641-
zend_string *filename;
1642-
uint32_t lineno;
1643-
va_list args;
1649+
zend_error_noreturn_impl(type, format);
1650+
}
16441651

1645-
get_filename_lineno(type, &filename, &lineno);
1646-
va_start(args, format);
1647-
zend_error_va_list(type, filename, lineno, format, args);
1648-
va_end(args);
1649-
/* Should never reach this. */
1650-
abort();
1652+
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...)
1653+
{
1654+
zend_error_noreturn_impl(type, format);
16511655
}
16521656

16531657
ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message)

Zend/zend.h

+1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ extern ZEND_API void (*zend_post_shutdown_cb)(void);
345345

346346
ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
347347
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
348+
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...);
348349
/* For custom format specifiers like H */
349350
ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...);
350351
/* If filename is NULL the default filename is used. */

Zend/zend_compile.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -4970,7 +4970,7 @@ static void zend_compile_static_var(zend_ast *ast) /* {{{ */
49704970
}
49714971

49724972
if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) {
4973-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate declaration of static variable $%s", ZSTR_VAL(var_name));
4973+
zend_error_noreturn_unchecked(E_COMPILE_ERROR, "Duplicate declaration of static variable $%S", var_name);
49744974
}
49754975

49764976
zend_eval_const_expr(&ast->child[1]);
@@ -7245,8 +7245,8 @@ static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array
72457245

72467246
value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval));
72477247
if (!value) {
7248-
zend_error_noreturn(E_COMPILE_ERROR,
7249-
"Cannot use variable $%s twice", ZSTR_VAL(var_name));
7248+
zend_error_noreturn_unchecked(E_COMPILE_ERROR,
7249+
"Cannot use variable $%S twice", var_name);
72507250
}
72517251

72527252
CG(zend_lineno) = zend_ast_get_lineno(var_name_ast);
@@ -7378,8 +7378,8 @@ static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
73787378
int i;
73797379
for (i = 0; i < op_array->last_var; i++) {
73807380
if (zend_string_equals(op_array->vars[i], var_name)) {
7381-
zend_error_noreturn(E_COMPILE_ERROR,
7382-
"Cannot use lexical variable $%s as a parameter name", ZSTR_VAL(var_name));
7381+
zend_error_noreturn_unchecked(E_COMPILE_ERROR,
7382+
"Cannot use lexical variable $%S as a parameter name", var_name);
73837383
}
73847384
}
73857385
}

Zend/zend_execute.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ static zend_never_inline ZEND_COLD zval* zval_undefined_cv(uint32_t var EXECUTE_
272272
{
273273
if (EXPECTED(EG(exception) == NULL)) {
274274
zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
275-
zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
275+
zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
276276
}
277277
return &EG(uninitialized_zval);
278278
}
@@ -3788,7 +3788,7 @@ static zend_never_inline void zend_fetch_this_var(int type OPLINE_DC EXECUTE_DAT
37883788
Z_ADDREF_P(result);
37893789
} else {
37903790
ZVAL_NULL(result);
3791-
zend_error(E_WARNING, "Undefined variable $this");
3791+
zend_error_unchecked(E_WARNING, "Undefined variable $this");
37923792
}
37933793
break;
37943794
case BP_VAR_IS:

Zend/zend_vm_def.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -1755,8 +1755,8 @@ ZEND_VM_C_LABEL(fetch_this):
17551755
/* Keep name alive in case an error handler tries to free it. */
17561756
zend_string_addref(name);
17571757
}
1758-
zend_error(E_WARNING, "Undefined %svariable $%s",
1759-
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
1758+
zend_error_unchecked(E_WARNING, "Undefined %svariable $%S",
1759+
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name);
17601760
if (type == BP_VAR_RW && !EG(exception)) {
17611761
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
17621762
} else {
@@ -1778,8 +1778,8 @@ ZEND_VM_C_LABEL(fetch_this):
17781778
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
17791779
retval = &EG(uninitialized_zval);
17801780
} else {
1781-
zend_error(E_WARNING, "Undefined %svariable $%s",
1782-
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
1781+
zend_error_unchecked(E_WARNING, "Undefined %svariable $%S",
1782+
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), name);
17831783
if (type == BP_VAR_RW && !EG(exception)) {
17841784
ZVAL_NULL(retval);
17851785
} else {

Zend/zend_vm_execute.h

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/opcache/jit/zend_jit_helpers.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call(zval *object)
9595
if (Z_TYPE_P(object) == IS_UNDEF && opline->op1_type == IS_CV) {
9696
zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
9797

98-
zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
98+
zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
9999
if (UNEXPECTED(EG(exception) != NULL)) {
100100
return;
101101
}
@@ -340,7 +340,7 @@ static int ZEND_FASTCALL zend_jit_undefined_op_helper(uint32_t var)
340340
const zend_execute_data *execute_data = EG(current_execute_data);
341341
zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
342342

343-
zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
343+
zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
344344
return EG(exception) == NULL;
345345
}
346346

@@ -354,7 +354,7 @@ static int ZEND_FASTCALL zend_jit_undefined_op_helper_write(HashTable *ht, uint3
354354
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
355355
GC_ADDREF(ht);
356356
}
357-
zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
357+
zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
358358
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
359359
if (!GC_REFCOUNT(ht)) {
360360
zend_array_destroy(ht);
@@ -2418,7 +2418,7 @@ static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, cons
24182418
if (Z_TYPE_P(container) == IS_UNDEF && opline->op1_type == IS_CV) {
24192419
zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
24202420

2421-
zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
2421+
zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
24222422
}
24232423
if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
24242424
ZVAL_UNDEF(EX_VAR(opline->result.var));

ext/opcache/jit/zend_jit_ir.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -4646,7 +4646,7 @@ static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t o
46464646
if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
46474647
ir_IF_FALSE_cold(if_def);
46484648

4649-
// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
4649+
// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
46504650
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
46514651

46524652
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,
55885588
if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
55895589
ir_IF_FALSE_cold(if_def);
55905590

5591-
// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
5591+
// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
55925592
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
55935593

55945594
ref2 = jit_EG(uninitialized_zval);
@@ -5604,7 +5604,7 @@ static int zend_jit_long_math_helper(zend_jit_ctx *jit,
56045604
if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
56055605
ir_IF_FALSE_cold(if_def);
56065606

5607-
// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var))));
5607+
// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
56085608
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
56095609

56105610
ref2 = jit_EG(uninitialized_zval);
@@ -5980,7 +5980,7 @@ static int zend_jit_simple_assign(zend_jit_ctx *jit,
59805980
jit_SET_EX_OPLINE(jit, opline);
59815981

59825982
ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
5983-
// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
5983+
// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
59845984
ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
59855985

59865986
if (check_exception) {

ext/standard/array.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2608,7 +2608,7 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu
26082608
zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
26092609
}
26102610
} else {
2611-
php_error_docref(NULL, E_WARNING, "Undefined variable $%s", ZSTR_VAL(Z_STR_P(entry)));
2611+
php_error_docref_unchecked(NULL, E_WARNING, "Undefined variable $%S", Z_STR_P(entry));
26122612
}
26132613
} else if (Z_TYPE_P(entry) == IS_ARRAY) {
26142614
if (Z_REFCOUNTED_P(entry)) {

0 commit comments

Comments
 (0)