Skip to content

Commit 666a86c

Browse files
authored
Fix resolving hooks within files declaring many functions on PHP 7.2 - 8.1 (#2045)
For details, see php/php-src#11222, which uses the same broken underlying API Signed-off-by: Bob Weinand <[email protected]>
1 parent b424086 commit 666a86c

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

zend_abstract_interface/interceptor/php7/resolver.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,36 @@ static void zai_interceptor_add_new_entries(HashPosition classpos, HashPosition
2424
}
2525
}
2626

27+
#if PHP_VERSION_ID >= 70200
28+
// Work around https://github.com/php/php-src/issues/11222
29+
// This is not a pretty workaround, but we don't have any better possibilities...
30+
static void zai_resolver_force_space(HashTable *ht) {
31+
// Assuming files don't declare more than a thousand functions
32+
const int reserved = 1000;
33+
34+
while (ht->nTableSize < reserved + ht->nNumOfElements) {
35+
// A rehash happens when all elements are used. The rehash also resets the nNumUsed.
36+
// However, all ht entries within nNumUsed are required to have a valid value.
37+
memset(ht->arData + ht->nNumUsed, IS_UNDEF, (ht->nTableSize - ht->nNumUsed) * sizeof(Bucket));
38+
ht->nNumUsed = ht->nTableSize;
39+
ht->nNumOfElements += reserved;
40+
dtor_func_t dtor = ht->pDestructor;
41+
ht->pDestructor = NULL;
42+
zend_hash_index_add_ptr(ht, 0, NULL);
43+
zend_hash_index_del(ht, 0);
44+
ht->pDestructor = dtor;
45+
ht->nNumOfElements -= reserved;
46+
}
47+
}
48+
#endif
49+
2750
static zend_op_array *(*prev_compile_file)(zend_file_handle *file_handle, int type);
2851
static zend_op_array *zai_interceptor_compile_file(zend_file_handle *file_handle, int type) {
52+
#if PHP_VERSION_ID >= 70200
53+
zai_resolver_force_space(CG(class_table));
54+
zai_resolver_force_space(CG(function_table));
55+
#endif
56+
2957
HashPosition classpos, funcpos;
3058
zend_hash_internal_pointer_end_ex(CG(class_table), &classpos);
3159
uint32_t class_iter = zend_hash_iterator_add(CG(class_table), classpos);

zend_abstract_interface/interceptor/php8/resolver_pre-8_2.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,32 @@ static void zai_interceptor_add_new_entries(HashPosition classpos, HashPosition
2525
}
2626
}
2727

28+
// Work around https://github.com/php/php-src/issues/11222
29+
// This is not a pretty workaround, but we don't have any better possibilities...
30+
static void zai_resolver_force_space(HashTable *ht) {
31+
// Assuming files don't declare more than a thousand functions
32+
const int reserved = 1000;
33+
34+
while (ht->nTableSize < reserved + ht->nNumOfElements) {
35+
// A rehash happens when all elements are used. The rehash also resets the nNumUsed.
36+
// However, all ht entries within nNumUsed are required to have a valid value.
37+
memset(ht->arData + ht->nNumUsed, IS_UNDEF, (ht->nTableSize - ht->nNumUsed) * sizeof(Bucket));
38+
ht->nNumUsed = ht->nTableSize;
39+
ht->nNumOfElements += reserved;
40+
dtor_func_t dtor = ht->pDestructor;
41+
ht->pDestructor = NULL;
42+
zend_hash_index_add_ptr(ht, 0, NULL);
43+
zend_hash_index_del(ht, 0);
44+
ht->pDestructor = dtor;
45+
ht->nNumOfElements -= reserved;
46+
}
47+
}
48+
2849
static zend_op_array *(*prev_compile_file)(zend_file_handle *file_handle, int type);
2950
static zend_op_array *zai_interceptor_compile_file(zend_file_handle *file_handle, int type) {
51+
zai_resolver_force_space(CG(class_table));
52+
zai_resolver_force_space(CG(function_table));
53+
3054
HashPosition classpos, funcpos;
3155
zend_hash_internal_pointer_end_ex(CG(class_table), &classpos);
3256
uint32_t class_iter = zend_hash_iterator_add(CG(class_table), classpos);

0 commit comments

Comments
 (0)