From 22f066e708e95debf48065563671d78619807651 Mon Sep 17 00:00:00 2001 From: Andi Gutmans Date: Thu, 9 Sep 1999 14:15:17 +0000 Subject: [PATCH] - Add foreach() freeing code. - Fix switch() freeing code to only free current function's switch expressions. - I have a feeling break expr; in a switch where expr > 1 leaks because it won't free all of the expressions. Fix is probably not trivial. --- Zend/zend_compile.c | 55 +++++++++++++++++++++++++++++++++++++++++---- Zend/zend_globals.h | 1 + Zend/zend_stack.c | 20 ++++++++++++----- Zend/zend_stack.h | 4 ++-- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cfe80872cba..afd77b220a8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -82,6 +82,7 @@ void init_compiler(CLS_D ELS_DC) zend_stack_init(&CG(bp_stack)); zend_stack_init(&CG(function_call_stack)); zend_stack_init(&CG(switch_cond_stack)); + zend_stack_init(&CG(foreach_copy_stack)); zend_stack_init(&CG(object_stack)); CG(active_class_entry) = NULL; zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0); @@ -102,6 +103,7 @@ void shutdown_compiler(CLS_D) zend_stack_destroy(&CG(bp_stack)); zend_stack_destroy(&CG(function_call_stack)); zend_stack_destroy(&CG(switch_cond_stack)); + zend_stack_destroy(&CG(foreach_copy_stack)); zend_stack_destroy(&CG(object_stack)); zend_llist_destroy(&CG(filenames_list)); zend_hash_apply(CG(function_table), (int (*)(void *)) is_not_internal_function); @@ -667,6 +669,19 @@ void do_begin_function_declaration(znode *function_token, znode *function_name, SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); } + + { + /* Push a seperator to the switch and foreach stacks */ + zend_switch_entry switch_entry; + + switch_entry.cond.op_type = IS_UNUSED; + switch_entry.default_case = 0; + switch_entry.control_var = 0; + + zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry)); + + zend_stack_push(&CG(foreach_copy_stack), (void *) &switch_entry.cond, sizeof(znode)); + } } @@ -674,6 +689,10 @@ void do_end_function_declaration(znode *function_token CLS_DC) { pass_two(CG(active_op_array)); CG(active_op_array) = function_token->u.op_array; + + /* Pop the switch and foreach seperators */ + zend_stack_del_top(&CG(switch_cond_stack)); + zend_stack_del_top(&CG(foreach_copy_stack)); } @@ -856,24 +875,48 @@ void do_pass_param(znode *param, int op, int offset CLS_DC) } -static void generate_free_switch_expr(zend_switch_entry *switch_entry CLS_DC) +static int generate_free_switch_expr(zend_switch_entry *switch_entry CLS_DC) { - zend_op *opline = get_next_op(CG(active_op_array) CLS_CC); + zend_op *opline; + + if (switch_entry->cond.op_type == IS_UNUSED) { + return 1; + } + + opline = get_next_op(CG(active_op_array) CLS_CC); opline->opcode = ZEND_SWITCH_FREE; opline->op1 = switch_entry->cond; SET_UNUSED(opline->op2); + return 0; } +static int generate_free_foreach_copy(znode *foreach_copy CLS_DC) +{ + zend_op *opline; + + if (foreach_copy->op_type == IS_UNUSED) { + return 1; + } + + opline = get_next_op(CG(active_op_array) CLS_CC); + + opline->opcode = ZEND_FREE; + opline->op1 = *foreach_copy; + SET_UNUSED(opline->op2); + return 0; +} void do_return(znode *expr CLS_DC) { zend_op *opline; #ifdef ZTS - zend_stack_apply_with_argument(&CG(switch_cond_stack), (void (*)(void *element, void *)) generate_free_switch_expr, ZEND_STACK_APPLY_TOPDOWN CLS_CC); + zend_stack_apply_with_argument(&CG(switch_cond_stack), (int (*)(void *element, void *)) generate_free_switch_expr, ZEND_STACK_APPLY_TOPDOWN CLS_CC); + zend_stack_apply_with_argument(&CG(foreach_copy_stack), (int (*)(void *element, void *)) generate_free_foreach_copy, ZEND_STACK_APPLY_TOPDOWN CLS_CC); #else - zend_stack_apply(&CG(switch_cond_stack), (void (*)(void *element)) generate_free_switch_expr, ZEND_STACK_APPLY_TOPDOWN); + zend_stack_apply(&CG(switch_cond_stack), (int (*)(void *element)) generate_free_switch_expr, ZEND_STACK_APPLY_TOPDOWN); + zend_stack_apply(&CG(foreach_copy_stack), (int (*)(void *element)) generate_free_foreach_copy, ZEND_STACK_APPLY_TOPDOWN); #endif opline = get_next_op(CG(active_op_array) CLS_CC); @@ -1808,6 +1851,8 @@ void do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_t SET_UNUSED(opline->op2); *open_brackets_token = opline->result; + zend_stack_push(&CG(foreach_copy_stack), (void *) &opline->result, sizeof(znode)); + /* save the location of the beginning of the loop (array fetching) */ foreach_token->u.opline_num = get_next_op_number(CG(active_op_array)); @@ -1887,6 +1932,8 @@ void do_foreach_end(znode *foreach_token, znode *open_brackets_token CLS_DC) do_free(open_brackets_token CLS_CC); + zend_stack_del_top(&CG(foreach_copy_stack)); + DEC_BPC(CG(active_op_array)); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index a87c9121631..5e9d1f4d81f 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -58,6 +58,7 @@ END_EXTERN_C() struct _zend_compiler_globals { zend_stack bp_stack; zend_stack switch_cond_stack; + zend_stack foreach_copy_stack; zend_stack object_stack; zend_class_entry class_entry, *active_class_entry; diff --git a/Zend/zend_stack.c b/Zend/zend_stack.c index 0f3b0f6aac6..011e8519c9b 100644 --- a/Zend/zend_stack.c +++ b/Zend/zend_stack.c @@ -118,38 +118,46 @@ ZEND_API int zend_stack_count(zend_stack *stack) } -ZEND_API void zend_stack_apply(zend_stack *stack, void (*apply_function)(void *element), int type) +ZEND_API void zend_stack_apply(zend_stack *stack, int (*apply_function)(void *element), int type) { int i; switch (type) { case ZEND_STACK_APPLY_TOPDOWN: for (i=stack->top-1; i>=0; i--) { - apply_function(stack->elements[i]); + if (apply_function(stack->elements[i])) { + break; + } } break; case ZEND_STACK_APPLY_BOTTOMUP: for (i=0; itop; i++) { - apply_function(stack->elements[i]); + if (apply_function(stack->elements[i])) { + break; + } } break; } } -ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, void (*apply_function)(void *element, void *arg), int type, void *arg) +ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, int (*apply_function)(void *element, void *arg), int type, void *arg) { int i; switch (type) { case ZEND_STACK_APPLY_TOPDOWN: for (i=stack->top-1; i>=0; i--) { - apply_function(stack->elements[i], arg); + if (apply_function(stack->elements[i], arg)) { + break; + } } break; case ZEND_STACK_APPLY_BOTTOMUP: for (i=0; itop; i++) { - apply_function(stack->elements[i], arg); + if (apply_function(stack->elements[i], arg)) { + break; + } } break; } diff --git a/Zend/zend_stack.h b/Zend/zend_stack.h index 5e084fd74f3..053d44632d5 100644 --- a/Zend/zend_stack.h +++ b/Zend/zend_stack.h @@ -38,8 +38,8 @@ ZEND_API int zend_stack_is_empty(zend_stack *stack); ZEND_API int zend_stack_destroy(zend_stack *stack); ZEND_API void **zend_stack_base(zend_stack *stack); ZEND_API int zend_stack_count(zend_stack *stack); -ZEND_API void zend_stack_apply(zend_stack *stack, void (*apply_function)(void *element), int type); -ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, void (*apply_function)(void *element, void *arg), int type, void *arg); +ZEND_API void zend_stack_apply(zend_stack *stack, int (*apply_function)(void *element), int type); +ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, int (*apply_function)(void *element, void *arg), int type, void *arg); #define ZEND_STACK_APPLY_TOPDOWN 1 #define ZEND_STACK_APPLY_BOTTOMUP 2