Skip to content

Commit 0e88f74

Browse files
committed
Merge branch 'PHP-8.1'
2 parents 83d96d6 + 85b669e commit 0e88f74

File tree

8 files changed

+111
-115
lines changed

8 files changed

+111
-115
lines changed

Zend/zend.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,8 +1232,6 @@ ZEND_API void zend_deactivate(void) /* {{{ */
12321232
/* we're no longer executing anything */
12331233
EG(current_execute_data) = NULL;
12341234

1235-
zend_observer_deactivate();
1236-
12371235
zend_try {
12381236
shutdown_scanner();
12391237
} zend_end_try();

Zend/zend_extensions.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,17 @@ ZEND_API int zend_get_resource_handle(const char *module_name)
267267

268268
ZEND_API int zend_get_op_array_extension_handle(const char *module_name)
269269
{
270+
int handle = zend_op_array_extension_handles++;
270271
zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
271-
return zend_op_array_extension_handles++;
272+
return handle;
273+
}
274+
275+
ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles)
276+
{
277+
int handle = zend_op_array_extension_handles;
278+
zend_op_array_extension_handles += handles;
279+
zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
280+
return handle;
272281
}
273282

274283
ZEND_API zend_extension *zend_get_extension(const char *extension_name)

Zend/zend_extensions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ extern ZEND_API int zend_op_array_extension_handles;
115115

116116
ZEND_API int zend_get_resource_handle(const char *module_name);
117117
ZEND_API int zend_get_op_array_extension_handle(const char *module_name);
118+
ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles);
118119
ZEND_API void zend_extension_dispatch_message(int message, void *arg);
119120
END_EXTERN_C()
120121

Zend/zend_observer.c

Lines changed: 94 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,6 @@
3131
#define ZEND_OBSERVABLE_FN(fn_flags) \
3232
(!(fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3333

34-
typedef struct _zend_observer_fcall_data {
35-
// points after the last handler
36-
zend_observer_fcall_handlers *end;
37-
// a variadic array using "struct hack"
38-
zend_observer_fcall_handlers handlers[1];
39-
} zend_observer_fcall_data;
40-
4134
zend_llist zend_observers_fcall_list;
4235
zend_llist zend_observer_error_callbacks;
4336
zend_llist zend_observer_fiber_init;
@@ -46,33 +39,18 @@ zend_llist zend_observer_fiber_destroy;
4639

4740
int zend_observer_fcall_op_array_extension;
4841

49-
ZEND_TLS zend_arena *fcall_handlers_arena;
5042
ZEND_TLS zend_execute_data *first_observed_frame;
5143
ZEND_TLS zend_execute_data *current_observed_frame;
5244

5345
// Call during minit/startup ONLY
54-
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init) {
55-
if (!ZEND_OBSERVER_ENABLED) {
56-
/* We don't want to get an extension handle unless an ext installs an observer */
57-
zend_observer_fcall_op_array_extension =
58-
zend_get_op_array_extension_handle("Zend Observer");
59-
60-
/* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
61-
* is called before any extensions have registered as an observer. So we
62-
* adjust the offset to the observed handler when we know we need to observe. */
63-
ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op));
64-
65-
/* ZEND_HANDLE_EXCEPTION also has SPEC(OBSERVER) and no observer extensions
66-
* exist when zend_init_exception_op() is called. */
67-
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op));
68-
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+1);
69-
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+2);
70-
}
46+
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init)
47+
{
7148
zend_llist_add_element(&zend_observers_fcall_list, &init);
7249
}
7350

7451
// Called by engine before MINITs
75-
ZEND_API void zend_observer_startup(void) {
52+
ZEND_API void zend_observer_startup(void)
53+
{
7654
zend_llist_init(&zend_observers_fcall_list, sizeof(zend_observer_fcall_init), NULL, 1);
7755
zend_llist_init(&zend_observer_error_callbacks, sizeof(zend_observer_error_cb), NULL, 1);
7856
zend_llist_init(&zend_observer_fiber_init, sizeof(zend_observer_fiber_init_handler), NULL, 1);
@@ -82,112 +60,117 @@ ZEND_API void zend_observer_startup(void) {
8260
zend_observer_fcall_op_array_extension = -1;
8361
}
8462

85-
ZEND_API void zend_observer_activate(void) {
86-
if (ZEND_OBSERVER_ENABLED) {
87-
fcall_handlers_arena = zend_arena_create(4096);
88-
} else {
89-
fcall_handlers_arena = NULL;
63+
ZEND_API void zend_observer_post_startup(void)
64+
{
65+
if (zend_observers_fcall_list.count) {
66+
/* We don't want to get an extension handle unless an ext installs an observer
67+
* Allocate each a begin and an end pointer */
68+
zend_observer_fcall_op_array_extension =
69+
zend_get_op_array_extension_handles("Zend Observer", (int) zend_observers_fcall_list.count * 2);
70+
71+
/* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
72+
* is called before any extensions have registered as an observer. So we
73+
* adjust the offset to the observed handler when we know we need to observe. */
74+
ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op));
75+
76+
/* ZEND_HANDLE_EXCEPTION also has SPEC(OBSERVER) and no observer extensions
77+
* exist when zend_init_exception_op() is called. */
78+
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op));
79+
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op) + 1);
80+
ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op) + 2);
9081
}
82+
}
83+
84+
ZEND_API void zend_observer_activate(void)
85+
{
9186
first_observed_frame = NULL;
9287
current_observed_frame = NULL;
9388
}
9489

95-
ZEND_API void zend_observer_deactivate(void) {
96-
if (fcall_handlers_arena) {
97-
zend_arena_destroy(fcall_handlers_arena);
98-
}
90+
ZEND_API void zend_observer_deactivate(void)
91+
{
92+
// now empty and unused, but kept for ABI compatibility
9993
}
10094

101-
ZEND_API void zend_observer_shutdown(void) {
95+
ZEND_API void zend_observer_shutdown(void)
96+
{
10297
zend_llist_destroy(&zend_observers_fcall_list);
10398
zend_llist_destroy(&zend_observer_error_callbacks);
10499
zend_llist_destroy(&zend_observer_fiber_init);
105100
zend_llist_destroy(&zend_observer_fiber_switch);
106101
zend_llist_destroy(&zend_observer_fiber_destroy);
107102
}
108103

109-
static void zend_observer_fcall_install(zend_execute_data *execute_data) {
110-
zend_llist_element *element;
104+
static void zend_observer_fcall_install(zend_execute_data *execute_data)
105+
{
111106
zend_llist *list = &zend_observers_fcall_list;
112107
zend_function *function = execute_data->func;
113108
zend_op_array *op_array = &function->op_array;
114109

115-
if (fcall_handlers_arena == NULL) {
116-
return;
117-
}
118-
119110
ZEND_ASSERT(function->type != ZEND_INTERNAL_FUNCTION);
120111

121-
zend_llist handlers_list;
122-
zend_llist_init(&handlers_list, sizeof(zend_observer_fcall_handlers), NULL, 0);
123-
for (element = list->head; element; element = element->next) {
112+
ZEND_ASSERT(RUN_TIME_CACHE(op_array));
113+
zend_observer_fcall_begin_handler *begin_handlers = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(op_array);
114+
zend_observer_fcall_end_handler *end_handlers = (zend_observer_fcall_end_handler *)begin_handlers + list->count, *end_handlers_start = end_handlers;
115+
116+
*begin_handlers = ZEND_OBSERVER_NOT_OBSERVED;
117+
*end_handlers = ZEND_OBSERVER_NOT_OBSERVED;
118+
119+
for (zend_llist_element *element = list->head; element; element = element->next) {
124120
zend_observer_fcall_init init;
125121
memcpy(&init, element->data, sizeof init);
126122
zend_observer_fcall_handlers handlers = init(execute_data);
127-
if (handlers.begin || handlers.end) {
128-
zend_llist_add_element(&handlers_list, &handlers);
123+
if (handlers.begin) {
124+
*(begin_handlers++) = handlers.begin;
129125
}
130-
}
131-
132-
ZEND_ASSERT(RUN_TIME_CACHE(op_array));
133-
void *ext;
134-
if (handlers_list.count) {
135-
size_t size = sizeof(zend_observer_fcall_data) + (handlers_list.count - 1) * sizeof(zend_observer_fcall_handlers);
136-
zend_observer_fcall_data *fcall_data = zend_arena_alloc(&fcall_handlers_arena, size);
137-
zend_observer_fcall_handlers *handlers = fcall_data->handlers;
138-
for (element = handlers_list.head; element; element = element->next) {
139-
memcpy(handlers++, element->data, sizeof *handlers);
126+
if (handlers.end) {
127+
*(end_handlers++) = handlers.end;
140128
}
141-
fcall_data->end = handlers;
142-
ext = fcall_data;
143-
} else {
144-
ext = ZEND_OBSERVER_NOT_OBSERVED;
145129
}
146-
147-
ZEND_OBSERVER_DATA(op_array) = ext;
148-
zend_llist_destroy(&handlers_list);
130+
131+
// end handlers are executed in reverse order
132+
for (--end_handlers; end_handlers_start < end_handlers; --end_handlers, ++end_handlers_start) {
133+
zend_observer_fcall_end_handler tmp = *end_handlers;
134+
*end_handlers = *end_handlers_start;
135+
*end_handlers_start = tmp;
136+
}
149137
}
150138

151139
static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_data)
152140
{
153-
zend_op_array *op_array;
154-
uint32_t fn_flags;
155-
zend_observer_fcall_data *fcall_data;
156-
zend_observer_fcall_handlers *handlers, *end;
157-
158141
if (!ZEND_OBSERVER_ENABLED) {
159142
return;
160143
}
161144

162-
op_array = &execute_data->func->op_array;
163-
fn_flags = op_array->fn_flags;
145+
zend_op_array *op_array = &execute_data->func->op_array;
146+
uint32_t fn_flags = op_array->fn_flags;
164147

165148
if (!ZEND_OBSERVABLE_FN(fn_flags)) {
166149
return;
167150
}
168151

169-
fcall_data = ZEND_OBSERVER_DATA(op_array);
170-
if (!fcall_data) {
152+
zend_observer_fcall_begin_handler *handler = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(op_array);
153+
if (!*handler) {
171154
zend_observer_fcall_install(execute_data);
172-
fcall_data = ZEND_OBSERVER_DATA(op_array);
173155
}
174156

175-
ZEND_ASSERT(fcall_data);
176-
if (fcall_data == ZEND_OBSERVER_NOT_OBSERVED) {
177-
return;
178-
}
157+
zend_observer_fcall_begin_handler *possible_handlers_end = handler + zend_observers_fcall_list.count;
179158

180-
if (first_observed_frame == NULL) {
181-
first_observed_frame = execute_data;
159+
zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)possible_handlers_end;
160+
if (*end_handler != ZEND_OBSERVER_NOT_OBSERVED) {
161+
if (first_observed_frame == NULL) {
162+
first_observed_frame = execute_data;
163+
}
164+
current_observed_frame = execute_data;
182165
}
183-
current_observed_frame = execute_data;
184166

185-
end = fcall_data->end;
186-
for (handlers = fcall_data->handlers; handlers != end; ++handlers) {
187-
if (handlers->begin) {
188-
handlers->begin(execute_data);
189-
}
167+
if (*handler == ZEND_OBSERVER_NOT_OBSERVED) {
168+
return;
190169
}
170+
171+
do {
172+
(*handler)(execute_data);
173+
} while (++handler != possible_handlers_end && *handler != NULL);
191174
}
192175

193176
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(zend_execute_data *execute_data)
@@ -203,43 +186,48 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
203186
}
204187
}
205188

206-
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(
207-
zend_execute_data *execute_data,
208-
zval *return_value)
189+
static inline bool zend_observer_is_skipped_frame(zend_execute_data *execute_data) {
190+
zend_function *func = execute_data->func;
191+
192+
if (!func || func->type == ZEND_INTERNAL_FUNCTION || !ZEND_OBSERVABLE_FN(func->common.fn_flags)) {
193+
return true;
194+
}
195+
196+
zend_observer_fcall_end_handler end_handler = (&ZEND_OBSERVER_DATA(&func->op_array))[zend_observers_fcall_list.count];
197+
if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED) {
198+
return true;
199+
}
200+
201+
return false;
202+
}
203+
204+
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_data, zval *return_value)
209205
{
210206
zend_function *func = execute_data->func;
211-
zend_observer_fcall_data *fcall_data;
212-
zend_observer_fcall_handlers *handlers, *end;
213207

214208
if (!ZEND_OBSERVER_ENABLED
215209
|| !ZEND_OBSERVABLE_FN(func->common.fn_flags)) {
216210
return;
217211
}
218212

219-
fcall_data = (zend_observer_fcall_data*)ZEND_OBSERVER_DATA(&func->op_array);
213+
zend_observer_fcall_end_handler *handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(&func->op_array) + zend_observers_fcall_list.count;
220214
// TODO: Fix exceptions from generators
221215
// ZEND_ASSERT(fcall_data);
222-
if (!fcall_data || fcall_data == ZEND_OBSERVER_NOT_OBSERVED) {
216+
if (!*handler || *handler == ZEND_OBSERVER_NOT_OBSERVED) {
223217
return;
224218
}
225219

226-
handlers = fcall_data->end;
227-
end = fcall_data->handlers;
228-
while (handlers-- != end) {
229-
if (handlers->end) {
230-
handlers->end(execute_data, return_value);
231-
}
232-
}
220+
zend_observer_fcall_end_handler *possible_handlers_end = handler + zend_observers_fcall_list.count;
221+
do {
222+
(*handler)(execute_data, return_value);
223+
} while (++handler != possible_handlers_end && *handler != NULL);
233224

234225
if (first_observed_frame == execute_data) {
235226
first_observed_frame = NULL;
236227
current_observed_frame = NULL;
237228
} else {
238229
zend_execute_data *ex = execute_data->prev_execute_data;
239-
while (ex && (!ex->func || ex->func->type == ZEND_INTERNAL_FUNCTION
240-
|| !ZEND_OBSERVABLE_FN(ex->func->common.fn_flags)
241-
|| !ZEND_OBSERVER_DATA(&ex->func->op_array)
242-
|| ZEND_OBSERVER_DATA(&ex->func->op_array) == ZEND_OBSERVER_NOT_OBSERVED)) {
230+
while (ex && zend_observer_is_skipped_frame(ex)) {
243231
ex = ex->prev_execute_data;
244232
}
245233
current_observed_frame = ex;
@@ -255,7 +243,6 @@ ZEND_API void zend_observer_fcall_end_all(void)
255243
}
256244
ex = ex->prev_execute_data;
257245
}
258-
current_observed_frame = NULL;
259246
}
260247

261248
ZEND_API void zend_observer_error_register(zend_observer_error_cb cb)
@@ -265,11 +252,8 @@ ZEND_API void zend_observer_error_register(zend_observer_error_cb cb)
265252

266253
void zend_observer_error_notify(int type, zend_string *error_filename, uint32_t error_lineno, zend_string *message)
267254
{
268-
zend_llist_element *element;
269-
zend_observer_error_cb callback;
270-
271-
for (element = zend_observer_error_callbacks.head; element; element = element->next) {
272-
callback = *(zend_observer_error_cb *) (element->data);
255+
for (zend_llist_element *element = zend_observer_error_callbacks.head; element; element = element->next) {
256+
zend_observer_error_cb callback = *(zend_observer_error_cb *) (element->data);
273257
callback(type, error_filename, error_lineno, message);
274258
}
275259
}

Zend/zend_observer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef zend_observer_fcall_handlers (*zend_observer_fcall_init)(zend_execute_da
5757
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init);
5858

5959
ZEND_API void zend_observer_startup(void); // Called by engine before MINITs
60+
ZEND_API void zend_observer_post_startup(void); // Called by engine after MINITs
6061
ZEND_API void zend_observer_activate(void);
6162
ZEND_API void zend_observer_deactivate(void);
6263
ZEND_API void zend_observer_shutdown(void);

ext/zend_test/tests/observer_bug81430_1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
--TEST--
22
Bug #81430 (Attribute instantiation frame accessing invalid frame pointer)
33
--EXTENSIONS--
4-
zend_test
4+
zend-test
55
--INI--
66
memory_limit=20M
77
zend_test.observer.enabled=1

ext/zend_test/tests/observer_bug81430_2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
--TEST--
22
Bug #81430 (Attribute instantiation leaves dangling execute_data pointer)
33
--EXTENSIONS--
4-
zend_test
4+
zend-test
55
--INI--
66
memory_limit=20M
77
zend_test.observer.enabled=1

main/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,6 +2278,9 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
22782278
module->version = PHP_VERSION;
22792279
module->info_func = PHP_MINFO(php_core);
22802280
}
2281+
2282+
/* freeze the list of observer fcall_init handlers */
2283+
zend_observer_post_startup();
22812284

22822285
/* Extensions that add engine hooks after this point do so at their own peril */
22832286
zend_finalize_system_id();

0 commit comments

Comments
 (0)