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
308313void 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