Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

fix bug with inherited old-style constructors #35

Closed
wants to merge 1 commit into from

2 participants

@tony2001

we need some additional safechecks when redefining/adding these cursed
old-style ctors.

@tony2001 tony2001 fix bug with inherited old-style constructors
we need some additional safechecks when redefining/adding these cursed
old-style ctors
d63c984
@zenovich zenovich referenced this pull request from a commit
@zenovich All ways of adding and removing magic methods and old-style construct…
…ors were reworked and corrected (issue #35).

Magic methods __isset, __unset, __callStatic, and __toString are now supported.
Functions runkit_class_adopt & runkit_class_emancipate now change class-hierarchy (issue #13).
tony2001's patch d63c984 was applied and reworked.
New tests were added.
7f5b7b1
@zenovich zenovich closed this
@tony2001 tony2001 referenced this pull request from a commit in tony2001/runkit
@tony2001 tony2001 Merge git://github.com/zenovich/runkit
* git://github.com/zenovich/runkit:
  Adding and redefining functions and methods, which return references, were fully implemented (#12). New optional argument 'return_ref' of functions runkit_function_add and runkit_function_redefine was introduced. New constant RUNKIT_ACC_RETURN_REFERENCE was introduced for use with functions runkit_method_add and runkit_method_redefine. New tests were added.
  The possible crash on manipulating constants having length less than two characters was eliminated. Functions manipulating constants were corrected to work in PHP5.4, new tests were added.
  All ways of adding and removing magic methods and old-style constructors were reworked and corrected (issue #35). Magic methods __isset, __unset, __callStatic, and __toString are now supported. Functions runkit_class_adopt & runkit_class_emancipate now change class-hierarchy (issue #13). tony2001's patch d63c984 was applied and reworked. New tests were added.
  functions and methods redefining in PHP 5.4 was corrected in all places, new tests were added (#36, #32)
  a fix was added to package.xml
  mad casing of classnames in different versions of PHP
  compilation bug (gcc 4.3+) with definition of internal function was fixed
3c35dda
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 12, 2012
  1. @tony2001

    fix bug with inherited old-style constructors

    tony2001 authored
    we need some additional safechecks when redefining/adding these cursed
    old-style ctors
This page is out of date. Refresh to see the latest.
View
9 php_runkit.h
@@ -335,9 +335,10 @@ struct _php_runkit_sandbox_object {
}
#ifdef ZEND_ENGINE_2
-#define PHP_RUNKIT_ADD_MAGIC_METHOD(ce, method, fe) { \
- if ((strcmp((method), (ce)->name) == 0) || \
- (strcmp((method), "__construct") == 0)) { (ce)->constructor = (fe); (fe)->common.fn_flags = ZEND_ACC_CTOR; } \
+#define PHP_RUNKIT_ADD_MAGIC_METHOD(ce, method, fe, orig_fe) { \
+ if ((strcasecmp((method), (ce)->name) == 0) || \
+ (strcmp((method), "__construct") == 0)) { (ce)->constructor = (fe); (fe)->common.fn_flags = ZEND_ACC_CTOR; } \
+ else if ((ce)->constructor && (ce)->constructor == orig_fe) { (ce)->constructor = (fe); (fe)->common.fn_flags = ZEND_ACC_CTOR; } \
else if (strcmp((method), "__destruct") == 0) { (ce)->destructor = (fe); (fe)->common.fn_flags = ZEND_ACC_DTOR; } \
else if (strcmp((method), "__clone") == 0) { (ce)->clone = (fe); (fe)->common.fn_flags = ZEND_ACC_CLONE; } \
else if (strcmp((method), "__get") == 0) (ce)->__get = (fe); \
@@ -355,7 +356,7 @@ struct _php_runkit_sandbox_object {
#define PHP_RUNKIT_DESTROY_FUNCTION(fe) destroy_zend_function(fe TSRMLS_CC);
#else
#define PHP_RUNKIT_DESTROY_FUNCTION(fe) destroy_zend_function(fe);
-#define PHP_RUNKIT_ADD_MAGIC_METHOD(ce, method, fe)
+#define PHP_RUNKIT_ADD_MAGIC_METHOD(ce, method, fe, orig_fe)
#define PHP_RUNKIT_DEL_MAGIC_METHOD(ce, fe)
#endif /* ZEND_ENGINE_2 */
#endif /* PHP_RUNKIT_MANIPULATION */
View
2  runkit_classes.c
@@ -95,7 +95,7 @@ static int php_runkit_inherit_methods(zend_function *fe, zend_class_entry *ce TS
}
efree(lower_function_name);
- PHP_RUNKIT_ADD_MAGIC_METHOD(ce, fe->common.function_name, fe);
+ PHP_RUNKIT_ADD_MAGIC_METHOD(ce, fe->common.function_name, fe, NULL);
return ZEND_HASH_APPLY_KEEP;
}
View
54 runkit_methods.c
@@ -270,6 +270,8 @@ int php_runkit_update_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce
zend_function *fe = va_arg(args, zend_function*);
char *fname = va_arg(args, char*);
int fname_len = va_arg(args, int);
+ zend_function *orig_fe = va_arg(args, zend_function*);
+ int add_or_update = va_arg(args, int);
zend_function *cfe = NULL;
char *fname_lower;
RUNKIT_UNDER53_TSRMLS_FETCH();
@@ -312,10 +314,29 @@ int php_runkit_update_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce
}
PHP_RUNKIT_FUNCTION_ADD_REF(fe);
- PHP_RUNKIT_ADD_MAGIC_METHOD(ce, fname, fe);
+ PHP_RUNKIT_ADD_MAGIC_METHOD(ce, fname, fe, orig_fe);
/* Process children of this child */
- 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, fe, fname, fname_len);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 7, ancestor_class, ce, fe, fname, fname_len, orig_fe, add_or_update);
+
+ if (add_or_update == HASH_ADD && ce->parent->constructor == fe) {
+ /* special case for old-style Foo::Foo() constructors */
+ zend_function *ctor;
+ char *lc_class_name;
+
+ lc_class_name = estrndup(ce->name, ce->name_length);
+ php_strtolower(lc_class_name, ce->name_length);
+
+ if (zend_hash_find(&ce->function_table, "__constructor", sizeof("__constructor"), (void **)&ctor)==SUCCESS) {
+ /* if the class has it's own ctor, we don't have to do anything at all */
+ } else if (zend_hash_find(&ce->function_table, lc_class_name, ce->name_length + 1, (void **)&ctor)==SUCCESS) {
+ /* --//-- */
+ } else {
+ /* if not, then we have inherit parent class ctor */
+ ce->constructor = ce->parent->constructor;
+ }
+ efree(lc_class_name);
+ }
efree(fname_lower);
@@ -332,6 +353,7 @@ int php_runkit_clean_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce)
zend_class_entry *scope;
char *fname = va_arg(args, char*);
int fname_len = va_arg(args, int);
+ zend_function *orig_cfe = va_arg(args, zend_function *);
zend_function *cfe = NULL;
char *fname_lower;
RUNKIT_UNDER53_TSRMLS_FETCH();
@@ -368,11 +390,11 @@ int php_runkit_clean_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce)
}
/* Process children of this child */
- 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, fname, fname_len);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 5, ancestor_class, ce, fname, fname_len, orig_cfe);
zend_hash_del(&ce->function_table, fname_lower, fname_len + 1);
- PHP_RUNKIT_DEL_MAGIC_METHOD(ce, cfe);
+ PHP_RUNKIT_DEL_MAGIC_METHOD(ce, orig_cfe);
efree(fname_lower);
return ZEND_HASH_APPLY_KEEP;
@@ -447,7 +469,7 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
const char *classname, *methodname, *arguments, *phpcode;
int classname_len, methodname_len, arguments_len, phpcode_len;
zend_class_entry *ce, *ancestor_class = NULL;
- zend_function func, *fe;
+ zend_function func, *fe, *orig_fe = NULL;
char *methodname_lower;
long argc = ZEND_NUM_ARGS();
#ifdef ZEND_ENGINE_2
@@ -489,6 +511,7 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
RETURN_FALSE;
}
ancestor_class = php_runkit_locate_scope(ce, fe, methodname, methodname_len);
+ orig_fe = fe;
if (php_runkit_check_call_stack(&fe->op_array TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot redefine a method while that method is active.");
@@ -534,11 +557,7 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
}
#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);
-
-
- if (zend_hash_add_or_update(&ce->function_table, methodname_lower, methodname_len + 1, &func, sizeof(zend_op_array), NULL, add_or_update) == FAILURE) {
+ if (zend_hash_add_or_update(&ce->function_table, methodname_lower, methodname_len + 1, &func, sizeof(zend_function), NULL, add_or_update) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add method to class");
efree(methodname_lower);
RETURN_FALSE;
@@ -557,7 +576,10 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
RETURN_FALSE;
}
- PHP_RUNKIT_ADD_MAGIC_METHOD(ce, methodname, fe);
+ PHP_RUNKIT_ADD_MAGIC_METHOD(ce, methodname, fe, orig_fe);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 7,
+ ancestor_class, ce, fe, methodname, methodname_len, orig_fe, add_or_update);
+
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);
@@ -611,9 +633,9 @@ static int php_runkit_method_copy(const char *dclass, int dclass_len, const char
return FAILURE;
}
- PHP_RUNKIT_ADD_MAGIC_METHOD(dce, dfunc, dfeInHashTable);
+ PHP_RUNKIT_ADD_MAGIC_METHOD(dce, dfunc, dfeInHashTable, NULL);
- 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);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 7, dce, dce, &dfe, dfunc_lower, dfunc_len, NULL, HASH_ADD);
efree(dfunc_lower);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
@@ -678,7 +700,7 @@ PHP_FUNCTION(runkit_method_remove)
}
php_strtolower(methodname_lower, methodname_len);
- 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);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 5, ancestor_class, ce, methodname, methodname_len, fe);
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");
@@ -777,9 +799,9 @@ PHP_FUNCTION(runkit_method_rename)
efree(newname_lower);
efree(methodname_lower);
- PHP_RUNKIT_ADD_MAGIC_METHOD(ce, newname, fe);
+ PHP_RUNKIT_ADD_MAGIC_METHOD(ce, newname, fe, NULL);
- 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);
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_update_children_methods, 7, ce, ce, fe, newname, newname_len, NULL, HASH_UPDATE);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
View
19 tests/runkit_add_old_style_ctor.phpt
@@ -0,0 +1,19 @@
+--TEST--
+add old-style parent ctor
+--FILE--
+<?php
+
+class Test {
+}
+
+class FOO_test extends test {
+}
+
+runkit_method_add("test", "test", "", "var_dump('new constructor');");
+$a = new foo_test;
+
+echo "==DONE==\n";
+?>
+--EXPECT--
+string(15) "new constructor"
+==DONE==
View
22 tests/runkit_add_old_style_ctor1.phpt
@@ -0,0 +1,22 @@
+--TEST--
+add old-style parent ctor (existing ctor)
+--FILE--
+<?php
+
+class Test {
+}
+
+class FOO_test extends test {
+ function foo_test() {
+ var_dump("foo_test ctor");
+ }
+}
+
+runkit_method_add("test", "test", "", "var_dump('new constructor');");
+$a = new foo_test;
+
+echo "==DONE==\n";
+?>
+--EXPECT--
+string(13) "foo_test ctor"
+==DONE==
View
22 tests/runkit_redefine_old_style_ctor.phpt
@@ -0,0 +1,22 @@
+--TEST--
+redefine old-style parent ctor
+--FILE--
+<?php
+
+class Test {
+ function test() {
+ var_dump("original constructor");
+ }
+}
+
+class FOO_test extends test {
+}
+
+runkit_method_redefine("test", "test", "", "var_dump('new constructor');");
+$a = new foo_test;
+
+echo "==DONE==\n";
+?>
+--EXPECT--
+string(15) "new constructor"
+==DONE==
Something went wrong with that request. Please try again.