Skip to content

Commit 437d88c

Browse files
committed
wip
1 parent 99640e2 commit 437d88c

File tree

9 files changed

+1249
-156
lines changed

9 files changed

+1249
-156
lines changed

Zend/Optimizer/zend_func_info.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
7777
}
7878
if ((t1 & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))
7979
&& (t2 & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
80-
if ((t3 & MAY_BE_ANY) != MAY_BE_DOUBLE) {
81-
tmp |= MAY_BE_ARRAY_OF_LONG;
82-
}
80+
tmp |= MAY_BE_ARRAY_OF_LONG;
8381
}
8482
if (tmp & MAY_BE_ARRAY_OF_ANY) {
8583
tmp |= MAY_BE_ARRAY_PACKED;

Zend/Optimizer/zend_optimizer.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,26 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
13321332
}
13331333
break;
13341334
}
1335+
#ifdef ZEND_VERIFY_TYPE_INFERENCE
1336+
if (ssa_op->op1_use >= 0) {
1337+
opline->op1_use_type = ssa->var_info[ssa_op->op1_use].type;
1338+
}
1339+
if (ssa_op->op2_use >= 0) {
1340+
opline->op2_use_type = ssa->var_info[ssa_op->op2_use].type;
1341+
}
1342+
if (ssa_op->result_use >= 0) {
1343+
opline->result_use_type = ssa->var_info[ssa_op->result_use].type;
1344+
}
1345+
if (ssa_op->op1_def >= 0) {
1346+
opline->op1_def_type = ssa->var_info[ssa_op->op1_def].type;
1347+
}
1348+
if (ssa_op->op2_def >= 0) {
1349+
opline->op2_def_type = ssa->var_info[ssa_op->op2_def].type;
1350+
}
1351+
if (ssa_op->result_def >= 0) {
1352+
opline->result_def_type = ssa->var_info[ssa_op->result_def].type;
1353+
}
1354+
#endif
13351355
zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
13361356
opline++;
13371357
}

Zend/tests/gh10168/wrong_assign_to_variable.phpt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
--TEST--
22
GH-10168: Wrong assign to variable
3+
--SKIPIF--
4+
<?php
5+
if (defined('ZEND_VERIFY_TYPE_INFERENCE')) die('skip Destructor side-effects violate type inference');
6+
?>
37
--FILE--
48
<?php
59

Zend/zend_execute.c

Lines changed: 2 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -5311,167 +5311,18 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
53115311
# include "zend_vm_trace_lines.h"
53125312
#elif defined(ZEND_VM_TRACE_MAP)
53135313
# include "zend_vm_trace_map.h"
5314-
#endif
5315-
5316-
#ifdef ZEND_VERIFY_TYPE_INFERENCE
5317-
5318-
#define ZEND_VERIFY_TYPE_INFERENCE_ERROR(msg, ...) \
5319-
do { \
5320-
fprintf(stderr, "Inference verification failed at %04d %s (" msg ")\n", (int)(opline - EX(func)->op_array.opcodes), operand, __VA_ARGS__); \
5321-
exit(139); \
5322-
} while (0)
5323-
5324-
static void zend_verify_type_inference(zval *value, uint32_t type_mask, uint8_t op_type, zend_execute_data *execute_data, const zend_op *opline, const char *operand)
5325-
{
5326-
if (type_mask == MAY_BE_CLASS) {
5327-
return;
5328-
}
5329-
5330-
if (Z_TYPE_P(value) == IS_INDIRECT) {
5331-
if (!(type_mask & MAY_BE_INDIRECT)) {
5332-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x mising MAY_BE_INDIRECT", type_mask);
5333-
}
5334-
value = Z_INDIRECT_P(value);
5335-
}
5336-
5337-
/* Verifying RC inference is currently not possible because type information is based on the SSA
5338-
* built without ZEND_SSA_RC_INFERENCE, which is missing various definitions for RC-modifying
5339-
* operations. Support could be added by repeating SSA-construction and type inference with the
5340-
* given flag. */
5341-
// if (Z_REFCOUNTED_P(value)) {
5342-
// if (Z_REFCOUNT_P(value) == 1 && !(type_mask & MAY_BE_RC1)) {
5343-
// ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_RC1", type_mask);
5344-
// }
5345-
// if (Z_REFCOUNT_P(value) > 1 && !(type_mask & MAY_BE_RCN)) {
5346-
// ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_RCN", type_mask);
5347-
// }
5348-
// }
5349-
5350-
if (Z_TYPE_P(value) == IS_REFERENCE) {
5351-
if (!(type_mask & MAY_BE_REF)) {
5352-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_REF", type_mask);
5353-
}
5354-
value = Z_REFVAL_P(value);
5355-
}
5356-
5357-
if (!(type_mask & (1u << Z_TYPE_P(value)))) {
5358-
if (Z_TYPE_P(value) == IS_UNUSED && op_type == IS_VAR && (type_mask & MAY_BE_NULL)) {
5359-
/* FETCH_OBJ_* for typed property may return IS_UNDEF. This is an exception. */
5360-
} else {
5361-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing type %d", type_mask, Z_TYPE_P(value));
5362-
}
5363-
}
5364-
5365-
if (Z_TYPE_P(value) == IS_ARRAY) {
5366-
HashTable *ht = Z_ARRVAL_P(value);
5367-
uint32_t num_checked = 0;
5368-
zend_string *str;
5369-
zval *val;
5370-
if (HT_IS_INITIALIZED(ht)) {
5371-
if (HT_IS_PACKED(ht) && !MAY_BE_PACKED(type_mask)) {
5372-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_PACKED", type_mask);
5373-
}
5374-
if (!HT_IS_PACKED(ht) && !MAY_BE_HASH(type_mask)) {
5375-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_HASH", type_mask);
5376-
}
5377-
} else {
5378-
if (!(type_mask & MAY_BE_ARRAY_EMPTY)) {
5379-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_EMPTY", type_mask);
5380-
}
5381-
}
5382-
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
5383-
if (str) {
5384-
if (!(type_mask & MAY_BE_ARRAY_KEY_STRING)) {
5385-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_KEY_STRING", type_mask);
5386-
break;
5387-
}
5388-
} else {
5389-
if (!(type_mask & MAY_BE_ARRAY_KEY_LONG)) {
5390-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_KEY_LONG", type_mask);
5391-
break;
5392-
}
5393-
}
5394-
5395-
uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
5396-
if (!(type_mask & array_type)) {
5397-
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing array type %d", type_mask, Z_TYPE_P(val));
5398-
break;
5399-
}
5400-
5401-
/* Don't check all elements of large arrays. */
5402-
if (++num_checked > 16) {
5403-
break;
5404-
}
5405-
} ZEND_HASH_FOREACH_END();
5406-
}
5407-
}
5408-
5409-
static void zend_verify_inference_use(zend_execute_data *execute_data, const zend_op *opline)
5410-
{
5411-
if (opline->op1_use_type
5412-
&& (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV))
5413-
&& opline->opcode != ZEND_ROPE_ADD
5414-
&& opline->opcode != ZEND_ROPE_END) {
5415-
zend_verify_type_inference(EX_VAR(opline->op1.var), opline->op1_use_type, opline->op1_type, execute_data, opline, "op1_use");
5416-
}
5417-
if (opline->op2_use_type
5418-
&& (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))) {
5419-
zend_verify_type_inference(EX_VAR(opline->op2.var), opline->op2_use_type, opline->op2_type, execute_data, opline, "op2_use");
5420-
}
5421-
if (opline->result_use_type
5422-
&& (opline->result_type & (IS_TMP_VAR|IS_VAR|IS_CV))) {
5423-
zend_verify_type_inference(EX_VAR(opline->result.var), opline->result_use_type, opline->result_type, execute_data, opline, "result_use");
5424-
}
5425-
}
5426-
5427-
static void zend_verify_inference_def(zend_execute_data *execute_data, const zend_op *opline)
5428-
{
5429-
if (EG(exception)) {
5430-
return;
5431-
}
5432-
if (opline->op1_def_type
5433-
&& (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV))
5434-
// array is actually changed by the the following instruction(s)
5435-
&& opline->opcode != ZEND_FETCH_DIM_W
5436-
&& opline->opcode != ZEND_FETCH_DIM_RW
5437-
&& opline->opcode != ZEND_FETCH_DIM_FUNC_ARG
5438-
&& opline->opcode != ZEND_FETCH_LIST_W) {
5439-
zend_verify_type_inference(EX_VAR(opline->op1.var), opline->op1_def_type, opline->op1_type, execute_data, opline, "op1_def");
5440-
}
5441-
if (opline->op2_def_type
5442-
&& (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))) {
5443-
zend_verify_type_inference(EX_VAR(opline->op2.var), opline->op2_def_type, opline->op2_type, execute_data, opline, "op2_def");
5444-
}
5445-
if (opline->result_def_type
5446-
&& (opline->result_type & (IS_TMP_VAR|IS_VAR|IS_CV))
5447-
&& opline->opcode != ZEND_ROPE_INIT
5448-
&& opline->opcode != ZEND_ROPE_ADD
5449-
// Some jump opcode handlers don't set result when it's never read
5450-
&& opline->opcode != ZEND_JMP_SET
5451-
&& opline->opcode != ZEND_JMP_NULL
5452-
&& opline->opcode != ZEND_COALESCE
5453-
&& opline->opcode != ZEND_ASSERT_CHECK) {
5454-
zend_verify_type_inference(EX_VAR(opline->result.var), opline->result_def_type, opline->result_type, execute_data, opline, "result_def");
5455-
}
5456-
}
5457-
5458-
# define ZEND_VERIFY_INFERENCE_USE() zend_verify_inference_use(execute_data, OPLINE);
5459-
# define ZEND_VERIFY_INFERENCE_DEF() zend_verify_inference_def(execute_data, OPLINE);
5460-
#else
5461-
# define ZEND_VERIFY_INFERENCE_USE()
5462-
# define ZEND_VERIFY_INFERENCE_DEF()
5314+
#elif defined(ZEND_VERIFY_TYPE_INFERENCE)
5315+
# include "zend_verify_type_inference.h"
54635316
#endif
54645317

54655318
#define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
5466-
ZEND_VERIFY_INFERENCE_DEF() \
54675319
CHECK_SYMBOL_TABLES() \
54685320
if (check_exception) { \
54695321
OPLINE = EX(opline) + (skip); \
54705322
} else { \
54715323
ZEND_ASSERT(!EG(exception)); \
54725324
OPLINE = opline + (skip); \
54735325
} \
5474-
ZEND_VERIFY_INFERENCE_USE() \
54755326
ZEND_VM_CONTINUE()
54765327

54775328
#define ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION() \

0 commit comments

Comments
 (0)