Skip to content

Commit 0d2b2ff

Browse files
authored
Merge pull request #3689 from DataDog/glopes/exec-crash
Try to prevent dangling tracked_streams
2 parents 0337bf0 + 5682c31 commit 0d2b2ff

1 file changed

Lines changed: 32 additions & 15 deletions

File tree

ext/integrations/exec_integration.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <sys/wait.h>
66
#endif
77

8+
#include <components/log/log.h>
89
#include <ext/standard/file.h>
910
#include <ext/standard/proc_open.h>
1011

@@ -298,7 +299,11 @@ void ddtrace_exec_handlers_rinit() {
298299
// OTOH ddtrace_exec_handlers_rshutdown is not called when ddtrace is
299300
// disabled because it needs to be called earlier on upon the real rshutodown
300301

301-
if (tracked_streams) {
302+
if (PG(during_request_startup)) {
303+
if (tracked_streams) {
304+
LOG(WARN, "tracked_streams is non-NULL during request startup");
305+
}
306+
} else {
302307
dd_exec_destroy_tracked_streams();
303308
}
304309

@@ -307,21 +312,33 @@ void ddtrace_exec_handlers_rinit() {
307312

308313
void ddtrace_exec_handlers_rshutdown() {
309314
if (tracked_streams) {
310-
zend_ulong h;
311-
zend_string *key;
312-
zval *val;
313-
ZEND_HASH_REVERSE_FOREACH_KEY_VAL(tracked_streams, h, key, val) {
314-
(void)h;
315-
(void)val;
316-
php_stream *stream;
317-
memcpy(&stream, ZSTR_VAL(key), sizeof stream);
318-
// manually close the tracked stream on rshutdown in case they
319-
// lived till the end of the request so we can finish the span
320-
zend_list_close(stream->res);
321-
}
322-
ZEND_HASH_FOREACH_END();
315+
// generally, a bailout during rshutdown would prevent the rest of the
316+
// shutdown from that extension from running.
317+
// Here, we're force-closing streams (the keys of tracked_streams) and
318+
// potentially destroying spans (the values of tracked_streams).
319+
// There is at least one avenue for an error to escape: when executing
320+
// onClose callbacks on spans, if there has already been a PHP timeout,
321+
// the zai sandbox will let the error escape.
322+
zend_try {
323+
zend_ulong h;
324+
zend_string *key;
325+
zval *val;
326+
ZEND_HASH_REVERSE_FOREACH_KEY_VAL(tracked_streams, h, key, val) {
327+
(void)h;
328+
(void)val;
329+
php_stream *stream;
330+
memcpy(&stream, ZSTR_VAL(key), sizeof stream);
331+
// manually close the tracked stream on rshutdown in case they
332+
// lived till the end of the request so we can finish the span
333+
zend_list_close(stream->res);
334+
}
335+
ZEND_HASH_FOREACH_END();
323336

324-
dd_exec_destroy_tracked_streams();
337+
dd_exec_destroy_tracked_streams();
338+
} zend_catch {
339+
LOG(WARN, "Bailout during tracked_streams destruction");
340+
tracked_streams = NULL;
341+
} zend_end_try();
325342
}
326343

327344
{

0 commit comments

Comments
 (0)