]> granicus.if.org Git - php/commitdiff
Respect strict_types during sccp function call evaluation
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 27 Nov 2020 19:20:48 +0000 (20:20 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 27 Nov 2020 19:24:00 +0000 (20:24 +0100)
Similar to what we do with attributes, add a dummy call frame
on which we can set the strict_types flag.

ext/opcache/Optimizer/sccp.c
ext/opcache/tests/opt/sccp_exception2.phpt
ext/opcache/tests/opt/sccp_exception3.phpt [new file with mode: 0644]

index 973c1763e363a8e3db1cc5ba56bbd0efcec5ba2f..b1979b68a8ab1308d91fb7b93cad15d2142364ee 100644 (file)
@@ -812,7 +812,6 @@ static zend_bool can_ct_eval_func_call(zend_string *name, uint32_t num_args, zva
                || zend_string_equals_literal(name, "str_contains")
                || zend_string_equals_literal(name, "str_ends_with")
                || zend_string_equals_literal(name, "str_split")
-               || zend_string_equals_literal(name, "str_split")
                || zend_string_equals_literal(name, "str_starts_with")
                || zend_string_equals_literal(name, "strpos")
                || zend_string_equals_literal(name, "substr")
@@ -901,9 +900,8 @@ static zend_bool can_ct_eval_func_call(zend_string *name, uint32_t num_args, zva
  * or just happened to be commonly used with constant operands in WP (need to test other
  * applications as well, of course). */
 static inline int ct_eval_func_call(
-               zval *result, zend_string *name, uint32_t num_args, zval **args) {
+               zend_op_array *op_array, zval *result, zend_string *name, uint32_t num_args, zval **args) {
        uint32_t i;
-       zend_execute_data *execute_data, *prev_execute_data;
        zend_function *func = zend_hash_find_ptr(CG(function_table), name);
        if (!func || func->type != ZEND_INTERNAL_FUNCTION) {
                return FAILURE;
@@ -952,9 +950,20 @@ static inline int ct_eval_func_call(
                return FAILURE;
        }
 
+       zend_execute_data *prev_execute_data = EG(current_execute_data);
+       zend_execute_data *execute_data, dummy_frame;
+       zend_op dummy_opline;
+
+       /* Add a dummy frame to get the correct strict_types behavior. */
+       memset(&dummy_frame, 0, sizeof(zend_execute_data));
+       memset(&dummy_opline, 0, sizeof(zend_op));
+       dummy_frame.func = (zend_function *) op_array;
+       dummy_frame.opline = &dummy_opline;
+       dummy_opline.opcode = ZEND_DO_FCALL;
+
        execute_data = safe_emalloc(num_args, sizeof(zval), ZEND_CALL_FRAME_SLOT * sizeof(zval));
        memset(execute_data, 0, sizeof(zend_execute_data));
-       prev_execute_data = EG(current_execute_data);
+       execute_data->prev_execute_data = &dummy_frame;
        EG(current_execute_data) = execute_data;
 
        EX(func) = func;
@@ -1832,7 +1841,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                                break;
                        }
 
-                       if (ct_eval_func_call(&zv, Z_STR_P(name), call->num_args, args) == SUCCESS) {
+                       if (ct_eval_func_call(scdf->op_array, &zv, Z_STR_P(name), call->num_args, args) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
                                break;
index 1485de52e6a0d63116aadae51ac21656fdcd23d0..9cff2b0dc2be0f9721754dcc7cea801d5cbd7aa6 100644 (file)
@@ -8,6 +8,6 @@ require __DIR__ . '/sccp_exception2.inc';
 Fatal error: Uncaught ValueError: version_compare(): Argument #3 ($operator) must be a valid comparison operator in %s:%d
 Stack trace:
 #0 %s(%d): version_compare('1.2', '2.1', '??')
-#1 %s(%d): require('/home/nikic/php...')
+#1 %s(%d): require('%s')
 #2 {main}
   thrown in %s on line %d
diff --git a/ext/opcache/tests/opt/sccp_exception3.phpt b/ext/opcache/tests/opt/sccp_exception3.phpt
new file mode 100644 (file)
index 0000000..e72a19d
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+Exception thrown during SCCP evaluation, strict types variation
+--FILE--
+<?php
+
+declare(strict_types=1);
+var_dump(str_contains("123", 1));
+
+?>
+--EXPECTF--
+Fatal error: Uncaught TypeError: str_contains(): Argument #2 ($needle) must be of type string, int given in %s:%d
+Stack trace:
+#0 %s(%d): str_contains('123', 1)
+#1 {main}
+  thrown in %s on line %d