Patch Fix for Scripting Engine problem Bug #45002
Patch version 2011-05-19 10:01 UTC
Return to Bug #45002 |
Download this patch
Patch Revisions:
Developer: allesbesser@gmail.com
Index: zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.293.2.11.2.9.2.28
diff -u -r1.293.2.11.2.9.2.28 zend.h
--- zend.h 15 Aug 2008 19:47:23 -0000 1.293.2.11.2.9.2.28
+++ zend.h 8 Sep 2008 09:06:13 -0000
@@ -432,8 +432,12 @@
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
+ union _zend_function *__getstatic;
+ union _zend_function *__setstatic;
union _zend_function *__unset;
union _zend_function *__isset;
+ union _zend_function *__unsetstatic;
+ union _zend_function *__issetstatic;
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
@@ -462,6 +466,7 @@
zend_uint doc_comment_len;
struct _zend_module_entry *module;
+ HashTable *guards;
};
#include "zend_stream.h"
Index: zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.34.2.53
diff -u -r1.296.2.27.2.34.2.53 zend_API.c
--- zend_API.c 22 Aug 2008 14:51:30 -0000 1.296.2.27.2.34.2.53
+++ zend_API.c 8 Sep 2008 09:06:15 -0000
@@ -1774,7 +1774,7 @@
int count=0, unload=0;
HashTable *target_function_table = function_table;
int error_type;
- zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
+ zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__getstatic = NULL, *__setstatic = NULL, *__unset = NULL, *__isset = NULL, *__unsetstatic = NULL, *__issetstatic = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
char *lowercase_name;
int fname_len;
char *lc_class_name = NULL;
@@ -1900,10 +1900,18 @@
__get = reg_function;
} else if ((fname_len == sizeof(ZEND_SET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME))) {
__set = reg_function;
+ } else if ((fname_len == sizeof(ZEND_GETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_GETSTATIC_FUNC_NAME, sizeof(ZEND_GETSTATIC_FUNC_NAME))) {
+ __getstatic = reg_function;
+ } else if ((fname_len == sizeof(ZEND_SETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SETSTATIC_FUNC_NAME, sizeof(ZEND_SETSTATIC_FUNC_NAME))) {
+ __setstatic = reg_function;
} else if ((fname_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME))) {
__unset = reg_function;
} else if ((fname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME))) {
__isset = reg_function;
+ } else if ((fname_len == sizeof(ZEND_UNSETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSETSTATIC_FUNC_NAME, sizeof(ZEND_UNSETSTATIC_FUNC_NAME))) {
+ __unsetstatic = reg_function;
+ } else if ((fname_len == sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSETSTATIC_FUNC_NAME, sizeof(ZEND_ISSETSTATIC_FUNC_NAME))) {
+ __issetstatic = reg_function;
} else {
reg_function = NULL;
}
@@ -1941,8 +1949,12 @@
scope->__tostring = __tostring;
scope->__get = __get;
scope->__set = __set;
+ scope->__getstatic = __getstatic;
+ scope->__setstatic = __setstatic;
scope->__unset = __unset;
scope->__isset = __isset;
+ scope->__unsetstatic = __unsetstatic;
+ scope->__issetstatic = __issetstatic;
if (ctor) {
ctor->common.fn_flags |= ZEND_ACC_CTOR;
if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
@@ -1994,6 +2006,18 @@
}
__set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
}
+ if (__getstatic) {
+ if (!(__getstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+ zend_error(error_type, "Method %s::%s() must be static", scope->name, __getstatic->common.function_name);
+ }
+ __getstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+ }
+ if (__setstatic) {
+ if (!(__setstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+ zend_error(error_type, "Method %s::%s() must be static", scope->name, __setstatic->common.function_name);
+ }
+ __setstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+ }
if (__unset) {
if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __unset->common.function_name);
@@ -2006,6 +2030,18 @@
}
__isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
}
+ if (__unsetstatic) {
+ if (!(__unsetstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+ zend_error(error_type, "Method %s::%s() must be static", scope->name, __unsetstatic->common.function_name);
+ }
+ __unsetstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+ }
+ if (__issetstatic) {
+ if (!(__issetstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+ zend_error(error_type, "Method %s::%s() must be static", scope->name, __issetstatic->common.function_name);
+ }
+ __issetstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+ }
efree(lc_class_name);
}
return SUCCESS;
Index: zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.41.2.85
diff -u -r1.647.2.27.2.41.2.85 zend_compile.c
--- zend_compile.c 29 Aug 2008 10:17:08 -0000 1.647.2.27.2.41.2.85
+++ zend_compile.c 8 Sep 2008 09:06:17 -0000
@@ -636,6 +636,21 @@
return;
} else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
+ } else if (last_op->opcode == ZEND_FETCH_W && last_op->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
+ if (n > 0) {
+ *opline = *last_op;
+ MAKE_NOP(last_op);
+ last_op = opline;
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ }
+ last_op->opcode = ZEND_ASSIGN_CLASS;
+ zend_do_op_data(opline, value TSRMLS_CC);
+ opline->op2.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op2.u.EA.type = 0;
+ opline->op2.op_type = IS_VAR;
+ SET_UNUSED(opline->result);
+ *result = last_op->result;
+ return;
} else {
break;
}
@@ -1288,6 +1303,16 @@
zend_error(E_WARNING, "The magic method __set() must have public visibility and can not be static");
}
CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_GETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GETSTATIC_FUNC_NAME, sizeof(ZEND_GETSTATIC_FUNC_NAME)-1))) {
+ if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+ zend_error(E_WARNING, "The magic method __getStatic() must have public visibility and be static");
+ }
+ CG(active_class_entry)->__getstatic = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_SETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SETSTATIC_FUNC_NAME, sizeof(ZEND_SETSTATIC_FUNC_NAME)-1))) {
+ if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+ zend_error(E_WARNING, "The magic method __setStatic() must have public visibility and be static");
+ }
+ CG(active_class_entry)->__setstatic = (zend_function *) CG(active_op_array);
} else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __unset() must have public visibility and can not be static");
@@ -1298,6 +1323,16 @@
zend_error(E_WARNING, "The magic method __isset() must have public visibility and can not be static");
}
CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSETSTATIC_FUNC_NAME, sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1))) {
+ if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+ zend_error(E_WARNING, "The magic method __issetStatic() must have public visibility and be static");
+ }
+ CG(active_class_entry)->__issetstatic = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_UNSETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSETSTATIC_FUNC_NAME, sizeof(ZEND_UNSETSTATIC_FUNC_NAME)-1))) {
+ if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+ zend_error(E_WARNING, "The magic method __unsetStatic() must have public visibility and be static");
+ }
+ CG(active_class_entry)->__unsetstatic = (zend_function *) CG(active_op_array);
} else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and can not be static");
@@ -2394,12 +2429,24 @@
if (!ce->__set) {
ce->__set = ce->parent->__set;
}
+ if (!ce->__getstatic) {
+ ce->__getstatic = ce->parent->__getstatic;
+ }
+ if (!ce->__setstatic) {
+ ce->__setstatic = ce->parent->__setstatic;
+ }
if (!ce->__unset) {
ce->__unset = ce->parent->__unset;
}
if (!ce->__isset) {
ce->__isset = ce->parent->__isset;
}
+ if (!ce->__unsetstatic) {
+ ce->__unsetstatic = ce->parent->__unsetstatic;
+ }
+ if (!ce->__issetstatic) {
+ ce->__issetstatic = ce->parent->__issetstatic;
+ }
if (!ce->__call) {
ce->__call = ce->parent->__call;
}
@@ -4929,6 +4976,8 @@
ce->doc_comment = NULL;
ce->doc_comment_len = 0;
+
+ ce->guards = NULL;
zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0);
@@ -4960,8 +5009,12 @@
ce->clone = NULL;
ce->__get = NULL;
ce->__set = NULL;
+ ce->__getstatic = NULL;
+ ce->__setstatic = NULL;
ce->__unset = NULL;
ce->__isset = NULL;
+ ce->__unsetstatic = NULL;
+ ce->__issetstatic = NULL;
ce->__call = NULL;
ce->__callstatic = NULL;
ce->__tostring = NULL;
Index: zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.12.2.33
diff -u -r1.316.2.8.2.12.2.33 zend_compile.h
--- zend_compile.h 29 Aug 2008 18:12:47 -0000 1.316.2.8.2.12.2.33
+++ zend_compile.h 8 Sep 2008 09:06:17 -0000
@@ -737,8 +737,12 @@
#define ZEND_DESTRUCTOR_FUNC_NAME "__destruct"
#define ZEND_GET_FUNC_NAME "__get"
#define ZEND_SET_FUNC_NAME "__set"
+#define ZEND_GETSTATIC_FUNC_NAME "__getstatic"
+#define ZEND_SETSTATIC_FUNC_NAME "__setstatic"
#define ZEND_UNSET_FUNC_NAME "__unset"
#define ZEND_ISSET_FUNC_NAME "__isset"
+#define ZEND_UNSETSTATIC_FUNC_NAME "__unsetstatic"
+#define ZEND_ISSETSTATIC_FUNC_NAME "__issetstatic"
#define ZEND_CALL_FUNC_NAME "__call"
#define ZEND_CALLSTATIC_FUNC_NAME "__callstatic"
#define ZEND_TOSTRING_FUNC_NAME "__tostring"
Index: zend_object_handlers.c
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.c,v
retrieving revision 1.135.2.6.2.22.2.20
diff -u -r1.135.2.6.2.22.2.20 zend_object_handlers.c
--- zend_object_handlers.c 14 Aug 2008 21:36:56 -0000 1.135.2.6.2.22.2.20
+++ zend_object_handlers.c 8 Sep 2008 09:06:19 -0000
@@ -308,6 +308,23 @@
stub.in_isset = 0;
return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
}
+
+static int zend_get_class_property_guard(zend_class_entry *ce, zend_property_info *property_info, zend_guard **pguard) /* {{{ */
+{
+ zend_guard stub;
+
+ if (!ce->guards) {
+ ALLOC_HASHTABLE(ce->guards);
+ zend_hash_init(ce->guards, 0, NULL, NULL, 0);
+ } else if (zend_hash_quick_find(ce->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
+ return SUCCESS;
+ }
+ stub.in_get = 0;
+ stub.in_set = 0;
+ stub.in_unset = 0;
+ stub.in_isset = 0;
+ return zend_hash_quick_add(ce->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
+}
/* }}} */
zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
@@ -978,6 +995,74 @@
}
/* }}} */
+ZEND_API int zend_std_set_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zval** value TSRMLS_DC) /* {{{ */
+{
+ zval **retval = NULL;
+ zend_class_entry *tmp_ce = ce;
+ zend_property_info *property_info;
+ zend_property_info std_property_info;
+
+#if DEBUG_OBJECT_HANDLERS
+ fprintf(stderr, "%s::$%s = ", ce->name, property_name);
+ zend_print_zval_r(*value, 2 TSRMLS_CC);
+#endif
+
+ if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) {
+ std_property_info.flags = ZEND_ACC_PUBLIC;
+ std_property_info.name = property_name;
+ std_property_info.name_length = property_name_len;
+ std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1);
+ std_property_info.ce = ce;
+ property_info = &std_property_info;
+ }
+
+ if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
+ zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
+ return 0;
+ }
+
+ zend_update_class_constants(tmp_ce TSRMLS_CC);
+ zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
+
+ if (!retval) {
+ zend_property_info property_info;
+ zend_guard *guard;
+
+ if (!ce->__setstatic) {
+ zend_error(E_ERROR, "Cannot access undeclared property %s::$%s", ce->name, property_name);
+ return NULL;
+ }
+
+ property_info.flags = ZEND_ACC_PUBLIC;
+ property_info.name = property_name;
+ property_info.name_length = property_name_len;
+ property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
+ property_info.ce = ce;
+
+ if (zend_get_class_property_guard(ce, &property_info, &guard) == SUCCESS && !guard->in_set) {
+ zval *member;
+ zval *return_value = NULL;
+ zend_class_entry *scope;
+
+ ALLOC_INIT_ZVAL(member);
+ ZVAL_STRING(member, property_info.name, 0);
+
+ guard->in_set = 1; /* prevent circular getting */
+ scope = EG(called_scope);
+ EG(called_scope)= ce;
+ zend_call_method_with_2_params(NULL, ce, &ce->__setstatic, ZEND_SETSTATIC_FUNC_NAME, &return_value, member, *value);
+ EG(called_scope)= scope;
+ guard->in_set = 0;
+ }
+
+ } else {
+ *retval = *value;
+ zval_copy_ctor(*retval);
+ }
+
+ return 1;
+}
+
ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC) /* {{{ */
{
zval **retval = NULL;
@@ -1010,6 +1095,43 @@
zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
if (!retval) {
+ zend_guard *guard;
+ zend_function *interceptor = silent ? ce->__issetstatic : ce->__getstatic;
+
+ if (interceptor && zend_get_class_property_guard(ce, property_info, &guard) == SUCCESS) {
+ zend_bool *in_interceptor;
+ char *interceptor_name;
+
+ if (silent) {
+ in_interceptor = &guard->in_isset;
+ interceptor_name = ZEND_ISSETSTATIC_FUNC_NAME;
+ } else {
+ in_interceptor = &guard->in_get;
+ interceptor_name = ZEND_GETSTATIC_FUNC_NAME;
+ }
+
+ if (!*in_interceptor) {
+ zval *member;
+ zval *return_value = NULL;
+ zend_class_entry *scope;
+
+ ALLOC_INIT_ZVAL(member);
+ ZVAL_STRING(member, property_info->name, 0);
+
+ *in_interceptor = 1; /* prevent circular getting */
+ scope = EG(called_scope);
+ EG(called_scope)= ce;
+ zend_call_method_with_1_params(NULL, ce, &interceptor, interceptor_name, &return_value, member);
+ EG(called_scope)= scope;
+ *in_interceptor = 0;
+
+ if (return_value) {
+ retval = &return_value;
+ return retval;
+ }
+ }
+ }
+
if (silent) {
return NULL;
} else {
@@ -1023,8 +1145,44 @@
ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) /* {{{ */
{
+
+ /* We will allow unsetting of static properties only if:
+ * a) __unsetStatic() is defined
+ * b) the member does not exist as declared member
+ * Otherwise, we'll raise a E_ERROR
+ */
+ if (ce->__unsetstatic && !zend_hash_exists(&ce->properties_info, property_name, property_name_len+1)) {
+ zend_property_info property_info;
+ zend_guard *guard;
+
+ property_info.flags = ZEND_ACC_PUBLIC;
+ property_info.name = property_name;
+ property_info.name_length = property_name_len;
+ property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
+ property_info.ce = ce;
+
+ if (zend_get_class_property_guard(ce, &property_info, &guard) == SUCCESS && !guard->in_unset) {
+ zval *member;
+ zval *return_value = NULL;
+ zend_class_entry *scope;
+
+ ALLOC_INIT_ZVAL(member);
+ ZVAL_STRING(member, property_info.name, 0);
+
+ guard->in_unset = 1; /* prevent circular getting */
+ scope = EG(called_scope);
+ EG(called_scope)= ce;
+ zend_call_method_with_1_params(NULL, ce, &ce->__unsetstatic, ZEND_UNSETSTATIC_FUNC_NAME, &return_value, member);
+ EG(called_scope)= scope;
+ guard->in_unset = 0;
+
+ if (return_value) {
+ return 1;
+ }
+ }
+ }
zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
- return 0;
+ return 0;
}
/* }}} */
Index: zend_object_handlers.h
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.h,v
retrieving revision 1.47.2.2.2.5.2.5
diff -u -r1.47.2.2.2.5.2.5 zend_object_handlers.h
--- zend_object_handlers.h 14 Aug 2008 21:36:56 -0000 1.47.2.2.2.5.2.5
+++ zend_object_handlers.h 8 Sep 2008 09:06:20 -0000
@@ -145,6 +145,7 @@
BEGIN_EXTERN_C()
ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC);
ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC);
+ZEND_API int zend_std_set_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zval **value TSRMLS_DC);
ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC);
ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC);
ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC);
Index: zend_opcode.c
===================================================================
RCS file: /repository/ZendEngine2/zend_opcode.c,v
retrieving revision 1.110.2.6.2.3.2.9
diff -u -r1.110.2.6.2.3.2.9 zend_opcode.c
--- zend_opcode.c 29 Aug 2008 18:12:47 -0000 1.110.2.6.2.3.2.9
+++ zend_opcode.c 8 Sep 2008 09:06:20 -0000
@@ -179,6 +179,10 @@
if (--ce->refcount > 0) {
return;
}
+ if (ce->guards) {
+ zend_hash_destroy(ce->guards);
+ FREE_HASHTABLE(ce->guards);
+ }
switch (ce->type) {
case ZEND_USER_CLASS:
zend_hash_destroy(&ce->default_properties);
Index: zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.59.2.29.2.48.2.70
diff -u -r1.59.2.29.2.48.2.70 zend_vm_def.h
--- zend_vm_def.h 15 Aug 2008 19:47:28 -0000 1.59.2.29.2.48.2.70
+++ zend_vm_def.h 8 Sep 2008 09:06:22 -0000
@@ -1503,6 +1503,22 @@
ZEND_VM_NEXT_OPCODE();
}
+ZEND_VM_HANDLER(137, ZEND_ASSIGN_CLASS, CONST, CONST|TMP|VAR|CV)
+{
+ zend_op *opline = EX(opline);
+ zend_op *op_data = opline+1;
+ zend_free_op free_op1;
+ zend_free_op free_value;
+ zval *varname = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+ zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+ /* assign_class has two opcodes! */
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
{
zend_op *opline = EX(opline);
Index: zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.62.2.30.2.49.2.70
diff -u -r1.62.2.30.2.49.2.70 zend_vm_execute.h
--- zend_vm_execute.h 15 Aug 2008 19:47:28 -0000 1.62.2.30.2.49.2.70
+++ zend_vm_execute.h 8 Sep 2008 09:06:36 -0000
@@ -2595,6 +2595,22 @@
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_ASSIGN_CLASS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+ zend_op *op_data = opline+1;
+
+ zend_free_op free_value;
+ zval *varname = &opline->op1.u.constant;
+ zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+ zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+ /* assign_class has two opcodes! */
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -3191,6 +3207,22 @@
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_ASSIGN_CLASS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+ zend_op *op_data = opline+1;
+
+ zend_free_op free_value;
+ zval *varname = &opline->op1.u.constant;
+ zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+ zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+ /* assign_class has two opcodes! */
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -3667,6 +3699,22 @@
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_ASSIGN_CLASS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+ zend_op *op_data = opline+1;
+
+ zend_free_op free_value;
+ zval *varname = &opline->op1.u.constant;
+ zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+ zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+ /* assign_class has two opcodes! */
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -4343,6 +4391,22 @@
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_ASSIGN_CLASS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+ zend_op *op_data = opline+1;
+
+ zend_free_op free_value;
+ zval *varname = &opline->op1.u.constant;
+ zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+ zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+ /* assign_class has two opcodes! */
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -33671,11 +33735,11 @@
ZEND_ASSIGN_OBJ_SPEC_CV_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_ASSIGN_OBJ_SPEC_CV_CV_HANDLER,
+ ZEND_ASSIGN_CLASS_SPEC_CONST_CONST_HANDLER,
+ ZEND_ASSIGN_CLASS_SPEC_CONST_TMP_HANDLER,
+ ZEND_ASSIGN_CLASS_SPEC_CONST_VAR_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_ASSIGN_CLASS_SPEC_CONST_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
Index: zend_vm_opcodes.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v
retrieving revision 1.42.2.17.2.1.2.7
diff -u -r1.42.2.17.2.1.2.7 zend_vm_opcodes.h
--- zend_vm_opcodes.h 14 Jul 2008 09:49:02 -0000 1.42.2.17.2.1.2.7
+++ zend_vm_opcodes.h 8 Sep 2008 09:06:36 -0000
@@ -138,6 +138,7 @@
#define ZEND_POST_INC_OBJ 134
#define ZEND_POST_DEC_OBJ 135
#define ZEND_ASSIGN_OBJ 136
+#define ZEND_ASSIGN_CLASS 137
#define ZEND_INSTANCEOF 138
#define ZEND_DECLARE_CLASS 139
#define ZEND_DECLARE_INHERITED_CLASS 140
Index: tests/get_static.phpt
===================================================================
RCS file: tests/get_static.phpt
diff -N tests/get_static.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/get_static.phpt 8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,32 @@
+--TEST--
+__getStatic()
+--FILE--
+<?php
+class Regular {
+ public static $exists= TRUE;
+}
+class Base {
+ public static function __getStatic($member) {
+ var_dump($member);
+ if ('class' === $member) {
+ return new ReflectionClass(get_called_class());
+ }
+ }
+}
+class Child extends Base {
+}
+
+var_dump(Base::$class->getName());
+var_dump(Child::$class->getName());
+var_dump(Regular::$exists);
+var_dump(Regular::$nonExistant);
+?>
+===DONE===
+--EXPECTF--
+string(5) "class"
+string(4) "Base"
+string(5) "class"
+string(5) "Child"
+bool(true)
+Fatal error: Access to undeclared static property: Regular::$nonExistant in %s
+===DONE===
Index: tests/isset_static.phpt
===================================================================
RCS file: tests/isset_static.phpt
diff -N tests/isset_static.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/isset_static.phpt 8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,35 @@
+--TEST--
+__issetStatic()
+--FILE--
+<?php
+class Regular {
+ public static $exists= TRUE;
+}
+class Base {
+ public static function __issetStatic($member) {
+ var_dump($member);
+ if ('class' === $member) {
+ return TRUE;
+ }
+ }
+}
+class Child extends Base {
+}
+
+var_dump(isset(Regular::$exists));
+var_dump(isset(Regular::$nonExistant));
+var_dump(isset(Base::$class));
+var_dump(isset(Child::$class));
+var_dump(isset(Base::$nonExistant));
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+bool(false)
+string(5) "class"
+bool(true)
+string(5) "class"
+bool(true)
+string(11) "nonExistant"
+bool(false)
+===DONE===
Index: tests/set_static.phpt
===================================================================
RCS file: tests/set_static.phpt
diff -N tests/set_static.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/set_static.phpt 8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,29 @@
+--TEST--
+__setStatic()
+--FILE--
+<?php
+class Regular {
+ public static $exists;
+}
+class Base {
+ public static function __setStatic($member, $value) {
+ var_dump($member, $value);
+ }
+}
+class Child extends Base {
+}
+
+var_dump(Regular::$exists);
+Regular::$exists= TRUE;
+var_dump(Regular::$exists);
+Base::$hello= 'World';
+Regular::$nonExistant= '@@';
+?>
+===DONE===
+--EXPECTF--
+NULL
+bool(true)
+string(5) "hello"
+string(5) "World"
+Fatal error: Cannot access undeclared property Regular::$nonExistant in %s
+===DONE===
Index: tests/unset_static.phpt
===================================================================
RCS file: tests/unset_static.phpt
diff -N tests/unset_static.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/unset_static.phpt 8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,37 @@
+--TEST--
+__unsetStatic()
+--FILE--
+<?php
+class Registry {
+ public static $members= array(
+ 'classes' => array('one', 'two', 'three')
+ );
+
+ public static function __unsetStatic($member) {
+ var_dump($member);
+ unset(self::$members[$member]);
+ }
+}
+var_dump(Registry::$members);
+unset(Registry::$classes);
+var_dump(Registry::$members);
+unset(Registry::$members);
+?>
+===DONE===
+--EXPECTF--
+array(1) {
+ ["classes"]=>
+ array(3) {
+ [0]=>
+ string(3) "one"
+ [1]=>
+ string(3) "two"
+ [2]=>
+ string(5) "three"
+ }
+}
+string(7) "classes"
+array(0) {
+}
+Fatal error: Attempt to unset static property Registry::$members in %s
+===DONE===
|