]> granicus.if.org Git - php/commitdiff
Don't propagate into ops that error on non-string
authorNikita Popov <nikic@php.net>
Sat, 7 Nov 2015 10:48:21 +0000 (11:48 +0100)
committerNikita Popov <nikic@php.net>
Sat, 7 Nov 2015 11:04:51 +0000 (12:04 +0100)
To properly support this make update_opN_const fallible -- they
are not always called through replace_with_const.

Zend/tests/varSyntax/static_prop_on_int_expr_class.phpt [new file with mode: 0644]
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/Optimizer/zend_optimizer_internal.h

diff --git a/Zend/tests/varSyntax/static_prop_on_int_expr_class.phpt b/Zend/tests/varSyntax/static_prop_on_int_expr_class.phpt
new file mode 100644 (file)
index 0000000..c7c44d5
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+Static property access on constexpr class evaluating to integer
+--FILE--
+<?php
+((int)1)::$b;
+?>
+--EXPECTF--
+Fatal error: Uncaught Error: Class name must be a valid object or a string in %s:%d
+Stack trace:
+#0 {main}
+  thrown in %s on line %d
index b7e16828668e55d3c85ee47183194619a0fdd2f0..210078e7a9673ccd01f0e6472096587cc6aa0c5e 100644 (file)
@@ -643,13 +643,15 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
                        (opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
                        opline->opcode != ZEND_FREE
                        ) {
-                       zend_op *src = VAR_SOURCE(opline->op1);
+                       znode_op op1 = opline->op1;
+                       zend_op *src = VAR_SOURCE(op1);
                        zval c = ZEND_OP1_LITERAL(src);
-                       VAR_UNSET(opline->op1);
                        zval_copy_ctor(&c);
-                       zend_optimizer_update_op1_const(op_array, opline, &c);
-                       literal_dtor(&ZEND_OP1_LITERAL(src));
-                       MAKE_NOP(src);
+                       if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
+                               VAR_SOURCE(op1) = NULL;
+                               literal_dtor(&ZEND_OP1_LITERAL(src));
+                               MAKE_NOP(src);
+                       }
                }
 
                /* T = QM_ASSIGN(C), F(T) => NOP, F(C) */
@@ -657,13 +659,15 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
                        VAR_SOURCE(opline->op2) &&
                        VAR_SOURCE(opline->op2)->opcode == ZEND_QM_ASSIGN &&
                        ZEND_OP1_TYPE(VAR_SOURCE(opline->op2)) == IS_CONST) {
-                       zend_op *src = VAR_SOURCE(opline->op2);
+                       znode_op op2 = opline->op2;
+                       zend_op *src = VAR_SOURCE(op2);
                        zval c = ZEND_OP1_LITERAL(src);
-                       VAR_UNSET(opline->op2);
                        zval_copy_ctor(&c);
-                       zend_optimizer_update_op2_const(op_array, opline, &c);
-                       literal_dtor(&ZEND_OP1_LITERAL(src));
-                       MAKE_NOP(src);
+                       if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
+                               VAR_SOURCE(op2) = NULL;
+                               literal_dtor(&ZEND_OP1_LITERAL(src));
+                               MAKE_NOP(src);
+                       }
                }
 
                /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
index 153de18e468ff245a821e2dafa4cd05fbc812bbf..9e13b6497e9ce356daf9804c6ce44c71dab922fe 100644 (file)
@@ -132,56 +132,60 @@ static inline void drop_leading_backslash(zval *val) {
        }
 }
 
-void zend_optimizer_update_op1_const(zend_op_array *op_array,
-                                     zend_op       *opline,
-                                     zval          *val)
+int zend_optimizer_update_op1_const(zend_op_array *op_array,
+                                    zend_op       *opline,
+                                    zval          *val)
 {
-       if (opline->opcode == ZEND_FREE) {
-               MAKE_NOP(opline);
-               zval_dtor(val);
-       } else {
-               ZEND_OP1_TYPE(opline) = IS_CONST;
-               if (Z_TYPE_P(val) == IS_STRING) {
-                       switch (opline->opcode) {
-                               case ZEND_INIT_STATIC_METHOD_CALL:
-                               case ZEND_CATCH:
-                               case ZEND_FETCH_CONSTANT:
-                               case ZEND_DEFINED:
-                               case ZEND_NEW:
-                                       drop_leading_backslash(val);
-                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val);
-                                       zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
-                                       Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
-                                       op_array->cache_size += sizeof(void*);
-                                       zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
-                                       break;
-                               default:
-                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val);
-                                       zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
-                                       break;
-                       }
-               } else {
-                       if (opline->opcode == ZEND_CONCAT ||
-                           opline->opcode == ZEND_FAST_CONCAT) {
-                               convert_to_string(val);
+       switch (opline->opcode) {
+               case ZEND_FREE:
+                       MAKE_NOP(opline);
+                       zval_dtor(val);
+                       break;
+               case ZEND_INIT_STATIC_METHOD_CALL:
+               case ZEND_CATCH:
+               case ZEND_FETCH_CONSTANT:
+               case ZEND_DEFINED:
+               case ZEND_NEW:
+                       if (Z_TYPE_P(val) != IS_STRING) {
+                               zval_dtor(val);
+                               return 0;
                        }
+                       ZEND_OP1_TYPE(opline) = IS_CONST;
+                       drop_leading_backslash(val);
                        opline->op1.constant = zend_optimizer_add_literal(op_array, val);
-               }
+                       zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
+                       Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
+                       op_array->cache_size += sizeof(void*);
+                       zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+                       break;
+               case ZEND_CONCAT:
+               case ZEND_FAST_CONCAT:
+                       convert_to_string(val);
+                       /* break missing intentionally */
+               default:
+                       ZEND_OP1_TYPE(opline) = IS_CONST;
+                       opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+                       if (Z_TYPE_P(val) == IS_STRING) {
+                               zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
+                       }
+                       break;
        }
+
+       return 1;
 }
 
-void zend_optimizer_update_op2_const(zend_op_array *op_array,
-                                     zend_op       *opline,
-                                     zval          *val)
+int zend_optimizer_update_op2_const(zend_op_array *op_array,
+                                    zend_op       *opline,
+                                    zval          *val)
 {
-       ZEND_OP2_TYPE(opline) = IS_CONST;
        if (opline->opcode == ZEND_INIT_FCALL) {
+               ZEND_OP2_TYPE(opline) = IS_CONST;
                zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
                opline->op2.constant = zend_optimizer_add_literal(op_array, val);
                zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
                Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
                op_array->cache_size += sizeof(void*);
-               return;
+               return 1;
        }
 
        switch (opline->opcode) {
@@ -206,11 +210,17 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
                case ZEND_ADD_INTERFACE:
                case ZEND_ADD_TRAIT:
                case ZEND_INSTANCEOF:
+                       if (Z_TYPE_P(val) != IS_STRING) {
+                               zval_dtor(val);
+                               return 0;
+                       }
+                       /* break missing intentionally */
                case ZEND_INIT_DYNAMIC_CALL:
                        drop_leading_backslash(val);
                        break;
        }
 
+       ZEND_OP2_TYPE(opline) = IS_CONST;
        opline->op2.constant = zend_optimizer_add_literal(op_array, val);
        if (Z_TYPE_P(val) == IS_STRING) {
                zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
@@ -322,6 +332,8 @@ check_numeric:
                                break;
                }
        }
+
+       return 1;
 }
 
 int zend_optimizer_replace_by_const(zend_op_array *op_array,
@@ -429,8 +441,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                default:
                                        break;
                        }
-                       zend_optimizer_update_op1_const(op_array, opline, val);
-                       break;
+                       return zend_optimizer_update_op1_const(op_array, opline, val);
                }
 
                if (ZEND_OP2_TYPE(opline) == type &&
@@ -442,8 +453,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                default:
                                        break;
                        }
-                       zend_optimizer_update_op2_const(op_array, opline, val);
-                       break;
+                       return zend_optimizer_update_op2_const(op_array, opline, val);
                }
                opline++;
        }
index ca452670d7515c6417a2df58c3afaebbc5cc0768..90df3cfadc140b20bab26279ffd0d2eeab09393e 100644 (file)
@@ -118,12 +118,12 @@ int  zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int
 void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value);
 int  zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value);
 int  zend_optimizer_lookup_cv(zend_op_array *op_array, zend_string* name);
-void zend_optimizer_update_op1_const(zend_op_array *op_array,
-                                     zend_op       *opline,
-                                     zval          *val);
-void zend_optimizer_update_op2_const(zend_op_array *op_array,
-                                     zend_op       *opline,
-                                     zval          *val);
+int zend_optimizer_update_op1_const(zend_op_array *op_array,
+                                    zend_op       *opline,
+                                    zval          *val);
+int zend_optimizer_update_op2_const(zend_op_array *op_array,
+                                    zend_op       *opline,
+                                    zval          *val);
 int  zend_optimizer_replace_by_const(zend_op_array *op_array,
                                      zend_op       *opline,
                                      zend_uchar     type,