Skip to content

Commit

Permalink
functions and methods redefining in PHP 5.4 was corrected in all plac…
Browse files Browse the repository at this point in the history
…es, new tests were added (zenovich#36, zenovich#32)
  • Loading branch information
zenovich committed Sep 15, 2012
1 parent a079457 commit 1a3af5e
Show file tree
Hide file tree
Showing 10 changed files with 379 additions and 80 deletions.
5 changes: 5 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,13 @@ Execute code in restricted environment (sandboxing).
<file name="runkit_function_add.phpt" role="test" />
<file name="runkit_function_copy.phpt" role="test" />
<file name="runkit_function_redefine.phpt" role="test" />
<file name="runkit_function_redefine_from_anonymous.phpt" role="test" />
<file name="runkit_function_remove.phpt" role="test" />
<file name="runkit_function_rename.phpt" role="test" />
<file name="runkit_function_rename_internal.phpt" role="test" />
<file name="runkit_function_rename_redefine_add_remove.phpt" role="test" />
<file name="runkit_functions_redefining_and_cache.inc" role="test" />
<file name="runkit_functions_redefining_and_cache.phpt" role="test" />
<file name="runkit_import_class.inc" role="test" />
<file name="runkit_import_class.phpt" role="test" />
<file name="runkit_import_constant_properties.inc" role="test" />
Expand All @@ -99,6 +102,8 @@ Execute code in restricted environment (sandboxing).
<file name="runkit_method_remove.phpt" role="test" />
<file name="runkit_method_rename.phpt" role="test" />
<file name="runkit_method_rename_inheritance.phpt" role="test" />
<file name="runkit_methods_redefining_and_cache.inc" role="test" />
<file name="runkit_methods_redefining_and_cache.phpt" role="test" />
<file name="runkit_return_value_used.phpt" role="test" />
<file name="runkit_zval_inspect.phpt" role="test" />
<file name="Runkit_Sandbox_.active.phpt" role="test" />
Expand Down
3 changes: 3 additions & 0 deletions php_runkit.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ extern ZEND_DECLARE_MODULE_GLOBALS(runkit);
/* runkit_functions.c */
#define RUNKIT_TEMP_FUNCNAME "__runkit_temporary_function__"
int php_runkit_check_call_stack(zend_op_array *op_array TSRMLS_DC);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
void php_runkit_clear_all_functions_runtime_cache(TSRMLS_D);
#endif
void php_runkit_function_copy_ctor(zend_function *fe, const char *newname, int newname_len TSRMLS_DC);
int php_runkit_generate_lambda_method(const char *arguments, int arguments_len, const char *phpcode, int phpcode_len, zend_function **pfe TSRMLS_DC);
int php_runkit_destroy_misplaced_functions(void *pDest TSRMLS_DC);
Expand Down
73 changes: 73 additions & 0 deletions runkit_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,67 @@ void php_runkit_function_copy_ctor(zend_function *fe, const char *newname, int n
}
/* }}}} */

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
/* {{{ php_runkit_clear_function_runtime_cache */
static int php_runkit_clear_function_runtime_cache(void *pDest TSRMLS_DC)
{
zend_function *f = (zend_function *) pDest;

if (pDest == NULL || f->type != ZEND_USER_FUNCTION ||
f->op_array.last_cache_slot == 0 || f->op_array.run_time_cache == NULL) {
return ZEND_HASH_APPLY_KEEP;
}

memset(f->op_array.run_time_cache, 0, (f->op_array.last_cache_slot) * sizeof(void *));

return ZEND_HASH_APPLY_KEEP;
}
/* }}} */

/* {{{ php_runkit_clear_all_functions_runtime_cache */
void php_runkit_clear_all_functions_runtime_cache(TSRMLS_D)
{
int i, count;
zend_execute_data *ptr;
HashPosition pos;

zend_hash_apply(EG(function_table), php_runkit_clear_function_runtime_cache TSRMLS_CC);

zend_hash_internal_pointer_reset_ex(EG(class_table), &pos);
count = zend_hash_num_elements(EG(class_table));
for (i = 0; i < count; ++i) {
zend_class_entry **curce;
zend_hash_get_current_data_ex(EG(class_table), (void**)&curce, &pos);
zend_hash_apply(&(*curce)->function_table, php_runkit_clear_function_runtime_cache TSRMLS_CC);
zend_hash_move_forward_ex(EG(class_table), &pos);
}

for (ptr = EG(current_execute_data); ptr != NULL; ptr = ptr->prev_execute_data) {
if (ptr->op_array == NULL || ptr->op_array->last_cache_slot == 0 || ptr->op_array->run_time_cache == NULL) {
continue;
}
memset(ptr->op_array->run_time_cache, 0, (ptr->op_array->last_cache_slot) * sizeof(void*));
}

if (!EG(objects_store).object_buckets) {
return;
}

for (i = 1; i < EG(objects_store).top ; i++) {
if (EG(objects_store).object_buckets[i].valid && (!EG(objects_store).object_buckets[i].destructor_called) &&
EG(objects_store).object_buckets[i].bucket.obj.object) {
zend_object *object;
object = (zend_object *) EG(objects_store).object_buckets[i].bucket.obj.object;
if (object->ce == zend_ce_closure) {
zend_closure *cl = (zend_closure *) object;
php_runkit_clear_function_runtime_cache((void*) &cl->func TSRMLS_CC);
}
}
}
}
/* }}} */
#endif

/* {{{ php_runkit_generate_lambda_method
Heavily borrowed from ZEND_FUNCTION(create_function) */
int php_runkit_generate_lambda_method(const char *arguments, int arguments_len, const char *phpcode, int phpcode_len, zend_function **pfe TSRMLS_DC)
Expand Down Expand Up @@ -451,6 +512,10 @@ PHP_FUNCTION(runkit_function_remove)
result = (zend_hash_del(EG(function_table), funcname_lower, funcname_len + 1) == SUCCESS);
efree(funcname_lower);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_BOOL(result);
}
/* }}} */
Expand Down Expand Up @@ -524,6 +589,10 @@ PHP_FUNCTION(runkit_function_rename)
}
efree(dfunc_lower);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_TRUE;
}
/* }}} */
Expand Down Expand Up @@ -578,6 +647,10 @@ PHP_FUNCTION(runkit_function_redefine)
efree(delta_desc);
efree(delta);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_BOOL(retval == SUCCESS);
}
/* }}} */
Expand Down
52 changes: 46 additions & 6 deletions runkit_import.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
#ifdef PHP_RUNKIT_MANIPULATION
/* {{{ php_runkit_import_functions
*/
static int php_runkit_import_functions(HashTable *function_table, long flags TSRMLS_DC)
static int php_runkit_import_functions(HashTable *function_table, long flags
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, zend_bool *clear_cache
#endif
TSRMLS_DC)
{
HashPosition pos;
int i, func_count = zend_hash_num_elements(function_table);
Expand Down Expand Up @@ -69,6 +73,9 @@ static int php_runkit_import_functions(HashTable *function_table, long flags TSR
return FAILURE;
}
}
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
*clear_cache = 1;
#endif
} else {
add_function = 0;
}
Expand All @@ -93,7 +100,11 @@ static int php_runkit_import_functions(HashTable *function_table, long flags TSR

/* {{{ php_runkit_import_class_methods
*/
static int php_runkit_import_class_methods(zend_class_entry *dce, zend_class_entry *ce, int override TSRMLS_DC)
static int php_runkit_import_class_methods(zend_class_entry *dce, zend_class_entry *ce, int override
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, zend_bool *clear_cache
#endif
TSRMLS_DC)
{
HashPosition pos;
zend_function *fe;
Expand Down Expand Up @@ -139,6 +150,10 @@ static int php_runkit_import_class_methods(zend_class_entry *dce, zend_class_ent
continue;
}

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
*clear_cache = 1;
#endif

zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 4, scope, dce, fn, fn_len);
if (zend_hash_del(&dce->function_table, fn, fn_len + 1) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error removing old method in destination class %s::%s", dce->name, fe->common.function_name);
Expand Down Expand Up @@ -409,7 +424,11 @@ static int php_runkit_import_class_props(zend_class_entry *dce, zend_class_entry

/* {{{ php_runkit_import_classes
*/
static int php_runkit_import_classes(HashTable *class_table, long flags TSRMLS_DC)
static int php_runkit_import_classes(HashTable *class_table, long flags
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, zend_bool *clear_cache
#endif
TSRMLS_DC)
{
HashPosition pos;
int i, class_count;
Expand Down Expand Up @@ -459,7 +478,11 @@ static int php_runkit_import_classes(HashTable *class_table, long flags TSRMLS_D
}

if (flags & PHP_RUNKIT_IMPORT_CLASS_METHODS) {
php_runkit_import_class_methods(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) TSRMLS_CC);
php_runkit_import_class_methods(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE)
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, clear_cache
#endif
TSRMLS_CC);
}

zend_hash_move_forward_ex(class_table, &pos);
Expand Down Expand Up @@ -572,6 +595,9 @@ PHP_FUNCTION(runkit_import)
zend_op_array *new_op_array;
zval *filename;
long flags = PHP_RUNKIT_IMPORT_CLASS_METHODS;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
zend_bool clear_cache = 0;
#endif

zend_op_array *(*local_compile_filename)(int type, zval *filename TSRMLS_DC) = compile_filename;

Expand Down Expand Up @@ -630,11 +656,19 @@ PHP_FUNCTION(runkit_import)
efree(new_op_array);

if (flags & PHP_RUNKIT_IMPORT_FUNCTIONS) {
php_runkit_import_functions(tmp_function_table, flags TSRMLS_CC);
php_runkit_import_functions(tmp_function_table, flags
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, &clear_cache
#endif
TSRMLS_CC);
}

if (flags & PHP_RUNKIT_IMPORT_CLASSES) {
php_runkit_import_classes(tmp_class_table, flags TSRMLS_CC);
php_runkit_import_classes(tmp_class_table, flags
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
, &clear_cache
#endif
TSRMLS_CC);
}

zend_hash_destroy(tmp_class_table);
Expand All @@ -644,6 +678,12 @@ PHP_FUNCTION(runkit_import)
zend_hash_destroy(tmp_function_table);
efree(tmp_function_table);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
if (clear_cache) {
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
}
#endif

RETURN_TRUE;
}
/* }}} */
Expand Down
87 changes: 13 additions & 74 deletions runkit_methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,67 +379,6 @@ int php_runkit_clean_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce)
}
/* }}} */

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
/* {{{ php_runkit_clear_function_runtime_cache */
int php_runkit_clear_function_runtime_cache(void *pDest TSRMLS_DC)
{
zend_function *f = (zend_function *) pDest;

if (pDest == NULL || f->type == ZEND_INTERNAL_FUNCTION ||
f->op_array.last_cache_slot == 0 || f->op_array.run_time_cache == NULL) {
return ZEND_HASH_APPLY_KEEP;
}

memset(f->op_array.run_time_cache, 0, (f->op_array.last_cache_slot) * sizeof(void *));

return ZEND_HASH_APPLY_KEEP;
}
/* }}} */

/* {{{ php_runkit_clear_all_functions_runtime_cache */
void php_runkit_clear_all_functions_runtime_cache(TSRMLS_D)
{
int i, count;
zend_execute_data *ptr;
HashPosition pos;

zend_hash_apply(EG(function_table), php_runkit_clear_function_runtime_cache TSRMLS_CC);

zend_hash_internal_pointer_reset_ex(EG(class_table), &pos);
count = zend_hash_num_elements(EG(class_table));
for (i = 0; i < count; ++i) {
zend_class_entry **curce;
zend_hash_get_current_data_ex(EG(class_table), (void**)&curce, &pos);
zend_hash_apply(&(*curce)->function_table, php_runkit_clear_function_runtime_cache TSRMLS_CC);
zend_hash_move_forward_ex(EG(class_table), &pos);
}

for (ptr = EG(current_execute_data); ptr != NULL; ptr = ptr->prev_execute_data) {
if (ptr->op_array == NULL || ptr->op_array->last_cache_slot == 0 || ptr->op_array->run_time_cache == NULL) {
continue;
}
memset(ptr->op_array->run_time_cache, 0, (ptr->op_array->last_cache_slot) * sizeof(void*));
}

if (!EG(objects_store).object_buckets) {
return;
}

for (i = 1; i < EG(objects_store).top ; i++) {
if (EG(objects_store).object_buckets[i].valid && (!EG(objects_store).object_buckets[i].destructor_called) &&
EG(objects_store).object_buckets[i].bucket.obj.object) {
zend_object *object;
object = (zend_object *) EG(objects_store).object_buckets[i].bucket.obj.object;
if (object->ce == zend_ce_closure) {
zend_closure *cl = (zend_closure *) object;
php_runkit_clear_function_runtime_cache((void*) &cl->func TSRMLS_CC);
}
}
}
}
/* }}} */
#endif

/* {{{ php_runkit_method_add_or_update
*/
static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int add_or_update)
Expand Down Expand Up @@ -534,6 +473,10 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
}
#endif

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 5,
ancestor_class, ce, &func, methodname, methodname_len);

Expand All @@ -559,9 +502,6 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad

PHP_RUNKIT_ADD_MAGIC_METHOD(ce, methodname, fe);
efree(methodname_lower);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_TRUE;
}
Expand Down Expand Up @@ -616,9 +556,6 @@ static int php_runkit_method_copy(const char *dclass, int dclass_len, const char
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 5, dce, dce, &dfe, dfunc_lower, dfunc_len);

efree(dfunc_lower);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif
return SUCCESS;
}
/* }}} */
Expand Down Expand Up @@ -680,6 +617,10 @@ PHP_FUNCTION(runkit_method_remove)

zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 4, ancestor_class, ce, methodname, methodname_len);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

if (zend_hash_del(&ce->function_table, methodname_lower, methodname_len + 1) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove method from class");
efree(methodname_lower);
Expand All @@ -688,9 +629,7 @@ PHP_FUNCTION(runkit_method_remove)

efree(methodname_lower);
PHP_RUNKIT_DEL_MAGIC_METHOD(ce, fe);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_TRUE;
}
/* }}} */
Expand Down Expand Up @@ -746,6 +685,10 @@ PHP_FUNCTION(runkit_method_rename)
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 4,
ancestor_class, ce, methodname_lower, methodname_len);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

func = *fe;
PHP_RUNKIT_FUNCTION_ADD_REF(&func);
efree((void *) func.common.function_name);
Expand Down Expand Up @@ -781,10 +724,6 @@ PHP_FUNCTION(runkit_method_rename)

zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 5, ce, ce, fe, newname, newname_len);

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif

RETURN_TRUE;
}
/* }}} */
Expand Down
Loading

0 comments on commit 1a3af5e

Please sign in to comment.