return 0;
}
-static zend_always_inline void free_attribute(zend_attribute *attr, bool persistent)
+static void attr_free(zval *v)
{
- uint32_t i;
+ zend_attribute *attr = Z_PTR_P(v);
zend_string_release(attr->name);
zend_string_release(attr->lcname);
- for (i = 0; i < attr->argc; i++) {
+ for (uint32_t i = 0; i < attr->argc; i++) {
if (attr->args[i].name) {
zend_string_release(attr->args[i].name);
}
zval_ptr_dtor(&attr->args[i].value);
}
- pefree(attr, persistent);
-}
-
-static void attr_free(zval *v)
-{
- free_attribute((zend_attribute *) Z_PTR_P(v), 0);
+ pefree(attr, attr->flags & ZEND_ATTRIBUTE_PERSISTENT);
}
-static void attr_pfree(zval *v)
-{
- free_attribute((zend_attribute *) Z_PTR_P(v), 1);
-}
-
-ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_bool persistent, uint32_t offset, zend_string *name, uint32_t argc)
+ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno)
{
+ bool persistent = flags & ZEND_ATTRIBUTE_PERSISTENT;
if (*attributes == NULL) {
*attributes = pemalloc(sizeof(HashTable), persistent);
- zend_hash_init(*attributes, 8, NULL, persistent ? attr_pfree : attr_free, persistent);
+ zend_hash_init(*attributes, 8, NULL, attr_free, persistent);
}
zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(argc), persistent);
}
attr->lcname = zend_string_tolower_ex(attr->name, persistent);
+ attr->flags = flags;
+ attr->lineno = lineno;
attr->offset = offset;
attr->argc = argc;
#define ZEND_ATTRIBUTE_IS_REPEATABLE (1<<6)
#define ZEND_ATTRIBUTE_FLAGS ((1<<7) - 1)
+/* Flags for zend_attribute.flags */
+#define ZEND_ATTRIBUTE_PERSISTENT (1<<0)
+#define ZEND_ATTRIBUTE_STRICT_TYPES (1<<1)
+
#define ZEND_ATTRIBUTE_SIZE(argc) \
(sizeof(zend_attribute) + sizeof(zend_attribute_arg) * (argc) - sizeof(zend_attribute_arg))
typedef struct _zend_attribute {
zend_string *name;
zend_string *lcname;
+ uint32_t flags;
+ uint32_t lineno;
/* Parameter offsets start at 1, everything else uses 0. */
uint32_t offset;
uint32_t argc;
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags);
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname);
-ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_bool persistent, uint32_t offset, zend_string *name, uint32_t argc);
+ZEND_API zend_attribute *zend_add_attribute(
+ HashTable **attributes, zend_string *name, uint32_t argc,
+ uint32_t flags, uint32_t offset, uint32_t lineno);
END_EXTERN_C()
static zend_always_inline zend_attribute *zend_add_class_attribute(zend_class_entry *ce, zend_string *name, uint32_t argc)
{
- return zend_add_attribute(&ce->attributes, ce->type != ZEND_USER_CLASS, 0, name, argc);
+ uint32_t flags = ce->type != ZEND_USER_CLASS ? ZEND_ATTRIBUTE_PERSISTENT : 0;
+ return zend_add_attribute(&ce->attributes, name, argc, flags, 0, 0);
}
static zend_always_inline zend_attribute *zend_add_function_attribute(zend_function *func, zend_string *name, uint32_t argc)
{
- return zend_add_attribute(&func->common.attributes, func->common.type != ZEND_USER_FUNCTION, 0, name, argc);
+ uint32_t flags = func->common.type != ZEND_USER_FUNCTION ? ZEND_ATTRIBUTE_PERSISTENT : 0;
+ return zend_add_attribute(&func->common.attributes, name, argc, flags, 0, 0);
}
static zend_always_inline zend_attribute *zend_add_parameter_attribute(zend_function *func, uint32_t offset, zend_string *name, uint32_t argc)
{
- return zend_add_attribute(&func->common.attributes, func->common.type != ZEND_USER_FUNCTION, offset + 1, name, argc);
+ uint32_t flags = func->common.type != ZEND_USER_FUNCTION ? ZEND_ATTRIBUTE_PERSISTENT : 0;
+ return zend_add_attribute(&func->common.attributes, name, argc, flags, offset + 1, 0);
}
static zend_always_inline zend_attribute *zend_add_property_attribute(zend_class_entry *ce, zend_property_info *info, zend_string *name, uint32_t argc)
{
- return zend_add_attribute(&info->attributes, ce->type != ZEND_USER_CLASS, 0, name, argc);
+ uint32_t flags = ce->type != ZEND_USER_CLASS ? ZEND_ATTRIBUTE_PERSISTENT : 0;
+ return zend_add_attribute(&info->attributes, name, argc, flags, 0, 0);
}
static zend_always_inline zend_attribute *zend_add_class_constant_attribute(zend_class_entry *ce, zend_class_constant *c, zend_string *name, uint32_t argc)
{
- return zend_add_attribute(&c->attributes, ce->type != ZEND_USER_CLASS, 0, name, argc);
+ uint32_t flags = ce->type != ZEND_USER_CLASS ? ZEND_ATTRIBUTE_PERSISTENT : 0;
+ return zend_add_attribute(&c->attributes, name, argc, flags, 0, 0);
}
void zend_register_attribute_ce(void);
HashTable *attributes;
zend_attribute *data;
zend_class_entry *scope;
+ zend_string *filename;
uint32_t target;
} attribute_reference;
zend_string_release_ex(prop_reference->unmangled_name, 0);
efree(intern->ptr);
break;
- case REF_TYPE_ATTRIBUTE:
+ case REF_TYPE_ATTRIBUTE: {
+ attribute_reference *attr_ref = intern->ptr;
+ if (attr_ref->filename) {
+ zend_string_release(attr_ref->filename);
+ }
efree(intern->ptr);
break;
+ }
case REF_TYPE_GENERATOR:
case REF_TYPE_CLASS_CONSTANT:
case REF_TYPE_OTHER:
/* {{{ reflection_attribute_factory */
static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data,
- zend_class_entry *scope, uint32_t target)
+ zend_class_entry *scope, uint32_t target, zend_string *filename)
{
reflection_object *intern;
attribute_reference *reference;
reference->attributes = attributes;
reference->data = data;
reference->scope = scope;
+ reference->filename = filename ? zend_string_copy(filename) : NULL;
reference->target = target;
intern->ptr = reference;
intern->ref_type = REF_TYPE_ATTRIBUTE;
/* }}} */
static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
- uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base) /* {{{ */
+ uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */
{
ZEND_ASSERT(attributes != NULL);
ZEND_HASH_FOREACH_PTR(attributes, attr) {
if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) {
- reflection_attribute_factory(&tmp, attributes, attr, scope, target);
+ reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
add_next_index_zval(ret, &tmp);
}
} ZEND_HASH_FOREACH_END();
}
}
- reflection_attribute_factory(&tmp, attributes, attr, scope, target);
+ reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
add_next_index_zval(ret, &tmp);
} ZEND_HASH_FOREACH_END();
/* }}} */
static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes,
- uint32_t offset, zend_class_entry *scope, uint32_t target) /* {{{ */
+ uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */
{
zend_string *name = NULL;
zend_long flags = 0;
array_init(return_value);
- if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base)) {
+ if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) {
RETURN_THROWS();
}
}
target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
}
- reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, fptr->common.attributes, 0, fptr->common.scope, target);
+ reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ fptr->common.attributes, 0, fptr->common.scope, target,
+ fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL);
}
/* }}} */
HashTable *attributes = param->fptr->common.attributes;
zend_class_entry *scope = param->fptr->common.scope;
- reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER);
+ reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
+ param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
}
/* {{{ Returns whether this parameter is an optional parameter */
GET_REFLECTION_OBJECT_PTR(ref);
- reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
+ reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
+ ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
}
/* }}} */
GET_REFLECTION_OBJECT_PTR(ce);
- reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS);
+ reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
+ ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
}
/* }}} */
GET_REFLECTION_OBJECT_PTR(ref);
- reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY);
+ reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
+ ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
}
/* }}} */
}
/* }}} */
-static int call_attribute_constructor(zend_class_entry *ce, zend_object *obj, zval *args, uint32_t argc, HashTable *named_params) /* {{{ */
+static int call_attribute_constructor(
+ zend_attribute *attr, zend_class_entry *ce, zend_object *obj,
+ zval *args, uint32_t argc, HashTable *named_params, zend_string *filename)
{
zend_function *ctor = ce->constructor;
+ zend_execute_data *prev_execute_data, dummy_frame;
+ zend_function dummy_func;
+ zend_op dummy_opline;
ZEND_ASSERT(ctor != NULL);
if (!(ctor->common.fn_flags & ZEND_ACC_PUBLIC)) {
return FAILURE;
}
+ if (filename) {
+ /* Set up dummy call frame that makes it look like the attribute was invoked
+ * from where it occurs in the code. */
+ memset(&dummy_frame, 0, sizeof(zend_execute_data));
+ memset(&dummy_func, 0, sizeof(zend_function));
+ memset(&dummy_opline, 0, sizeof(zend_op));
+
+ prev_execute_data = EG(current_execute_data);
+ dummy_frame.prev_execute_data = prev_execute_data;
+ dummy_frame.func = &dummy_func;
+ dummy_frame.opline = &dummy_opline;
+
+ dummy_func.type = ZEND_USER_FUNCTION;
+ dummy_func.common.fn_flags =
+ attr->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0;
+ dummy_func.op_array.filename = filename;
+
+ dummy_opline.opcode = ZEND_DO_FCALL;
+ dummy_opline.lineno = attr->lineno;
+
+ EG(current_execute_data) = &dummy_frame;
+ }
+
zend_call_known_function(ctor, obj, obj->ce, NULL, argc, args, named_params);
+ if (filename) {
+ EG(current_execute_data) = prev_execute_data;
+ }
+
if (EG(exception)) {
zend_object_store_ctor_failed(obj);
return FAILURE;
return SUCCESS;
}
-/* }}} */
static void attribute_ctor_cleanup(
zval *obj, zval *args, uint32_t argc, HashTable *named_params) /* {{{ */
}
if (ce->constructor) {
- if (FAILURE == call_attribute_constructor(ce, Z_OBJ(obj), args, argc, named_params)) {
+ if (FAILURE == call_attribute_constructor(attr->data, ce, Z_OBJ(obj), args, argc, named_params, attr->filename)) {
attribute_ctor_cleanup(&obj, args, argc, named_params);
RETURN_THROWS();
}