?? ??? 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)
--- /dev/null
+--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
}
/* }}} */
+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;
}
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 {
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;
}
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--;
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++;
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++;
opline++;
}
- strip_nop(block, ctx);
+ strip_nop(block, op_array, ctx);
}
/* Rebuild plain (optimized) op_array from CFG */