From 8991876588bf5962d481f67c49c7093f607a1696 Mon Sep 17 00:00:00 2001 From: Dani Jimenez Date: Tue, 2 Jun 2026 13:27:04 +0200 Subject: [PATCH] Guard span baggage inheritance against malformed parent zval ddtrace_inherit_span_properties copies the parent span's baggage property with ZVAL_COPY_DEREF, which runs GC_ADDREF unconditionally when the source is flagged refcounted. When the parent baggage zval carries the refcounted flag but a NULL counted pointer, GC_ADDREF dereferences NULL and the process takes a SIGSEGV during span creation. Skip the copy and fall back to the property's declared empty-array default when the source zval is in that broken state. Valid baggage is unaffected. Signed-off-by: Dani Jimenez --- ext/serializer.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ext/serializer.c b/ext/serializer.c index b9ec42a951..e2b2714e42 100644 --- a/ext/serializer.c +++ b/ext/serializer.c @@ -723,6 +723,14 @@ static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtr } } +// Detects a zval that is flagged as refcounted but carries a NULL counted +// pointer. Copying such a zval with ZVAL_COPY_DEREF dereferences NULL inside +// GC_ADDREF and crashes the process. +static zend_always_inline bool dd_zval_is_broken_refcounted(zval *zv) { + ZVAL_DEREF(zv); + return Z_REFCOUNTED_P(zv) && Z_COUNTED_P(zv) == NULL; +} + void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data *parent) { zval *prop_service = &span->property_service; zval_ptr_dtor(prop_service); @@ -733,7 +741,13 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval *prop_baggage = &span->property_baggage, *prop_parent_baggage = &parent->property_baggage; zval_ptr_dtor(prop_baggage); - ZVAL_COPY_DEREF(prop_baggage, prop_parent_baggage); + if (UNEXPECTED(dd_zval_is_broken_refcounted(prop_parent_baggage))) { + // Fall back to the property's declared default instead of dereferencing + // a NULL refcounted pointer; baggage stays a valid array downstream. + ZVAL_EMPTY_ARRAY(prop_baggage); + } else { + ZVAL_COPY_DEREF(prop_baggage, prop_parent_baggage); + } zend_array *parent_meta = ddtrace_property_array(&parent->property_meta);