Skip to content

Commit 76fcd70

Browse files
authored
Fix enum preloading again (#8859)
1 parent 42c5712 commit 76fcd70

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

Zend/zend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ typedef struct _zend_class_mutable_data {
115115
zval *default_properties_table;
116116
HashTable *constants_table;
117117
uint32_t ce_flags;
118+
HashTable *backed_enum_table;
118119
} zend_class_mutable_data;
119120

120121
typedef struct _zend_class_dependency {

Zend/zend_API.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ typedef struct _zend_fcall_info_cache {
321321
#define CE_DEFAULT_PROPERTIES_TABLE(ce) \
322322
zend_class_default_properties_table(ce)
323323

324+
#define CE_BACKED_ENUM_TABLE(ce) \
325+
zend_class_backed_enum_table(ce)
326+
324327
#define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0)
325328

326329
ZEND_API int zend_next_free_module(void);
@@ -450,6 +453,26 @@ static zend_always_inline zval *zend_class_default_properties_table(zend_class_e
450453
}
451454
}
452455

456+
static zend_always_inline void zend_class_set_backed_enum_table(zend_class_entry *ce, HashTable *backed_enum_table)
457+
{
458+
if (ZEND_MAP_PTR(ce->mutable_data) && ce->type == ZEND_USER_CLASS) {
459+
zend_class_mutable_data *mutable_data = (zend_class_mutable_data*)ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
460+
mutable_data->backed_enum_table = backed_enum_table;
461+
} else {
462+
ce->backed_enum_table = backed_enum_table;
463+
}
464+
}
465+
466+
static zend_always_inline HashTable *zend_class_backed_enum_table(zend_class_entry *ce)
467+
{
468+
if (ZEND_MAP_PTR(ce->mutable_data) && ce->type == ZEND_USER_CLASS) {
469+
zend_class_mutable_data *mutable_data = (zend_class_mutable_data*)ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
470+
return mutable_data->backed_enum_table;
471+
} else {
472+
return ce->backed_enum_table;
473+
}
474+
}
475+
453476
ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value);
454477
ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value);
455478
ZEND_API void zend_update_property_null(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length);

Zend/zend_enum.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,14 @@ void zend_enum_add_interfaces(zend_class_entry *ce)
187187
zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce)
188188
{
189189
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_ENUM);
190-
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
191190
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
192191

193192
uint32_t backing_type = ce->enum_backing_type;
194193
ZEND_ASSERT(backing_type != IS_UNDEF);
195194

196-
ce->backed_enum_table = emalloc(sizeof(HashTable));
197-
zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 0);
195+
HashTable *backed_enum_table = emalloc(sizeof(HashTable));
196+
zend_hash_init(backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 0);
197+
zend_class_set_backed_enum_table(ce, backed_enum_table);
198198

199199
zend_string *enum_class_name = ce->name;
200200

@@ -219,35 +219,35 @@ zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce)
219219

220220
if (ce->enum_backing_type == IS_LONG) {
221221
zend_long long_key = Z_LVAL_P(case_value);
222-
zval *existing_case_name = zend_hash_index_find(ce->backed_enum_table, long_key);
222+
zval *existing_case_name = zend_hash_index_find(backed_enum_table, long_key);
223223
if (existing_case_name) {
224224
zend_throw_error(NULL, "Duplicate value in enum %s for cases %s and %s",
225225
ZSTR_VAL(enum_class_name),
226226
Z_STRVAL_P(existing_case_name),
227227
ZSTR_VAL(name));
228228
goto failure;
229229
}
230-
zend_hash_index_add_new(ce->backed_enum_table, long_key, case_name);
230+
zend_hash_index_add_new(backed_enum_table, long_key, case_name);
231231
} else {
232232
ZEND_ASSERT(ce->enum_backing_type == IS_STRING);
233233
zend_string *string_key = Z_STR_P(case_value);
234-
zval *existing_case_name = zend_hash_find(ce->backed_enum_table, string_key);
234+
zval *existing_case_name = zend_hash_find(backed_enum_table, string_key);
235235
if (existing_case_name != NULL) {
236236
zend_throw_error(NULL, "Duplicate value in enum %s for cases %s and %s",
237237
ZSTR_VAL(enum_class_name),
238238
Z_STRVAL_P(existing_case_name),
239239
ZSTR_VAL(name));
240240
goto failure;
241241
}
242-
zend_hash_add_new(ce->backed_enum_table, string_key, case_name);
242+
zend_hash_add_new(backed_enum_table, string_key, case_name);
243243
}
244244
} ZEND_HASH_FOREACH_END();
245245

246246
return SUCCESS;
247247

248248
failure:
249-
zend_hash_release(ce->backed_enum_table);
250-
ce->backed_enum_table = NULL;
249+
zend_hash_release(backed_enum_table);
250+
zend_class_set_backed_enum_table(ce, NULL);
251251
return FAILURE;
252252
}
253253

@@ -282,17 +282,19 @@ ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_clas
282282
return FAILURE;
283283
}
284284
}
285-
if (!ce->backed_enum_table) {
285+
286+
HashTable *backed_enum_table = CE_BACKED_ENUM_TABLE(ce);
287+
if (!backed_enum_table) {
286288
goto not_found;
287289
}
288290

289291
zval *case_name_zv;
290292
if (ce->enum_backing_type == IS_LONG) {
291-
case_name_zv = zend_hash_index_find(ce->backed_enum_table, long_key);
293+
case_name_zv = zend_hash_index_find(backed_enum_table, long_key);
292294
} else {
293295
ZEND_ASSERT(ce->enum_backing_type == IS_STRING);
294296
ZEND_ASSERT(string_key != NULL);
295-
case_name_zv = zend_hash_find(ce->backed_enum_table, string_key);
297+
case_name_zv = zend_hash_find(backed_enum_table, string_key);
296298
}
297299

298300
if (case_name_zv == NULL) {
@@ -496,8 +498,9 @@ ZEND_API zend_class_entry *zend_register_internal_enum(
496498
ce->ce_flags |= ZEND_ACC_ENUM;
497499
ce->enum_backing_type = type;
498500
if (type != IS_UNDEF) {
499-
ce->backed_enum_table = pemalloc(sizeof(HashTable), 1);
500-
zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 1);
501+
HashTable *backed_enum_table = pemalloc(sizeof(HashTable), 1);
502+
zend_hash_init(backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 1);
503+
zend_class_set_backed_enum_table(ce, backed_enum_table);
501504
}
502505

503506
zend_enum_register_props(ce);
@@ -562,12 +565,14 @@ ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, z
562565
zval_make_interned_string(value);
563566
}
564567

568+
HashTable *backed_enum_table = CE_BACKED_ENUM_TABLE(ce);
569+
565570
zval case_name_zv;
566571
ZVAL_STR(&case_name_zv, case_name);
567572
if (Z_TYPE_P(value) == IS_LONG) {
568-
zend_hash_index_add_new(ce->backed_enum_table, Z_LVAL_P(value), &case_name_zv);
573+
zend_hash_index_add_new(backed_enum_table, Z_LVAL_P(value), &case_name_zv);
569574
} else {
570-
zend_hash_add_new(ce->backed_enum_table, Z_STR_P(value), &case_name_zv);
575+
zend_hash_add_new(backed_enum_table, Z_STR_P(value), &case_name_zv);
571576
}
572577
} else {
573578
ZEND_ASSERT(ce->enum_backing_type == IS_UNDEF);

Zend/zend_opcode.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,11 @@ ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce)
275275
mutable_data->default_properties_table = NULL;
276276
}
277277

278+
if (mutable_data->backed_enum_table) {
279+
zend_hash_release(mutable_data->backed_enum_table);
280+
mutable_data->backed_enum_table = NULL;
281+
}
282+
278283
ZEND_MAP_PTR_SET_IMM(ce->mutable_data, NULL);
279284
}
280285
}

0 commit comments

Comments
 (0)