Merge branch 'PHP-7.1'

* PHP-7.1:
  Fixed bug #72944 (Null pointer deref in zval_delref_p).
This commit is contained in:
Dmitry Stogov 2016-08-29 12:15:37 +03:00
commit 6318c80347
6 changed files with 73 additions and 15 deletions

12
Zend/tests/bug72944.phpt Normal file
View File

@ -0,0 +1,12 @@
--TEST--
Bug #72944 (Null pointer deref in zval_delref_p).
--FILE--
<?php
"a"== e & $A = $A? 0 : 0 ?:0;
echo "OK\n";
?>
--EXPECTF--
Notice: Use of undefined constant e - assumed 'e' in %sbug72944.php on line 2
Notice: Undefined variable: A in %sbug72944.php on line 2
OK

View File

@ -2198,10 +2198,42 @@ static inline uint32_t zend_emit_jump(uint32_t opnum_target) /* {{{ */
}
/* }}} */
ZEND_API int zend_is_smart_branch(zend_op *opline) /* {{{ */
{
switch (opline->opcode) {
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
case ZEND_INSTANCEOF:
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
return 1;
default:
return 0;
}
}
/* }}} */
static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target) /* {{{ */
{
uint32_t opnum = get_next_op_number(CG(active_op_array));
zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL);
zend_op *opline;
if ((cond->op_type & (IS_CV|IS_CONST))
&& opnum > 0
&& zend_is_smart_branch(CG(active_op_array)->opcodes + opnum - 1)) {
/* emit extra NOP to avoid incorrect SMART_BRANCH in very rare cases */
zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
opnum = get_next_op_number(CG(active_op_array));
}
opline = zend_emit_op(NULL, opcode, cond, NULL);
opline->op2.opline_num = opnum_target;
return opnum;
}

View File

@ -791,6 +791,7 @@ ZEND_API char *zend_make_compiled_string_description(const char *name);
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers);
uint32_t zend_get_class_fetch_type(zend_string *name);
ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc);
ZEND_API int zend_is_smart_branch(zend_op *opline);
typedef zend_bool (*zend_auto_global_callback)(zend_string *name);
typedef struct _zend_auto_global {

View File

@ -91,6 +91,15 @@ static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
zend_op *opcodes = op_array->opcodes;
while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP) {
/* check if NOP breaks incorrect smart branch */
if (b->len == 2
&& (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
|| op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
&& (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
&& b->start > 0
&& zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
break;
}
b->start++;
b->len--;
}
@ -114,6 +123,14 @@ static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
}
j++;
}
if (i + 1 < b->start + b->len
&& (op_array->opcodes[i+1].opcode == ZEND_JMPZ
|| op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
&& op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
&& zend_is_smart_branch(op_array->opcodes + j - 1)) {
/* don't remove NOP, that splits incorrect smart branch */
j++;
}
i++;
}
b->len = j - b->start;

View File

@ -149,20 +149,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa)
i + 1 < op_array->last &&
(op_array->opcodes[i+1].opcode == ZEND_JMPZ ||
op_array->opcodes[i+1].opcode == ZEND_JMPNZ) &&
(op_array->opcodes[i-1].opcode == ZEND_IS_IDENTICAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_NOT_IDENTICAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_NOT_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER ||
op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER_OR_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_CASE ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_VAR ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_STATIC_PROP ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ ||
op_array->opcodes[i-1].opcode == ZEND_INSTANCEOF ||
op_array->opcodes[i-1].opcode == ZEND_TYPE_CHECK ||
op_array->opcodes[i-1].opcode == ZEND_DEFINED))) {
zend_is_smart_branch(op_array->opcodes + i - 1))) {
if (i != target) {
op_array->opcodes[target] = op_array->opcodes[i];
ssa->ops[target] = ssa->ops[i];

View File

@ -109,6 +109,15 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *
b = blocks + block_map[live_range->start];
if (b->flags & ZEND_BB_REACHABLE) {
while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) {
/* check if NOP breaks incorrect smart branch */
if (b->len == 2
&& (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
|| op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
&& (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
&& b->start > 0
&& zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
break;
}
b->start++;
b->len--;
}