mirror of
https://github.com/php/php-src.git
synced 2024-12-12 03:15:29 +08:00
68fdad82c9
Fixes OSS-Fuzz #23140.
157 lines
4.1 KiB
C
157 lines
4.1 KiB
C
#include "zend.h"
|
|
#include "zend_API.h"
|
|
#include "zend_attributes.h"
|
|
|
|
ZEND_API zend_class_entry *zend_ce_php_attribute;
|
|
|
|
static HashTable internal_validators;
|
|
|
|
void zend_attribute_validate_phpattribute(zend_attribute *attr, int target)
|
|
{
|
|
if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
|
|
zend_error(E_COMPILE_ERROR, "Only classes can be marked with <<PhpAttribute>>");
|
|
}
|
|
}
|
|
|
|
ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname)
|
|
{
|
|
return zend_hash_find_ptr(&internal_validators, lcname);
|
|
}
|
|
|
|
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
|
|
{
|
|
if (attributes) {
|
|
zend_attribute *attr;
|
|
|
|
ZEND_HASH_FOREACH_PTR(attributes, attr) {
|
|
if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) {
|
|
return attr;
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
|
|
{
|
|
if (attributes) {
|
|
zend_attribute *attr;
|
|
|
|
ZEND_HASH_FOREACH_PTR(attributes, attr) {
|
|
if (attr->offset == offset && ZSTR_LEN(attr->lcname) == len) {
|
|
if (0 == memcmp(ZSTR_VAL(attr->lcname), str, len)) {
|
|
return attr;
|
|
}
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname)
|
|
{
|
|
return get_attribute(attributes, lcname, 0);
|
|
}
|
|
|
|
ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
|
|
{
|
|
return get_attribute_str(attributes, str, len, 0);
|
|
}
|
|
|
|
ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
|
|
{
|
|
return get_attribute(attributes, lcname, offset + 1);
|
|
}
|
|
|
|
ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
|
|
{
|
|
return get_attribute_str(attributes, str, len, offset + 1);
|
|
}
|
|
|
|
static zend_always_inline void free_attribute(zend_attribute *attr, int persistent)
|
|
{
|
|
uint32_t i;
|
|
|
|
zend_string_release(attr->name);
|
|
zend_string_release(attr->lcname);
|
|
|
|
for (i = 0; i < attr->argc; i++) {
|
|
zval_ptr_dtor(&attr->argv[i]);
|
|
}
|
|
|
|
pefree(attr, persistent);
|
|
}
|
|
|
|
static void attr_free(zval *v)
|
|
{
|
|
free_attribute((zend_attribute *) Z_PTR_P(v), 0);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (*attributes == NULL) {
|
|
*attributes = pemalloc(sizeof(HashTable), persistent);
|
|
zend_hash_init(*attributes, 8, NULL, persistent ? attr_pfree : attr_free, persistent);
|
|
}
|
|
|
|
zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(argc), persistent);
|
|
|
|
if (persistent == ((GC_FLAGS(name) & IS_STR_PERSISTENT) != 0)) {
|
|
attr->name = zend_string_copy(name);
|
|
} else {
|
|
attr->name = zend_string_dup(name, persistent);
|
|
}
|
|
|
|
attr->lcname = zend_string_tolower_ex(attr->name, persistent);
|
|
attr->offset = offset;
|
|
attr->argc = argc;
|
|
|
|
/* Initialize arguments to avoid partial initialization in case of fatal errors. */
|
|
for (uint32_t i = 0; i < argc; i++) {
|
|
ZVAL_UNDEF(&attr->argv[i]);
|
|
}
|
|
|
|
zend_hash_next_index_insert_ptr(*attributes, attr);
|
|
|
|
return attr;
|
|
}
|
|
|
|
ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
|
|
{
|
|
if (ce->type != ZEND_INTERNAL_CLASS) {
|
|
zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
|
|
}
|
|
|
|
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
|
|
|
|
zend_hash_update_ptr(&internal_validators, lcname, validator);
|
|
zend_string_release(lcname);
|
|
|
|
zend_add_class_attribute(ce, zend_ce_php_attribute->name, 0);
|
|
}
|
|
|
|
void zend_register_attribute_ce(void)
|
|
{
|
|
zend_hash_init(&internal_validators, 8, NULL, NULL, 1);
|
|
|
|
zend_class_entry ce;
|
|
|
|
INIT_CLASS_ENTRY(ce, "PhpAttribute", NULL);
|
|
zend_ce_php_attribute = zend_register_internal_class(&ce);
|
|
zend_ce_php_attribute->ce_flags |= ZEND_ACC_FINAL;
|
|
|
|
zend_compiler_attribute_register(zend_ce_php_attribute, zend_attribute_validate_phpattribute);
|
|
}
|
|
|
|
void zend_attributes_shutdown(void)
|
|
{
|
|
zend_hash_destroy(&internal_validators);
|
|
}
|