Skip to content

Commit

Permalink
Fix T_NUM_STRING negation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikic committed Dec 11, 2016
1 parent 8b82e2c commit 2c70581
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 4 deletions.
47 changes: 47 additions & 0 deletions Zend/tests/neg_num_string.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
--TEST--
Test edge-cases for negative num strings in interpolated string offsets
--FILE--
<?php

$a = [
"0" => 1,
"-0" => 2,
"1" => 3,
"-1" => 4,
"0x0" => 5,
"-0x0" => 6,
"00" => 7,
"-00" => 8,
"9223372036854775808" => 9,
"-9223372036854775808" => 10,
"2147483648" => 11,
"-2147483648" => 12,
];

var_dump("$a[0]");
var_dump("$a[-0]");
var_dump("$a[1]");
var_dump("$a[-1]");
var_dump("$a[0x0]");
var_dump("$a[-0x0]");
var_dump("$a[00]");
var_dump("$a[-00]");
var_dump("$a[9223372036854775808]");
var_dump("$a[-9223372036854775808]");
var_dump("$a[2147483648]");
var_dump("$a[-2147483648]");

?>
--EXPECT--
string(1) "1"
string(1) "2"
string(1) "3"
string(1) "4"
string(1) "5"
string(1) "6"
string(1) "7"
string(1) "8"
string(1) "9"
string(2) "10"
string(2) "11"
string(2) "12"
22 changes: 22 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,28 @@ zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
}
/* }}} */

zend_ast *zend_negate_num_string(zend_ast *ast) /* {{{ */
{
zval *zv = zend_ast_get_zval(ast);
if (Z_TYPE_P(zv) == IS_LONG) {
if (Z_LVAL_P(zv) == 0) {
ZVAL_NEW_STR(zv, zend_string_init("-0", sizeof("-0")-1, 0));
} else {
ZEND_ASSERT(Z_LVAL_P(zv) > 0);
Z_LVAL_P(zv) *= -1;
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
size_t orig_len = Z_STRLEN_P(zv);
zend_string_extend(Z_STR_P(zv), orig_len + 1, 0);
memmove(Z_STRVAL_P(zv) + 1, Z_STRVAL_P(zv), orig_len + 1);
Z_STRVAL_P(zv)[0] = '-';
} else {
ZEND_ASSERT(0);
}
return ast;
}
/* }}} */

void zend_verify_namespace(void) /* {{{ */
{
if (FC(has_bracketed_namespaces) && !FC(in_namespace)) {
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,10 @@ ZEND_API binary_op_type get_binary_op(int opcode);

void zend_stop_lexing(void);
void zend_emit_final_return(int return_one);

/* Used during AST construction */
zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right);
zend_ast *zend_negate_num_string(zend_ast *ast);
uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag);
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag);
void zend_handle_encoding_declaration(zend_ast *ast);
Expand Down
8 changes: 4 additions & 4 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -1247,10 +1247,10 @@ encaps_var:
;

encaps_var_offset:
T_STRING { $$ = $1; }
| T_NUM_STRING { $$ = $1; }
| '-' T_NUM_STRING { $$ = zend_ast_create(ZEND_AST_UNARY_MINUS, $2); }
| T_VARIABLE { $$ = zend_ast_create(ZEND_AST_VAR, $1); }
T_STRING { $$ = $1; }
| T_NUM_STRING { $$ = $1; }
| '-' T_NUM_STRING { $$ = zend_negate_num_string($2); }
| T_VARIABLE { $$ = zend_ast_create(ZEND_AST_VAR, $1); }
;


Expand Down

0 comments on commit 2c70581

Please sign in to comment.