Fixed mem leaks, added tests and ternary operator

This commit is contained in:
Bob Weinand 2013-10-31 18:21:37 +01:00
parent 2361745806
commit 466c5dd1fe
12 changed files with 210 additions and 30 deletions

View File

@ -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

View File

@ -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"

View File

@ -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)

View File

@ -0,0 +1,11 @@
--TEST--
Dynamic Constant Expressions
--FILE--
<?php
const FOO = 1;
const BAR = FOO | 2;
echo BAR;
?>
--EXPECTF--
3

View File

@ -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)

View File

@ -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)
}

View File

@ -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]);
}

View File

@ -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);

View File

@ -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;

View File

@ -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; }

View File

@ -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

View File

@ -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) \