Skip to content

Commit

Permalink
Bug 57649 (https://bugs.php.net/bug.php?id=57649) has been fixed with…
Browse files Browse the repository at this point in the history
…out apathy ;)

New tests from github.com/php/pecl-php-runkit have been added (thanks to sgolemon).
Some memory allocation problems have been resolved.
  • Loading branch information
zenovich committed May 18, 2013
1 parent 07179d7 commit c592699
Show file tree
Hide file tree
Showing 17 changed files with 407 additions and 42 deletions.
14 changes: 14 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Execute code in restricted environment (sandboxing).
* A test for correctness of runkit.superglobals feature was added
* Tests for correctness of inheritance of properties were added
* Tests for correctness of adding static properties were added
* Bug 57649 (https://bugs.php.net/bug.php?id=57649) has been fixed without apathy ;)
Thanks to Sara Golemon for tests.

Build system improvements:
* Declarations after statement were restricted during compiling
Expand Down Expand Up @@ -228,6 +230,7 @@ Execute code in restricted environment (sandboxing).
<file name="runkit_static_property_add.phpt" role="test" />
<file name="runkit_static_property_add_existing.phpt" role="test" />
<file name="runkit_static_property_add_to_subclasses.phpt" role="test" />
<file name="runkit_static_vars.phpt" role="test" />
<file name="runkit_superglobals.phpt" role="test" />
<file name="runkit_default_property_add_and_remove_for_class_with_dynamic_properties_overriding_in_objects.phpt" role="test" />
<file name="runkit_default_property_add_overriding_objects.phpt" role="test" />
Expand All @@ -246,6 +249,17 @@ Execute code in restricted environment (sandboxing).
<file name="runkit_import_class_property_and_inheritance_overriding_objects.phpt" role="test" />
<file name="runkit_import_function_overriding_objects4.inc" role="test" />
<file name="runkit_import_function_overriding_objects4.phpt" role="test" />
<file name="bug56662.phpt" role="test" />
<file name="bug56976.phpt" role="test" />
<file name="bug57249.inc" role="test" />
<file name="bug57249.phpt" role="test" />
<file name="bug57649.inc" role="test" />
<file name="bug57649.phpt" role="test" />
<file name="bug57658.phpt" role="test" />
<file name="runkit_import_methods1.inc" role="test" />
<file name="runkit_import_methods2.inc" role="test" />
<file name="runkit_import_methods.phpt" role="test" />
<file name="runkit_method_rename_002.phpt" role="test" />
</dir> <!-- //tests -->
<file name="config.m4" role="src" />
<file name="config.w32" role="src" />
Expand Down
3 changes: 3 additions & 0 deletions php_runkit.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ zend_class_entry *_php_runkit_locate_scope(zend_class_entry *ce, zend_function *
/* runkit_constants.c */
int php_runkit_update_children_consts(RUNKIT_53_TSRMLS_ARG(void *pDest), int num_args, va_list args, zend_hash_key *hash_key);

/* runkit_classes.c */
int php_runkit_class_copy(zend_class_entry *src, const char *classname, int classname_len TSRMLS_DC);

/* runkit_props.c */
int php_runkit_update_children_def_props(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce), int num_args, va_list args, zend_hash_key *hash_key);
int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int propname_len, zval *copyval, long visibility, const char *doc_comment, int doc_comment_len, zend_class_entry *definer_class, int override, int override_in_objects TSRMLS_DC);
Expand Down
63 changes: 63 additions & 0 deletions runkit_classes.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,69 @@ static int php_runkit_inherit_methods(zend_function *fe, zend_class_entry *ce TS
}
/* }}} */

/* {{{ php_runkit_class_copy
Copy class into class table */
int php_runkit_class_copy(zend_class_entry *src, const char *classname, int classname_len TSRMLS_DC)
{
zend_class_entry *new_class_entry;

#ifndef ZEND_ENGINE_2
new_class_entry = emalloc(sizeof(zend_class_entry));

new_class_entry->type = ZEND_USER_CLASS;
new_class_entry->name = estrdup(classname);
new_class_entry->name_length = classname_len;
new_class_entry->refcount = (int *) emalloc(sizeof(int));
*(new_class_entry->refcount) = 1;
new_class_entry->constants_updated = 0;

zend_hash_init(&new_class_entry->function_table, 10, NULL, ZEND_FUNCTION_DTOR, 0);
zend_hash_init(&new_class_entry->default_properties, 10, NULL, ZVAL_PTR_DTOR, 0);

new_class_entry->handle_function_call = src->handle_function_call;
new_class_entry->handle_property_set = src->handle_property_set;
new_class_entry->handle_property_get = src->handle_property_get;

new_class_entry->parent = src->parent;

zend_hash_update(CG(class_table), new_class_entry->name, classname_len, new_class_entry, sizeof(zend_class_entry), (void **) &new_class_entry);
#else
char *lcname;

new_class_entry = emalloc(sizeof(zend_class_entry));
new_class_entry->type = ZEND_USER_CLASS;
new_class_entry->name = estrndup(classname, classname_len);
new_class_entry->name_length = classname_len;

zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
new_class_entry->info.user.filename = src->info.user.filename;
new_class_entry->info.user.line_start = src->info.user.line_start;
new_class_entry->info.user.doc_comment = src->info.user.doc_comment;
new_class_entry->info.user.doc_comment_len = src->info.user.doc_comment_len;
new_class_entry->info.user.line_end = src->info.user.line_end;
new_class_entry->num_traits = src->num_traits;
new_class_entry->traits = src->traits;
#else
new_class_entry->filename = src->filename;
new_class_entry->line_start = src->line_start;
new_class_entry->doc_comment = src->doc_comment;
new_class_entry->doc_comment_len = src->doc_comment_len;
new_class_entry->line_end = src->line_end;
#endif
new_class_entry->ce_flags = src->ce_flags;

lcname = zend_str_tolower_dup(classname, classname_len);
zend_hash_update(EG(class_table), lcname, classname_len + 1, &new_class_entry, sizeof(zend_class_entry *), NULL);
efree(lcname);


new_class_entry->num_interfaces = src->num_interfaces;
#endif
return SUCCESS;
}
/* }}} */

/* {{{ proto bool runkit_class_adopt(string classname, string parentname)
Convert a base class to an inherited class, add ancestral methods when appropriate */
PHP_FUNCTION(runkit_class_adopt)
Expand Down
91 changes: 52 additions & 39 deletions runkit_import.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ static int php_runkit_import_classes(HashTable *class_table, long flags
uint key_len;
int type;
ulong idx;
char *lcname;
zend_class_entry *dce;

zend_hash_get_current_data_ex(class_table, (void*)&ce, &pos);
#ifdef ZEND_ENGINE_2
Expand All @@ -440,57 +442,68 @@ static int php_runkit_import_classes(HashTable *class_table, long flags
return FAILURE;
}

if (((type = zend_hash_get_current_key_ex(EG(class_table), &key, &key_len, &idx, 0, &pos)) != HASH_KEY_NON_EXISTANT) &&
ce && ce->type == ZEND_USER_CLASS) {
zend_class_entry *dce;
if (ce->type != ZEND_USER_CLASS) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot import internal class!");
return FAILURE;
}

if (php_runkit_fetch_class(ce->name, ce->name_length, &dce TSRMLS_CC) == FAILURE) {
/* Oddly non-existant target class or error retreiving it... Or it's an internal class... */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot redeclare class %s", ce->name);
continue;
}
type = zend_hash_get_current_key_ex(class_table, &key, &key_len, &idx, 0, &pos);

lcname = estrndup(ce->name, ce->name_length);
if (lcname == NULL) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Not enough memory");
return FAILURE;
}
php_strtolower(lcname, ce->name_length);

if (!zend_hash_exists(EG(class_table), lcname, ce->name_length + 1)) {
php_runkit_class_copy(ce, ce->name, ce->name_length TSRMLS_CC);
}
efree(lcname);

if (php_runkit_fetch_class(ce->name, ce->name_length, &dce TSRMLS_CC) == FAILURE) {
/* Oddly non-existant target class or error retreiving it... Or it's an internal class... */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot redeclare class %s", ce->name);
continue;
}

#ifdef ZEND_ENGINE_2
if (flags & PHP_RUNKIT_IMPORT_CLASS_CONSTS) {
php_runkit_import_class_consts(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) TSRMLS_CC);
}
if (flags & PHP_RUNKIT_IMPORT_CLASS_STATIC_PROPS) {
php_runkit_import_class_static_props(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) != 0,
(flags & PHP_RUNKIT_OVERRIDE_OBJECTS) != 0
TSRMLS_CC);
}
if (flags & PHP_RUNKIT_IMPORT_CLASS_CONSTS) {
php_runkit_import_class_consts(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) TSRMLS_CC);
}
if (flags & PHP_RUNKIT_IMPORT_CLASS_STATIC_PROPS) {
php_runkit_import_class_static_props(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) != 0,
(flags & PHP_RUNKIT_OVERRIDE_OBJECTS) != 0
TSRMLS_CC);
}
#endif

if (flags & PHP_RUNKIT_IMPORT_CLASS_PROPS) {
php_runkit_import_class_props(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) != 0,
(flags & PHP_RUNKIT_OVERRIDE_OBJECTS) != 0
TSRMLS_CC);
}
if (flags & PHP_RUNKIT_IMPORT_CLASS_PROPS) {
php_runkit_import_class_props(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE) != 0,
(flags & PHP_RUNKIT_OVERRIDE_OBJECTS) != 0
TSRMLS_CC);
}

if (flags & PHP_RUNKIT_IMPORT_CLASS_METHODS) {
php_runkit_import_class_methods(dce, ce, (flags & PHP_RUNKIT_IMPORT_OVERRIDE)
if (flags & PHP_RUNKIT_IMPORT_CLASS_METHODS) {
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
, clear_cache
#endif
TSRMLS_CC);
}
TSRMLS_CC);
}

zend_hash_move_forward_ex(class_table, &pos);
zend_hash_move_forward_ex(class_table, &pos);

if (type == HASH_KEY_IS_STRING) {
if (zend_hash_del(class_table, key, key_len) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove temporary version of class %s", ce->name);
continue;
}
} else {
if (zend_hash_index_del(class_table, idx) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove temporary version of class %s", ce->name);
continue;
}
if (type == HASH_KEY_IS_STRING) {
if (zend_hash_del(class_table, key, key_len) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove temporary version of class %s", ce->name);
continue;
}
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not find class definition in class table");
return FAILURE;
if (zend_hash_index_del(class_table, idx) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove temporary version of class %s", ce->name);
continue;
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions runkit_methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,7 @@ PHP_FUNCTION(runkit_method_rename)
#endif

func = *fe;
PHP_RUNKIT_FUNCTION_ADD_REF(&func);
efree((void*) func.common.function_name);
func.common.function_name = estrndup(newname, newname_len + 1);
php_runkit_function_copy_ctor(&func, newname, newname_len TSRMLS_CC);

if (zend_hash_add(&ce->function_table, newname_lower, newname_len + 1, &func, sizeof(zend_function), NULL) == FAILURE) {
efree(newname_lower);
Expand Down
30 changes: 30 additions & 0 deletions tests/bug56662.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Bug#56662 - Wrong access level with RUNKIT_ACC_PUBLIC
--SKIPIF--
<?php if(!extension_loaded("runkit")) print "skip";
if(version_compare(PHP_VERSION, '5.0.0', '<')) print "skip";
?>
--FILE--
<?php
class A {}
runkit_method_add ('A', 'x', '', '', RUNKIT_ACC_PUBLIC);
Reflection::export(new ReflectionMethod('A', 'x'));

class B extends A { public function x() {} }
Reflection::export(new ReflectionMethod('B', 'x'));

eval("class C extends A { public function x() {} }");
Reflection::export(new ReflectionMethod('C', 'x'));

--EXPECTF--
Method [ <user%S> public method x ] {
@@ %s/tests/bug56662.php(3) : runkit runtime-created function 1 - 1
}

Method [ <user, overwrites A%S> public method x ] {
@@ %s/tests/bug56662.php 6 - 6
}

Method [ <user, overwrites A, prototype A> public method x ] {
@@ %s/tests/bug56662.php(9) : eval()'d code 1 - 1
}
32 changes: 32 additions & 0 deletions tests/bug56976.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Bug#56976 - Failure adding __call method
--SKIPIF--
<?php if(!extension_loaded("runkit")) print "skip";
if(version_compare(PHP_VERSION, '5.0.0', '<')) print "skip";
?>
--FILE--
<?php
class ParentClass
{
public function foo()
{
echo "ParentClass::foo\n";
}
}

class ChildClass extends ParentClass { }

var_dump(runkit_method_add('ParentClass', '__call', '$method, $args',
'echo "In ParentClass::__call()\n";' .
'call_user_func_array(array($this, "prefix_{$method}"), $args);'));

var_dump(runkit_method_rename('ChildClass', 'foo', 'prefix_foo'));

$o = new ChildClass;
$o->foo();

--EXPECT--
bool(true)
bool(true)
In ParentClass::__call()
ParentClass::foo
7 changes: 7 additions & 0 deletions tests/bug57249.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php
class cBuggyClass {
public function mBuggyMethod() {
static $ls_a_iCache;
echo 'mBuggyMethod();'.PHP_EOL;
}
}
16 changes: 16 additions & 0 deletions tests/bug57249.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Bug#57249 - Sutdown bug with runkit_import on a function-static variable
--SKIPIF--
<?php if(!extension_loaded("runkit")) print "skip";
if(version_compare(PHP_VERSION, '5.0.0', '<')) print "skip";
?>
--FILE--
<?php
runkit_import('bug57249.inc', RUNKIT_IMPORT_CLASS_METHODS);
$g_oBuggyObject = new cBuggyClass();
$g_oBuggyObject->mBuggyMethod();

class cBuggyClass { }

--EXPECT--
mBuggyMethod();
8 changes: 8 additions & 0 deletions tests/bug57649.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
class a {
public function foo() {
echo "foo()\n";
}
}

class c { }
26 changes: 26 additions & 0 deletions tests/bug57649.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Bug#57649 - runkit_import() - methods not added - multiple classes in one file
--SKIPIF--
<?php if(!extension_loaded("runkit")) print "skip";
if(version_compare(PHP_VERSION, '5.0.0', '<')) print "skip";
?>
--FILE--
<?php
class b {
public function foobar() {
echo "foobar()\n";
}
}

class a extends b { }

runkit_import( dirname(__FILE__) . "/bug57649.inc" );

$a = new a();
$a->foobar();
$a->foo();
var_dump(class_exists('c'));
--EXPECT--
foobar()
foo()
bool(true)
16 changes: 16 additions & 0 deletions tests/bug57658.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Bug#57658 - runkit_class_adopt fails on method names with capitals
--SKIPIF--
<?php if(!extension_loaded("runkit")) print "skip"; ?>
--FILE--
<?php
if (version_compare(phpversion(), "5.0.0") >= 0) {
error_reporting(E_ALL & ~E_STRICT);
}

class A { function aB() { print "a";} function aC() { echo "d"; } }
class B { function aB() { print "b";} }
runkit_class_adopt("B", "A");
B::aC();
--EXPECT--
d
Loading

0 comments on commit c592699

Please sign in to comment.