summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2013-10-31 18:21:37 +0100
committerBob Weinand <bobwei9@hotmail.com>2013-10-31 18:21:37 +0100
commit466c5dd1fe194ab3d1634695e2dc96240f951f50 (patch)
tree4e2aaced8f7b16165e815c77025a381a56208db0 /Zend
parent2361745806553db9099542d9237ade00dcee799b (diff)
downloadphp-git-466c5dd1fe194ab3d1634695e2dc96240f951f50.tar.gz
Fixed mem leaks, added tests and ternary operator
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/class_properties_dynamic.phpt13
-rw-r--r--Zend/tests/class_properties_static.phpt20
-rw-r--r--Zend/tests/constant_expressions.phpt49
-rw-r--r--Zend/tests/constant_expressions_dynamic.phpt11
-rw-r--r--Zend/tests/function_arguments_003.phpt17
-rw-r--r--Zend/tests/static_variable.phpt29
-rw-r--r--Zend/zend_ast.c61
-rw-r--r--Zend/zend_ast.h12
-rw-r--r--Zend/zend_execute_API.c2
-rw-r--r--Zend/zend_language_parser.y2
-rw-r--r--Zend/zend_operators.c22
-rw-r--r--Zend/zend_operators.h2
12 files changed, 210 insertions, 30 deletions
diff --git a/Zend/tests/class_properties_dynamic.phpt b/Zend/tests/class_properties_dynamic.phpt
new file mode 100644
index 0000000000..8a1fc6f029
--- /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 0000000000..9a56466340
--- /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 0000000000..441b9a6f2a
--- /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 0000000000..21c9216cc1
--- /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 0000000000..b882476d1d
--- /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 0000000000..ea69a8f86b
--- /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 705c4df465..7d85e24106 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 9841c3463e..218f2c02e0 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 eabebacce4..a66cdeea92 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 517ae56e41..af00f2ef4a 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 e8629291e5..53a84de155 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 ce21af3d2e..79ede57320 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) \