From 98e31eaaed5501b921b0974e7d379ee31a0275d3 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Fri, 29 May 2026 09:13:48 +0200 Subject: [PATCH 1/2] Add dynamic_service DBM propagation mode --- ext/configuration.c | 2 + ext/configuration.h | 1 + ext/ddtrace.stub.php | 6 +++ ext/ddtrace_arginfo.h | 3 +- .../DatabaseIntegrationHelper.php | 6 ++- tests/Integration/DatabaseMonitoringTest.php | 45 +++++++++++++++++++ 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/ext/configuration.c b/ext/configuration.c index 7714360cebf..4abda69e963 100644 --- a/ext/configuration.c +++ b/ext/configuration.c @@ -76,6 +76,8 @@ static bool dd_parse_dbm_mode(zai_str value, zval *decoded_value, bool persisten ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_SERVICE); } else if (zai_str_eq_ci_cstr(value, "full")) { ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_FULL); + } else if (zai_str_eq_ci_cstr(value, "dynamic_service")) { + ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_DYNAMIC_SERVICE); } else { return false; } diff --git a/ext/configuration.h b/ext/configuration.h index 0fafcc56b1a..f0828bc22fd 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -22,6 +22,7 @@ enum ddtrace_dbm_propagation_mode { DD_TRACE_DBM_PROPAGATION_DISABLED, DD_TRACE_DBM_PROPAGATION_SERVICE, DD_TRACE_DBM_PROPAGATION_FULL, + DD_TRACE_DBM_PROPAGATION_DYNAMIC_SERVICE, }; // To remove in 1.0 diff --git a/ext/ddtrace.stub.php b/ext/ddtrace.stub.php index ee00a8ee3b2..b94b16c3285 100644 --- a/ext/ddtrace.stub.php +++ b/ext/ddtrace.stub.php @@ -23,6 +23,12 @@ */ const DBM_PROPAGATION_FULL = UNKNOWN; + /** + * @var int + * @cvalue DD_TRACE_DBM_PROPAGATION_DYNAMIC_SERVICE + */ + const DBM_PROPAGATION_DYNAMIC_SERVICE = UNKNOWN; + /** * @var int * @cvalue DDTRACE_FFE_TYPE_STRING diff --git a/ext/ddtrace_arginfo.h b/ext/ddtrace_arginfo.h index 9722e64a323..4742822d095 100644 --- a/ext/ddtrace_arginfo.h +++ b/ext/ddtrace_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit ddtrace.stub.php instead. - * Stub hash: 8d552cbb5a25472ccb510275ab86276a29e85d7a */ + * Stub hash: b3087c1f239d5aa8ea38f875b7236f47e56a1ca7 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_trace_method, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, className, IS_STRING, 0) @@ -593,6 +593,7 @@ static void register_ddtrace_symbols(int module_number) REGISTER_LONG_CONSTANT("DDTrace\\DBM_PROPAGATION_DISABLED", DD_TRACE_DBM_PROPAGATION_DISABLED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DDTrace\\DBM_PROPAGATION_SERVICE", DD_TRACE_DBM_PROPAGATION_SERVICE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DDTrace\\DBM_PROPAGATION_FULL", DD_TRACE_DBM_PROPAGATION_FULL, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("DDTrace\\DBM_PROPAGATION_DYNAMIC_SERVICE", DD_TRACE_DBM_PROPAGATION_DYNAMIC_SERVICE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DDTrace\\FFE_STRING", DDTRACE_FFE_TYPE_STRING, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DDTrace\\FFE_INT", DDTRACE_FFE_TYPE_INT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("DDTrace\\FFE_FLOAT", DDTRACE_FFE_TYPE_FLOAT, CONST_PERSISTENT); diff --git a/src/DDTrace/Integrations/DatabaseIntegrationHelper.php b/src/DDTrace/Integrations/DatabaseIntegrationHelper.php index 59a96f4870f..1283e80e80c 100644 --- a/src/DDTrace/Integrations/DatabaseIntegrationHelper.php +++ b/src/DDTrace/Integrations/DatabaseIntegrationHelper.php @@ -49,7 +49,8 @@ public static function injectDatabaseIntegrationData(HookData $hook, $backend, $ $peerService = $span->meta['peer.service'] ?? ''; // Inject base hash into span tags if enabled - if (dd_trace_env_config("DD_DBM_INJECT_SQL_BASEHASH")) { + if (dd_trace_env_config("DD_DBM_INJECT_SQL_BASEHASH") + || $propagationMode == \DDTrace\DBM_PROPAGATION_DYNAMIC_SERVICE) { $baseHash = \DDTrace\System\process_tags_base_hash(); if ($baseHash !== null) { $span->meta[Tag::PROPAGATED_HASH] = $baseHash; @@ -136,7 +137,8 @@ public static function propagateViaSqlComments( } // Inject base hash into SQL comment if enabled - if (dd_trace_env_config("DD_DBM_INJECT_SQL_BASEHASH")) { + if (dd_trace_env_config("DD_DBM_INJECT_SQL_BASEHASH") + || $mode == \DDTrace\DBM_PROPAGATION_DYNAMIC_SERVICE) { $baseHash = \DDTrace\System\process_tags_base_hash(); if ($baseHash !== null) { $tags["ddsh"] = $baseHash; diff --git a/tests/Integration/DatabaseMonitoringTest.php b/tests/Integration/DatabaseMonitoringTest.php index d95539882c2..1a1911b7ccf 100644 --- a/tests/Integration/DatabaseMonitoringTest.php +++ b/tests/Integration/DatabaseMonitoringTest.php @@ -407,4 +407,49 @@ public function testBaseHashNotInjectedWhenDisabled() ]) ]); } + + public function testDynamicServiceMode() + { + // dynamic_service is equivalent to service + DD_DBM_INJECT_SQL_BASEHASH=true: + // service-style comment (no traceparent) plus the base hash, even though + // DD_DBM_INJECT_SQL_BASEHASH is left unset. + self::putEnv('DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=true'); + self::putEnv('DD_DBM_PROPAGATION_MODE=dynamic_service'); + self::putEnv('DD_TRACE_DEBUG_PRNG_SEED=42'); + + \dd_trace_internal_fn('reload_process_tags'); + \dd_trace_internal_fn('set_container_tags_hash', 'abc123'); + + try { + $hook = \DDTrace\install_hook(self::class . "::instrumented", function (HookData $hook) { + $hook->span()->service = "testdb"; + $hook->span()->name = "instrumented"; + DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql', 1); + }); + + $this->assertNotNull(\DDTrace\System\process_tags_base_hash(), 'process_tags_base_hash() is null'); + + $traces = $this->isolateTracer(function () use (&$commentedQuery) { + \DDTrace\start_trace_span(); + $commentedQuery = $this->instrumented(0, "SELECT 1"); + \DDTrace\close_span(); + }); + } finally { + \DDTrace\remove_hook($hook); + } + + // service-style: a ddsh base hash is injected, but no traceparent + $this->assertRegularExpression( + '/^\/\*dddbs=\'testdb\',ddps=\'phpunit\',ddsh=\'[0-9a-f]+\'\*\/ SELECT 1$/', + $commentedQuery + ); + + $ddshValue = preg_replace('/^.*ddsh=\'([^\']+)\'.*$/', '$1', $commentedQuery); + $propagatedHash = $traces[0][1]['meta']['_dd.propagated_hash'] ?? null; + $this->assertNotNull($propagatedHash, '_dd.propagated_hash not found in span'); + $this->assertSame($ddshValue, $propagatedHash, 'ddsh in SQL comment does not match _dd.propagated_hash in span'); + + // dynamic_service is not full mode, so the trace-injected marker must be absent + $this->assertArrayNotHasKey('_dd.dbm_trace_injected', $traces[0][1]['meta']); + } } From 59ce77140dd13e77d81c81554cfd462accc5a99f Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 29 May 2026 15:35:14 +0200 Subject: [PATCH 2/2] Fix use-after-free in set_container_tags_hash test function --- ext/ddtrace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/ddtrace.c b/ext/ddtrace.c index 08cabc95e29..b55d4282674 100644 --- a/ext/ddtrace.c +++ b/ext/ddtrace.c @@ -3284,7 +3284,9 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else if (params_count == 1 && FUNCTION_NAME_MATCHES("set_container_tags_hash")) { zval *container_tags_hash = ZVAL_VARARG_PARAM(params, 0); if (Z_TYPE_P(container_tags_hash) == IS_STRING) { - ddtrace_process_tags_set_container_tags_hash(Z_STR_P(container_tags_hash)); + zend_string *hash = zend_string_dup(Z_STR_P(container_tags_hash), 1); + ddtrace_process_tags_set_container_tags_hash(hash); + zend_string_release(hash); RETVAL_TRUE; } else { RETVAL_FALSE;