Merge branch 'temporary_cleaning' of https://github.com/laruence/php-src into temporary_cleaning

* 'temporary_cleaning' of https://github.com/laruence/php-src:
  Fixed checkpoint get
  Fixed crash of invalid pointer derefer
  cleanup
This commit is contained in:
Dmitry Stogov 2015-07-07 12:00:53 +03:00
commit 0341626ea9

View file

@ -867,6 +867,8 @@ static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array,
start++; start++;
} }
if (start < end) { if (start < end) {
op_var_info *new_opTs;
var_offset = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var); var_offset = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var);
if (op_array->opcodes[end].opcode == ZEND_ROPE_END) { if (op_array->opcodes[end].opcode == ZEND_ROPE_END) {
var_offset |= ZEND_LIVE_ROPE; var_offset |= ZEND_LIVE_ROPE;
@ -890,10 +892,11 @@ static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array,
} else { } else {
count += 2; count += 2;
} }
op_var_info *newOpTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
newOpTs->next = opTs[start]; new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
newOpTs->var = var_offset; new_opTs->next = opTs[start];
opTs[start] = newOpTs; new_opTs->var = var_offset;
opTs[start] = new_opTs;
for (j = start + 1; j < end; j++) { for (j = start + 1; j < end; j++) {
if (opTs[j-1]->next == opTs[j]) { if (opTs[j-1]->next == opTs[j]) {
@ -904,84 +907,97 @@ static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array,
} else { } else {
count += 2; count += 2;
} }
op_var_info *newOpTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info)); new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
newOpTs->next = opTs[j]; new_opTs->next = opTs[j];
newOpTs->var = var_offset; new_opTs->var = var_offset;
opTs[j] = newOpTs; opTs[j] = new_opTs;
} }
} }
} }
return count; return count;
} }
static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_array *op_array, zend_bool done_pass_two) static uint32_t *generate_var_liveliness_info_ex(zend_op_array *op_array, zend_bool done_pass_two)
{ {
uint32_t i, op_live_total = 0, var; zend_op *opline, *end;
void *checkpoint = zend_arena_checkpoint(CG(arena)); uint32_t var, i, op_live_total = 0;
uint32_t *info, info_off = op_array->last + 1; uint32_t *info, info_off = op_array->last + 1;
uint32_t *Tstart = zend_arena_alloc(&CG(arena), sizeof(uint32_t) * op_array->T); void *checkpoint = zend_arena_checkpoint(CG(arena));
uint32_t *Tstart = zend_arena_alloc(&CG(arena), sizeof(uint32_t) * op_array->T);
op_var_info **opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info *) * op_array->last); op_var_info **opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info *) * op_array->last);
memset(Tstart, -1, sizeof(uint32_t) * op_array->T); memset(Tstart, -1, sizeof(uint32_t) * op_array->T);
memset(opTs, 0, sizeof(op_var_info *) * op_array->last); memset(opTs, 0, sizeof(op_var_info *) * op_array->last);
zend_op *end_op = op_array->opcodes + op_array->last; opline = op_array->opcodes;
zend_op *cur_op = op_array->opcodes; end = opline + op_array->last;
for (; cur_op < end_op; cur_op++) { do {
if ((cur_op->result_type & (IS_VAR | IS_TMP_VAR)) if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
&& !(cur_op->result_type & EXT_TYPE_UNUSED) && !((opline)->result_type & EXT_TYPE_UNUSED)
&& cur_op->opcode != ZEND_BOOL /* the following opcodes are used in inline branching (and anyway always bool, so no need to free) and may not be defined depending on the taken branch */ /* the following opcodes are used in inline branching
&& cur_op->opcode != ZEND_JMPZ_EX * (and anyway always bool, so no need to free) and may
&& cur_op->opcode != ZEND_JMPNZ_EX * not be defined depending on the taken branch */
&& (cur_op->opcode != ZEND_QM_ASSIGN || (cur_op + 1)->opcode != ZEND_JMP) /* these two consecutive ops appear on ternary; the result of true branch is undefined for false branch */ && opline->opcode != ZEND_BOOL
&& cur_op->opcode != ZEND_CASE /* exception for opcache, it might nowhere use the temporary (anyway bool, so no need to free) */ && opline->opcode != ZEND_JMPZ_EX
&& cur_op->opcode != ZEND_ROPE_ADD /* the following opcodes reuse TMP created before */ && opline->opcode != ZEND_JMPNZ_EX
&& cur_op->opcode != ZEND_ADD_ARRAY_ELEMENT /* these two consecutive ops appear on ternary,
&& cur_op->opcode != ZEND_FAST_CALL /* passes fast_call */ * the result of true branch is undefined for false branch */
&& cur_op->opcode != ZEND_FETCH_CLASS /* the following opcodes pass class_entry */ && (opline->opcode != ZEND_QM_ASSIGN || (opline + 1)->opcode != ZEND_JMP)
&& cur_op->opcode != ZEND_DECLARE_CLASS /* exception for opcache, it might nowhere use the temporary
&& cur_op->opcode != ZEND_DECLARE_INHERITED_CLASS * (anyway bool, so no need to free) */
&& cur_op->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED && opline->opcode != ZEND_CASE
&& cur_op->opcode != ZEND_DECLARE_ANON_CLASS /* the following opcodes reuse TMP created before */
&& cur_op->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) { && opline->opcode != ZEND_ROPE_ADD
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
/* passes fast_call */
&& opline->opcode != ZEND_FAST_CALL
/* the following opcodes pass class_entry */
&& opline->opcode != ZEND_FETCH_CLASS
&& opline->opcode != ZEND_DECLARE_CLASS
&& opline->opcode != ZEND_DECLARE_INHERITED_CLASS
&& opline->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED
&& opline->opcode != ZEND_DECLARE_ANON_CLASS
&& opline->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) {
if (done_pass_two) { if (done_pass_two) {
var = EX_VAR_TO_NUM(cur_op->result.var) - op_array->last_var; var = EX_VAR_TO_NUM(opline->result.var) - op_array->last_var;
} else { } else {
var = cur_op->result.var; var = opline->result.var;
} }
/* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */ /* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */
if (cur_op->opcode == ZEND_NEW) { if (opline->opcode == ZEND_NEW) {
Tstart[var] = cur_op->op2.opline_num - 1; Tstart[var] = opline->op2.opline_num - 1;
} else { } else {
Tstart[var] = cur_op - op_array->opcodes; Tstart[var] = opline - op_array->opcodes;
} }
} }
if (cur_op->op1_type & (IS_VAR | IS_TMP_VAR)) { if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
if (done_pass_two) { if (done_pass_two) {
var = EX_VAR_TO_NUM(cur_op->op1.var) - op_array->last_var; var = EX_VAR_TO_NUM(opline->op1.var) - op_array->last_var;
} else { } else {
var = cur_op->op1.var; var = opline->op1.var;
} }
if (Tstart[var] != (uint32_t)-1 if (Tstart[var] != (uint32_t)-1
&& cur_op->opcode != ZEND_ROPE_ADD /* the following opcodes don't free TMP */ /* the following opcodes don't free TMP */
&& cur_op->opcode != ZEND_FETCH_LIST && opline->opcode != ZEND_ROPE_ADD
&& cur_op->opcode != ZEND_CASE && opline->opcode != ZEND_FETCH_LIST
&& cur_op->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_CASE
&& cur_op->opcode != ZEND_FE_FETCH_RW) { && opline->opcode != ZEND_FE_FETCH_R
op_live_total += liveliness_kill_var(op_array, cur_op, var, Tstart, opTs); && opline->opcode != ZEND_FE_FETCH_RW) {
op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
} }
} }
if (cur_op->op2_type & (IS_VAR | IS_TMP_VAR)) { if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
if (done_pass_two) { if (done_pass_two) {
var = EX_VAR_TO_NUM(cur_op->op2.var) - op_array->last_var; var = EX_VAR_TO_NUM(opline->op2.var) - op_array->last_var;
} else { } else {
var = cur_op->op2.var; var = opline->op2.var;
} }
if (Tstart[var] != (uint32_t)-1) { if (Tstart[var] != (uint32_t)-1) {
op_live_total += liveliness_kill_var(op_array, cur_op, var, Tstart, opTs); op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
} }
} }
} } while (++opline != end);
#if ZEND_DEBUG #if ZEND_DEBUG
/* Check that all TMP variable live-ranges are closed */ /* Check that all TMP variable live-ranges are closed */