Commit:    466c5dd1fe194ab3d1634695e2dc96240f951f50
Author:    Bob Weinand <bobw...@hotmail.com>         Thu, 31 Oct 2013 18:21:37 
+0100
Parents:   2361745806553db9099542d9237ade00dcee799b
Branches:  PHP-5.6

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=466c5dd1fe194ab3d1634695e2dc96240f951f50

Log:
Fixed mem leaks, added tests and ternary operator

Changed paths:
  A  Zend/tests/class_properties_dynamic.phpt
  A  Zend/tests/class_properties_static.phpt
  A  Zend/tests/constant_expressions.phpt
  A  Zend/tests/constant_expressions_dynamic.phpt
  A  Zend/tests/function_arguments_003.phpt
  A  Zend/tests/static_variable.phpt
  M  Zend/zend_ast.c
  M  Zend/zend_ast.h
  M  Zend/zend_execute_API.c
  M  Zend/zend_language_parser.y
  M  Zend/zend_operators.c
  M  Zend/zend_operators.h

diff --git a/Zend/tests/class_properties_dynamic.phpt 
b/Zend/tests/class_properties_dynamic.phpt
new file mode 100644
index 0000000..8a1fc6f
--- /dev/null
+++ b/Zend/tests/class_properties_dynamic.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Class Property Expressions
+--FILE--
+<?php
+class Foo {
+       const BAR = 1 << 0;
+       const BAZ = 1 << 1;
+       public $bar = self::BAR | self::BAZ;
+}
+echo (new Foo)->bar;
+?>
+--EXPECTF--
+3
diff --git a/Zend/tests/class_properties_static.phpt 
b/Zend/tests/class_properties_static.phpt
new file mode 100644
index 0000000..9a56466
--- /dev/null
+++ b/Zend/tests/class_properties_static.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Static Class Property Expressions
+--FILE--
+<?php
+class Foo {
+       public $b1 = 1 + 1;
+       public $b2 = 1 << 2;
+       public $b3 = "foo " . " bar " . " baz";
+}
+$f = new Foo;
+var_dump(
+       $f->b1,
+       $f->b2,
+       $f->b3
+);
+?>
+--EXPECT--
+int(2)
+int(4)
+string(13) "foo  bar  baz"
diff --git a/Zend/tests/constant_expressions.phpt 
b/Zend/tests/constant_expressions.phpt
new file mode 100644
index 0000000..441b9a6
--- /dev/null
+++ b/Zend/tests/constant_expressions.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Constant Expressions
+--FILE--
+<?php
+const T_1 = 1 << 1;
+const T_2 = 1 / 2;
+const T_3 = 1.5 + 1.5;
+const T_4 = "foo" . "bar";
+const T_5 = (1.5 + 1.5) * 2;
+const T_6 = "foo" . 2 . 3 . 4.0;
+const T_7 = __LINE__;
+const T_8 = <<<ENDOFSTRING
+This is a test string
+ENDOFSTRING;
+const T_9 = ~-1;
+const T_10 = (-1?:1) + (0?2:3);
+
+// Test order of operations
+const T_11 = 1 + 2 * 3;
+
+// Test for memory leaks
+const T_12 = "1" + 2 + "3";
+
+var_dump(T_1);
+var_dump(T_2);
+var_dump(T_3);
+var_dump(T_4);
+var_dump(T_5);
+var_dump(T_6);
+var_dump(T_7);
+var_dump(T_8);
+var_dump(T_9);
+var_dump(T_10);
+var_dump(T_11);
+var_dump(T_12);
+?>
+--EXPECT--
+int(2)
+float(0.5)
+float(3)
+string(6) "foobar"
+float(6)
+string(6) "foo234"
+int(8)
+string(21) "This is a test string"
+int(0)
+int(2)
+int(7)
+int(6)
diff --git a/Zend/tests/constant_expressions_dynamic.phpt 
b/Zend/tests/constant_expressions_dynamic.phpt
new file mode 100644
index 0000000..21c9216
--- /dev/null
+++ b/Zend/tests/constant_expressions_dynamic.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Dynamic Constant Expressions
+--FILE--
+<?php
+const FOO = 1;
+const BAR = FOO | 2;
+
+echo BAR;
+?>
+--EXPECTF--
+3
diff --git a/Zend/tests/function_arguments_003.phpt 
b/Zend/tests/function_arguments_003.phpt
new file mode 100644
index 0000000..b882476
--- /dev/null
+++ b/Zend/tests/function_arguments_003.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Function Argument Parsing #003
+--FILE--
+<?php
+const a = 10;
+
+function t1($a = 1 + 1, $b = 1 << 2, $c = "foo" . "bar", $d = a * 10) {
+       var_dump($a, $b, $c, $d);
+}
+
+t1();
+?>
+--EXPECT--
+int(2)
+int(4)
+string(6) "foobar"
+int(100)
diff --git a/Zend/tests/static_variable.phpt b/Zend/tests/static_variable.phpt
new file mode 100644
index 0000000..ea69a8f
--- /dev/null
+++ b/Zend/tests/static_variable.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Static Variable Expressions
+--FILE--
+<?php
+const bar = 2, baz = bar + 1;
+
+function foo() {
+       static $a = 1 + 1;
+       static $b = [bar => 1 + 1, baz * 2 => 1 << 2];
+       static $c = [1 => bar] + [3 => baz];
+       var_dump($a, $b, $c);
+}
+
+foo();
+?>
+--EXPECT--
+int(2)
+array(2) {
+  [2]=>
+  int(2)
+  [6]=>
+  int(4)
+}
+array(2) {
+  [1]=>
+  int(2)
+  [3]=>
+  int(3)
+}
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index 705c4df..7d85e24 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -22,7 +22,8 @@
 #include "zend_execute.h"
 
 #define OP_IS_CONST_THEN(op, do_code) \
-       switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \
+       switch (op?Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK:-1) { \
+               case -1: \
                case IS_CONSTANT: \
                case IS_CONSTANT_ARRAY: \
                case IS_CONSTANT_AST: { \
@@ -31,20 +32,26 @@
        }
 
 #define OP_IS_NOT_CONST_THEN(op, do_code) \
-       switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \
-               case IS_CONSTANT: \
-               case IS_CONSTANT_ARRAY: \
-               case IS_CONSTANT_AST: \
-                       break; \
+       if (op) { \
+               switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \
+                       case IS_CONSTANT: \
+                       case IS_CONSTANT_ARRAY: \
+                       case IS_CONSTANT_AST: \
+                               break; \
 \
-               default: { \
-                       do_code \
+                       default: { \
+                               do_code \
+                       } \
                } \
        }
 
 #define COPY_ZVAL_TO_OP(nr) \
-       Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \
-       *Z_AST_P(result)->ops[nr] = *op##nr;
+       if (op##nr) { \
+               Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \
+               *Z_AST_P(result)->ops[nr] = *op##nr; \
+       } else { \
+               Z_AST_P(result)->ops[nr] = NULL; \
+       }
 
 void zend_ast_add(zval *result, intermediary_ast_function_type func, char 
op_count) {
        zend_ast *ast = emalloc(sizeof(zend_ast));
@@ -58,9 +65,10 @@ void zend_ast_add(zval *result, 
intermediary_ast_function_type func, char op_cou
 
 /* Do operations on constant operators at compile time (AST building time) */
 
-void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0) {
+void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 
TSRMLS_DC) {
        OP_IS_NOT_CONST_THEN(op0,
-               func(result, op0);
+               func(result, op0 TSRMLS_CC);
+               zval_dtor(op0);
                return;
        )
 
@@ -68,9 +76,11 @@ void zend_ast_add_unary(zval *result, unary_ast_func func, 
zval *op0) {
        COPY_ZVAL_TO_OP(0)
 }
 
-void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval 
*op1) {
+void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval 
*op1 TSRMLS_DC) {
        OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1,
-               func(result, op0, op1);
+               func(result, op0, op1 TSRMLS_CC);
+               zval_dtor(op0);
+               zval_dtor(op1);
                return;
        ))
        
@@ -79,9 +89,12 @@ void zend_ast_add_binary(zval *result, binary_ast_func func, 
zval *op0, zval *op
        COPY_ZVAL_TO_OP(1)
 }
 
-void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval 
*op1, zval *op2) {
+void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval 
*op1, zval *op2 TSRMLS_DC) {
        OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1, 
OP_IS_NOT_CONST_THEN(op2, 
-               func(result, op0, op1, op2);
+               func(result, op0, op1, op2 TSRMLS_CC);
+               zval_dtor(op0);
+               zval_dtor(op1);
+               zval_dtor(op2);
                return;
        )))
        
@@ -95,20 +108,22 @@ void zend_ast_evaluate(zval *result, zend_ast *ast 
TSRMLS_DC) {
        int i;
 
        for (i = ast->op_count; i--;) {
-               OP_IS_CONST_THEN(ast->ops[i],
-                       zval_update_constant_ex(&ast->ops[i], (void *)1, NULL 
TSRMLS_CC);
-               )
+               if (ast->ops[i]) {
+                       OP_IS_CONST_THEN(ast->ops[i],
+                               zval_update_constant_ex(&ast->ops[i], (void 
*)1, NULL TSRMLS_CC);
+                       )
+               }
        }
 
        switch (ast->op_count) {
                case 1:
-                       ((unary_ast_func)ast->func)(result, ast->ops[0]);
+                       ((unary_ast_func)ast->func)(result, ast->ops[0] 
TSRMLS_CC);
                        break;
                case 2:
-                       ((binary_ast_func)ast->func)(result, ast->ops[0], 
ast->ops[1]);
+                       ((binary_ast_func)ast->func)(result, ast->ops[0], 
ast->ops[1] TSRMLS_CC);
                        break;
                case 3:
-                       ((ternary_ast_func)ast->func)(result, ast->ops[0], 
ast->ops[1], ast->ops[2]);
+                       ((ternary_ast_func)ast->func)(result, ast->ops[0], 
ast->ops[1], ast->ops[2] TSRMLS_CC);
                        break;
        }
 }
@@ -117,7 +132,7 @@ void zend_ast_destroy(zend_ast *ast TSRMLS_DC) {
        int i;
 
        for (i = ast->op_count; i--;) {
-               if (!Z_DELREF_P(ast->ops[i])) {
+               if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) {
                        zval_dtor(ast->ops[i]);
                        efree(ast->ops[i]);
                }
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h
index 9841c34..218f2c0 100644
--- a/Zend/zend_ast.h
+++ b/Zend/zend_ast.h
@@ -26,9 +26,9 @@ typedef struct _zend_ast zend_ast;
 #include "zend.h"
 
 typedef void(*intermediary_ast_function_type)(zval *, ...);
-typedef int(*unary_ast_func)(zval *result, zval *op0);
-typedef int(*binary_ast_func)(zval *result, zval *op0, zval *op1);
-typedef int(*ternary_ast_func)(zval *result, zval *op0, zval *op1, zval *op2);
+typedef int(*unary_ast_func)(zval *result, zval *op0 TSRMLS_DC);
+typedef int(*binary_ast_func)(zval *result, zval *op0, zval *op1 TSRMLS_DC);
+typedef int(*ternary_ast_func)(zval *result, zval *op0, zval *op1, zval *op2 
TSRMLS_DC);
 
 struct _zend_ast {
        char op_count;
@@ -37,9 +37,9 @@ struct _zend_ast {
        int refcount;
 };
 
-void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0);
-void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval 
*op1);
-void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval 
*op1, zval *op2);
+void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 
TSRMLS_DC);
+void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval 
*op1 TSRMLS_DC);
+void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval 
*op1, zval *op2 TSRMLS_DC);
 
 void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC);
 
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index eabebac..a66cdee 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -599,7 +599,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, 
zend_class_entry *sco
                                        continue;
                                }
                                if (str_index[str_index_len - 2] == 
IS_CONSTANT_AST) {
-                                       zend_ast_evaluate(&const_value, 
*(zend_ast **)str_index);
+                                       zend_ast_evaluate(&const_value, 
*(zend_ast **)str_index TSRMLS_CC);
                                        ZEND_AST_DEL_REF(*(zend_ast 
**)str_index);
                                } else if (!zend_get_constant_ex(str_index, 
str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] 
TSRMLS_CC)) {
                                        char *actual;
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 517ae56..af00f2e 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -982,6 +982,8 @@ static_operation:
        |       static_scalar_value T_SL static_scalar_value { 
zend_ast_add_binary(&$$.u.constant, shift_left_function, &$1.u.constant, 
&$3.u.constant TSRMLS_CC); }
        |       static_scalar_value T_SR static_scalar_value { 
zend_ast_add_binary(&$$.u.constant, shift_right_function, &$1.u.constant, 
&$3.u.constant TSRMLS_CC); }
        |       static_scalar_value '.' static_scalar_value { 
zend_ast_add_binary(&$$.u.constant, concat_function, &$1.u.constant, 
&$3.u.constant TSRMLS_CC); }
+       |       static_scalar_value '?' ':' static_scalar_value { 
zend_ast_add_ternary(&$$.u.constant, ternary_function, &$1.u.constant, NULL, 
&$4.u.constant TSRMLS_CC); }
+       |       static_scalar_value '?' static_scalar_value ':' 
static_scalar_value { zend_ast_add_ternary(&$$.u.constant, ternary_function, 
&$1.u.constant, &$3.u.constant, &$5.u.constant TSRMLS_CC); }
        |       '+' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); 
zend_ast_add_binary(&$$.u.constant, add_function, &$1.u.constant, 
&$2.u.constant TSRMLS_CC); }
        |       '-' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); 
zend_ast_add_binary(&$$.u.constant, sub_function, &$1.u.constant, 
&$2.u.constant TSRMLS_CC); }
        |       '(' static_scalar_value ')' { $$ = $2; }
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index e862929..53a84de 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -2323,6 +2323,28 @@ ZEND_API void zend_locale_sprintf_double(zval *op 
ZEND_FILE_LINE_DC) /* {{{ */
 }
 /* }}} */
 
+#define PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(var) \
+       *result = *var; \
+       if (Z_REFCOUNT_P(var) == 1) { \
+               Z_TYPE_P(var) = IS_NULL; \
+       }
+
+ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval 
*if_not TSRMLS_DC) /* {{{ */
+{
+       if (i_zend_is_true(condition)) {
+               if (then) {
+                       PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(then);
+               } else {
+                       
PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(condition);
+               }
+       } else {
+               PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(if_not);
+       }
+
+       return SUCCESS;
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index ce21af3..79ede57 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -376,6 +376,8 @@ ZEND_API int zend_atoi(const char *str, int str_len);
 ZEND_API long zend_atol(const char *str, int str_len);
 
 ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC);
+
+ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval 
*if_not TSRMLS_DC);
 END_EXTERN_C()
 
 #define convert_to_ex_master(ppzv, lower_type, upper_type)     \
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to