diff --git a/dd-java-agent/instrumentation/websocket/javax-websocket-1.0/src/main/java/datadog/trace/instrumentation/websocket/jsr256/TracingSendHandler.java b/dd-java-agent/instrumentation/websocket/javax-websocket-1.0/src/main/java/datadog/trace/instrumentation/websocket/jsr256/TracingSendHandler.java index c5a582859a3..62712b15592 100644 --- a/dd-java-agent/instrumentation/websocket/javax-websocket-1.0/src/main/java/datadog/trace/instrumentation/websocket/jsr256/TracingSendHandler.java +++ b/dd-java-agent/instrumentation/websocket/javax-websocket-1.0/src/main/java/datadog/trace/instrumentation/websocket/jsr256/TracingSendHandler.java @@ -21,7 +21,7 @@ public TracingSendHandler(SendHandler delegate, HandlerContext handlerContext) { @Override public void onResult(SendResult sendResult) { final AgentSpan wsSpan = handlerContext.getWebsocketSpan(); - try (final ContextScope ignored = activateSpan(wsSpan)) { + try (final ContextScope ignored = wsSpan != null ? activateSpan(wsSpan) : null) { delegate.onResult(sendResult); } finally { if (sendResult.getException() != null) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java b/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java index 33e6580574e..56d36a180af 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java @@ -113,6 +113,11 @@ private AgentScope activate( final byte source, final boolean overrideAsyncPropagation, final boolean isAsyncPropagating) { + if (span == null) { + log.debug(SEND_TELEMETRY, "Attempted to activate a null span. Returning NoopScope."); + return INVALID_SCOPE; + } + ScopeStack scopeStack = scopeStack(); final ContinuableScope top = scopeStack.top; @@ -131,8 +136,6 @@ private AgentScope activate( } } - assert span != null; - // Inherit the async propagation from the active scope unless the value is overridden boolean asyncPropagation = overrideAsyncPropagation diff --git a/dd-trace-core/src/test/java/datadog/trace/core/scopemanager/ScopeManagerForkedTest.java b/dd-trace-core/src/test/java/datadog/trace/core/scopemanager/ScopeManagerForkedTest.java index dc683942549..f3c4a101dce 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/scopemanager/ScopeManagerForkedTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/scopemanager/ScopeManagerForkedTest.java @@ -36,6 +36,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.bootstrap.instrumentation.api.NoopScope; import datadog.trace.bootstrap.instrumentation.api.ProfilingContextIntegration; import datadog.trace.common.writer.ListWriter; import datadog.trace.core.CoreTracer; @@ -124,6 +125,27 @@ void nonDdspanActivationResultsInAContinuableScope() { assertNull(scopeManager.active()); } + @Test + void activatingNullSpanReturnsNoopScopeAndDoesNotCorruptStack() { + AgentScope nullScope = scopeManager.activateSpan(null); + + assertInstanceOf(NoopScope.class, nullScope); + assertNull(scopeManager.active()); + + nullScope.close(); + + // a subsequent activation on the same thread must not NPE, even though the noop + // activation above never pushed a scope with a null context onto the stack + AgentSpan span = tracer.buildSpan("test", "test").start(); + AgentScope scope = tracer.activateSpan(span); + + assertSame(scope, scopeManager.active()); + assertSame(span, scope.span()); + + scope.close(); + span.finish(); + } + @Test void noScopeIsActiveBeforeActivation() throws Exception { tracer.buildSpan("test", "test").start();