Skip to content

Commit 2c70581

Browse files
committed
Fix T_NUM_STRING negation
T_NUM_STRING follows the rules of symtable numeric string conversion. If the offset isn't an integer under those rules, it is treated as a string. This should apply to negated T_NUM_STRINGs as well.
1 parent 8b82e2c commit 2c70581

File tree

4 files changed

+76
-4
lines changed

4 files changed

+76
-4
lines changed

Zend/tests/neg_num_string.phpt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Test edge-cases for negative num strings in interpolated string offsets
3+
--FILE--
4+
<?php
5+
6+
$a = [
7+
"0" => 1,
8+
"-0" => 2,
9+
"1" => 3,
10+
"-1" => 4,
11+
"0x0" => 5,
12+
"-0x0" => 6,
13+
"00" => 7,
14+
"-00" => 8,
15+
"9223372036854775808" => 9,
16+
"-9223372036854775808" => 10,
17+
"2147483648" => 11,
18+
"-2147483648" => 12,
19+
];
20+
21+
var_dump("$a[0]");
22+
var_dump("$a[-0]");
23+
var_dump("$a[1]");
24+
var_dump("$a[-1]");
25+
var_dump("$a[0x0]");
26+
var_dump("$a[-0x0]");
27+
var_dump("$a[00]");
28+
var_dump("$a[-00]");
29+
var_dump("$a[9223372036854775808]");
30+
var_dump("$a[-9223372036854775808]");
31+
var_dump("$a[2147483648]");
32+
var_dump("$a[-2147483648]");
33+
34+
?>
35+
--EXPECT--
36+
string(1) "1"
37+
string(1) "2"
38+
string(1) "3"
39+
string(1) "4"
40+
string(1) "5"
41+
string(1) "6"
42+
string(1) "7"
43+
string(1) "8"
44+
string(1) "9"
45+
string(2) "10"
46+
string(2) "11"
47+
string(2) "12"

Zend/zend_compile.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,28 @@ zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
18301830
}
18311831
/* }}} */
18321832

1833+
zend_ast *zend_negate_num_string(zend_ast *ast) /* {{{ */
1834+
{
1835+
zval *zv = zend_ast_get_zval(ast);
1836+
if (Z_TYPE_P(zv) == IS_LONG) {
1837+
if (Z_LVAL_P(zv) == 0) {
1838+
ZVAL_NEW_STR(zv, zend_string_init("-0", sizeof("-0")-1, 0));
1839+
} else {
1840+
ZEND_ASSERT(Z_LVAL_P(zv) > 0);
1841+
Z_LVAL_P(zv) *= -1;
1842+
}
1843+
} else if (Z_TYPE_P(zv) == IS_STRING) {
1844+
size_t orig_len = Z_STRLEN_P(zv);
1845+
zend_string_extend(Z_STR_P(zv), orig_len + 1, 0);
1846+
memmove(Z_STRVAL_P(zv) + 1, Z_STRVAL_P(zv), orig_len + 1);
1847+
Z_STRVAL_P(zv)[0] = '-';
1848+
} else {
1849+
ZEND_ASSERT(0);
1850+
}
1851+
return ast;
1852+
}
1853+
/* }}} */
1854+
18331855
void zend_verify_namespace(void) /* {{{ */
18341856
{
18351857
if (FC(has_bracketed_namespaces) && !FC(in_namespace)) {

Zend/zend_compile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,10 @@ ZEND_API binary_op_type get_binary_op(int opcode);
726726

727727
void zend_stop_lexing(void);
728728
void zend_emit_final_return(int return_one);
729+
730+
/* Used during AST construction */
729731
zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right);
732+
zend_ast *zend_negate_num_string(zend_ast *ast);
730733
uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag);
731734
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag);
732735
void zend_handle_encoding_declaration(zend_ast *ast);

Zend/zend_language_parser.y

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,10 +1247,10 @@ encaps_var:
12471247
;
12481248

12491249
encaps_var_offset:
1250-
T_STRING { $$ = $1; }
1251-
| T_NUM_STRING { $$ = $1; }
1252-
| '-' T_NUM_STRING { $$ = zend_ast_create(ZEND_AST_UNARY_MINUS, $2); }
1253-
| T_VARIABLE { $$ = zend_ast_create(ZEND_AST_VAR, $1); }
1250+
T_STRING { $$ = $1; }
1251+
| T_NUM_STRING { $$ = $1; }
1252+
| '-' T_NUM_STRING { $$ = zend_negate_num_string($2); }
1253+
| T_VARIABLE { $$ = zend_ast_create(ZEND_AST_VAR, $1); }
12541254
;
12551255

12561256

0 commit comments

Comments
 (0)