Skip to content

Commit 9794bcb

Browse files
authored
Merge pull request #2990 from DataDog/kikoveiga/RUM-10417/fix-potential-exception
RUM-10417: Handle potential StackOverflowError
2 parents 8f7122f + ff8e241 commit 9794bcb

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

integrations/dd-sdk-android-okhttp/src/main/kotlin/com/datadog/android/okhttp/trace/TracingInterceptor.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,20 @@ internal constructor(
169169
throwable: Throwable?
170170
) {
171171
if (span != null) {
172-
tracedRequestListener.onRequestIntercepted(request, span, response, throwable)
172+
try {
173+
tracedRequestListener.onRequestIntercepted(request, span, response, throwable)
174+
} catch (e: StackOverflowError) {
175+
sdkCore.internalLogger.log(
176+
InternalLogger.Level.ERROR,
177+
InternalLogger.Target.USER,
178+
{
179+
"$ERROR_STACK_OVERFLOW\nRequest: ${request.method}:${request.url}"
180+
},
181+
e
182+
)
183+
@Suppress("ThrowingInternalException")
184+
throw e
185+
}
173186
}
174187
}
175188

@@ -853,6 +866,11 @@ internal constructor(
853866
"but you didn't register any AgentTracer.TracerAPI. " +
854867
"We automatically created a local tracer for you."
855868

869+
internal const val ERROR_STACK_OVERFLOW =
870+
"StackOverflowError detected in TracedRequestListener. " +
871+
"This is likely caused by retrying the same request within the " +
872+
"onRequestIntercepted callback, leading to infinite recursion."
873+
856874
internal const val NETWORK_REQUESTS_TRACKING_FEATURE_NAME = "Network Requests"
857875
internal const val ALL_IN_SAMPLE_RATE: Double = 100.0
858876
internal const val ZERO_SAMPLE_RATE: Float = 0f

integrations/dd-sdk-android-okhttp/src/test/kotlin/com/datadog/android/okhttp/trace/TracingInterceptorTest.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,6 +1659,36 @@ internal open class TracingInterceptorTest {
16591659
verify(mockFuture).get(1, TimeUnit.SECONDS)
16601660
}
16611661

1662+
@Test
1663+
fun `M log error and rethrow W listener causes StackOverflowError`(
1664+
@IntForgery(min = 200, max = 600) statusCode: Int
1665+
) {
1666+
// Given
1667+
whenever(mockResolver.isFirstPartyUrl(fakeUrl.toHttpUrl())).thenReturn(true)
1668+
stubChain(mockChain, statusCode)
1669+
1670+
whenever(
1671+
mockRequestListener.onRequestIntercepted(any(), any(), anyOrNull(), anyOrNull())
1672+
).doAnswer { throw StackOverflowError() }
1673+
1674+
// When
1675+
assertThrows<StackOverflowError> {
1676+
testedInterceptor.intercept(mockChain)
1677+
}
1678+
1679+
// Then
1680+
val expectedMessage = "${TracingInterceptor.ERROR_STACK_OVERFLOW}\n" +
1681+
"Request: ${fakeRequest.method}:${fakeRequest.url}"
1682+
1683+
mockInternalLogger.verifyLog(
1684+
InternalLogger.Level.ERROR,
1685+
InternalLogger.Target.USER,
1686+
expectedMessage,
1687+
StackOverflowError::class.java,
1688+
mode = org.mockito.kotlin.atLeast(1)
1689+
)
1690+
}
1691+
16621692
// region Internal
16631693

16641694
internal fun stubChain(chain: Interceptor.Chain, statusCode: Int) {

0 commit comments

Comments
 (0)