Repository navigation
Conversation
41c8478 to
cb5269e
Compare
dstogov
left a comment
There was a problem hiding this comment.
This solution looks completely wrong.
The following PHP code doesn't modify $a (it throws exception) and $a is still empty.
$a = [];
$a[$a] = 1;cb5269e to
f6f5b5b
Compare
|
Confirmed: |
| function arrayKeyThrows() { | ||
| $a = []; | ||
| try { | ||
| $a[$a] = 1; |
There was a problem hiding this comment.
I don't think this tests what you think it does. This compiles to ASSIGN_DIM
There was a problem hiding this comment.
Ah, indeed, that case never reached FETCH_DIM_W. Dropped it.
| --INI-- | ||
| opcache.enable=1 | ||
| opcache.enable_cli=1 | ||
| opcache.jit=1254 |
There was a problem hiding this comment.
| opcache.jit=1254 | |
| opcache.optimization_level=-1 |
I think it shoud have been this.
}
}
- if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG
- && (opline->op2_type == IS_UNUSED
- || !(t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)))) {
- tmp &= ~MAY_BE_ARRAY_EMPTY;
- }
}
+ if (opline->opcode == ZEND_FETCH_DIM_W
+ || opline->opcode == ZEND_FETCH_DIM_RW
+ || opline->opcode == ZEND_FETCH_LIST_W) {
+ tmp &= ~MAY_BE_ARRAY_EMPTY;
+ }
if (!(tmp & MAY_BE_ARRAY)
|| (tmp & MAY_BE_ARRAY_KEY_ANY)I think this might solve the problem. Also, the test should be in |
FETCH_DIM_W stripped MAY_BE_ARRAY_EMPTY only when key_type had a valid key bit. When the key operand widened across loop iterations from MAY_BE_ARRAY to MAY_BE_ARRAY|MAY_BE_LONG, the strip switched on in the second pass and the result type lost MAY_BE_ARRAY_EMPTY. Strip only when the key cannot throw (append, or no MAY_BE_ARRAY|MAY_BE_OBJECT in the key type), since such a key throws before the write and leaves the array empty. Fixes phpGH-17144
f6f5b5b to
a965cab
Compare
|
That is the first version of this PR, which Dmitry rejected above, so I kept the guarded strip. Moved the test to |
Yes, but I think this is the correct solution. Dmitry's remark was a bit vague. Disregarding the difference between |
|
Agreed, DFA bails on any function with try/catch, so nothing observes the def past the throw. |
Summary
FETCH_DIM_WstrippedMAY_BE_ARRAY_EMPTYonly inside a block guarded bykey_type & (MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING). When the key operand's type widened across loop iterations (e.g. fromMAY_BE_ARRAYto include scalar types),key_typewent from 0 to non-zero, causing the flag to be stripped on the second pass but not the first. This violated monotonicity and triggered the narrowing assertion.Strips
MAY_BE_ARRAY_EMPTYfor write opcodes (W, RW, LIST_W) regardless ofkey_type, since a dimension write makes the array non-empty.Fixes #17144