Fixed bug #72944 (Null pointer deref in zval_delref_p).

This commit is contained in:
Dmitry Stogov 2016-08-29 12:02:50 +03:00
parent ca1eb585ee
commit b66039db33
5 changed files with 77 additions and 4 deletions

1
NEWS
View File

@ -3,6 +3,7 @@ PHP NEWS
?? ??? 2016 PHP 7.0.11
- Core:
. Fixed bug #72944 (Null pointer deref in zval_delref_p). (Dmitry)
. Fixed bug #72943 (assign_dim on string doesn't reset hval). (Laruence)
. Fixed bug #72911 (Memleak in zend_binary_assign_op_obj_helper). (Laruence)
. Fixed bug #72813 (Segfault with __get returned by ref). (Laruence)

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

@ -1944,10 +1944,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

@ -761,6 +761,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(zend_uchar 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

@ -561,7 +561,7 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int
convert_to_string((v)); \
}
static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx)
static void strip_nop(zend_code_block *block, zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline = block->start_opline;
zend_op *end, *new_end;
@ -575,6 +575,14 @@ static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx)
}
return;
}
if (block->len == 2
&& ((block->start_opline + 1)->opcode == ZEND_JMPZ
|| (block->start_opline + 1)->opcode == ZEND_JMPNZ)
&& (block->start_opline + 1)->op1_type & (IS_CV|IS_CONST)
&& block->start_opline > op_array->opcodes
&& zend_is_smart_branch(block->start_opline - 1)) {
break;
}
block->start_opline++;
block->start_opline_no++;
block->len--;
@ -588,10 +596,21 @@ static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx)
zend_op *src;
int len = 0;
src = opline;
while (opline < end && opline->opcode == ZEND_NOP) {
if (opline + 1 < end
&& ((opline + 1)->opcode == ZEND_JMPZ
|| (opline + 1)->opcode == ZEND_JMPNZ)
&& (opline + 1)->op1_type & (IS_CV|IS_CONST)
&& opline > op_array->opcodes
&& zend_is_smart_branch(opline - 1)) {
/* don't remove NOP, that splits incorrect smart branch */
opline++;
break;
}
src++;
opline++;
}
src = opline;
while (opline < end && opline->opcode != ZEND_NOP) {
opline++;
@ -621,6 +640,14 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
if (block->follow_to) {
delete_code_block(block, ctx);
}
if (block->len == 2
&& ((block->start_opline + 1)->opcode == ZEND_JMPZ
|| (block->start_opline + 1)->opcode == ZEND_JMPNZ)
&& (block->start_opline + 1)->op1_type & (IS_CV|IS_CONST)
&& block->start_opline > op_array->opcodes
&& zend_is_smart_branch(block->start_opline - 1)) {
break;
}
return;
}
block->start_opline++;
@ -1137,7 +1164,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
opline++;
}
strip_nop(block, ctx);
strip_nop(block, op_array, ctx);
}
/* Rebuild plain (optimized) op_array from CFG */