diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index a2e1d03404d8..1e6cacca5c43 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -4926,6 +4926,9 @@ ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array } /* }}} */ +/* Key types whose conversion to an array offset may emit a diagnostic */ +#define MAY_BE_THROWING_KEY (MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE) + ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa, uint32_t t1, uint32_t t2) { if (opline->op1_type == IS_CV) { @@ -5205,7 +5208,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op return 1; } return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED || - (t2 & (MAY_BE_UNDEF|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); + (t2 & (MAY_BE_UNDEF|MAY_BE_THROWING_KEY)); case ZEND_ASSIGN_OBJ: if (t1 & (MAY_BE_ANY-MAY_BE_OBJECT)) { return 1; @@ -5257,9 +5260,9 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op case ZEND_ROPE_END: return t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT); case ZEND_INIT_ARRAY: - return (opline->op2_type != IS_UNUSED) && (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); + return (opline->op2_type != IS_UNUSED) && (t2 & MAY_BE_THROWING_KEY); case ZEND_ADD_ARRAY_ELEMENT: - return (opline->op2_type == IS_UNUSED) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); + return (opline->op2_type == IS_UNUSED) || (t2 & MAY_BE_THROWING_KEY); case ZEND_STRLEN: return (t1 & MAY_BE_ANY) != MAY_BE_STRING; case ZEND_COUNT: @@ -5286,9 +5289,9 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op case ZEND_FETCH_IS: return (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)); case ZEND_ISSET_ISEMPTY_DIM_OBJ: - return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT)); + return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_THROWING_KEY); case ZEND_FETCH_DIM_IS: - return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); + return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_THROWING_KEY); case ZEND_CAST: switch (opline->extended_value) { case IS_LONG: @@ -5309,7 +5312,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op if ((t2 & MAY_BE_ANY) != MAY_BE_ARRAY) { return 1; } - if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { + if (t1 & MAY_BE_THROWING_KEY) { return 1; } return 0; @@ -5334,7 +5337,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op if (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { return 1; } - if (t2 & (MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT)) { + if (t2 & MAY_BE_THROWING_KEY) { return 1; } if (opline->op2_type == IS_UNUSED) { diff --git a/ext/opcache/tests/jit/add_array_element_float_key.phpt b/ext/opcache/tests/jit/add_array_element_float_key.phpt new file mode 100644 index 000000000000..8d6d4efd2b31 --- /dev/null +++ b/ext/opcache/tests/jit/add_array_element_float_key.phpt @@ -0,0 +1,27 @@ +--TEST-- +JIT ADD_ARRAY_ELEMENT: float key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- + 1]); +} + +try { + test(1.5); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/array_key_exists_float_key.phpt b/ext/opcache/tests/jit/array_key_exists_float_key.phpt new file mode 100644 index 000000000000..e1c9b62ac23c --- /dev/null +++ b/ext/opcache/tests/jit/array_key_exists_float_key.phpt @@ -0,0 +1,27 @@ +--TEST-- +JIT ARRAY_KEY_EXISTS: float key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/assign_dim_float_key.phpt b/ext/opcache/tests/jit/assign_dim_float_key.phpt new file mode 100644 index 000000000000..014ccba9260b --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_float_key.phpt @@ -0,0 +1,28 @@ +--TEST-- +JIT ASSIGN_DIM: float key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/fetch_dim_w_float_key.phpt b/ext/opcache/tests/jit/fetch_dim_w_float_key.phpt new file mode 100644 index 000000000000..03058e916658 --- /dev/null +++ b/ext/opcache/tests/jit/fetch_dim_w_float_key.phpt @@ -0,0 +1,37 @@ +--TEST-- +JIT FETCH_DIM_W: float key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +destruct +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/init_array_float_key.phpt b/ext/opcache/tests/jit/init_array_float_key.phpt new file mode 100644 index 000000000000..315c7f08181b --- /dev/null +++ b/ext/opcache/tests/jit/init_array_float_key.phpt @@ -0,0 +1,27 @@ +--TEST-- +JIT INIT_ARRAY: float key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- + 1]); +} + +try { + test(1.5); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/isset_isempty_dim_obj_resource_key.phpt b/ext/opcache/tests/jit/isset_isempty_dim_obj_resource_key.phpt new file mode 100644 index 000000000000..cb5ccd6b040e --- /dev/null +++ b/ext/opcache/tests/jit/isset_isempty_dim_obj_resource_key.phpt @@ -0,0 +1,29 @@ +--TEST-- +JIT ISSET_ISEMPTY_DIM_OBJ: resource key conversion may throw +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Exception: Resource ID#%d used as offset, casting to integer (%d) diff --git a/ext/opcache/tests/opt/dce_018.phpt b/ext/opcache/tests/opt/dce_018.phpt new file mode 100644 index 000000000000..f4613d0d860d --- /dev/null +++ b/ext/opcache/tests/opt/dce_018.phpt @@ -0,0 +1,27 @@ +--TEST-- +DCE must not remove ASSIGN_DIM with a float key +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/opt/dce_019.phpt b/ext/opcache/tests/opt/dce_019.phpt new file mode 100644 index 000000000000..3996185c84ff --- /dev/null +++ b/ext/opcache/tests/opt/dce_019.phpt @@ -0,0 +1,27 @@ +--TEST-- +DCE must not remove INIT_ARRAY with a float key +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- + 1]; +} + +try { + test(1.5); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/opt/dce_020.phpt b/ext/opcache/tests/opt/dce_020.phpt new file mode 100644 index 000000000000..722c40506fbc --- /dev/null +++ b/ext/opcache/tests/opt/dce_020.phpt @@ -0,0 +1,27 @@ +--TEST-- +DCE must not remove ADD_ARRAY_ELEMENT with a float key +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- + 1]; +} + +try { + test(1.5); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/opt/dce_021.phpt b/ext/opcache/tests/opt/dce_021.phpt new file mode 100644 index 000000000000..6cf0fd49779d --- /dev/null +++ b/ext/opcache/tests/opt/dce_021.phpt @@ -0,0 +1,27 @@ +--TEST-- +DCE must not remove ARRAY_KEY_EXISTS with a float key +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/opt/dce_022.phpt b/ext/opcache/tests/opt/dce_022.phpt new file mode 100644 index 000000000000..d2e0ac1baf49 --- /dev/null +++ b/ext/opcache/tests/opt/dce_022.phpt @@ -0,0 +1,29 @@ +--TEST-- +DCE must not remove ISSET_ISEMPTY_DIM_OBJ with a resource key +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Exception: Resource ID#%d used as offset, casting to integer (%d)