Skip to content

Commit f3d6437

Browse files
committed
Add an integration test for the case 19196
1 parent 07039f0 commit f3d6437

File tree

3 files changed

+137
-1
lines changed

3 files changed

+137
-1
lines changed

tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/TraceAnnotationsTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected TraceAnnotationsTests(string sampleAppName, bool enableTelemetry, ITes
7878
[SkippableFact]
7979
public async Task SubmitTraces()
8080
{
81-
const int expectedSpanCount = 51;
81+
const int expectedSpanCount = 52;
8282
var ddTraceMethodsString = string.Empty;
8383

8484
foreach (var type in TestTypes)
@@ -88,6 +88,10 @@ public async Task SubmitTraces()
8888

8989
ddTraceMethodsString += ";Samples.TraceAnnotations.ExtensionMethods[ExtensionMethodForTestType,ExtensionMethodForTestTypeGeneric,ExtensionMethodForTestTypeTypeStruct];System.Net.Http.HttpRequestMessage[set_Method]";
9090

91+
// Add method with extreme exception handling nesting (APMS-19196 regression test)
92+
// Must target the sync method which has the EH directly in its body (not in an async state machine)
93+
ddTraceMethodsString += ";Samples.TraceAnnotations.ExtremeExceptionHandling[DeepNestedExceptionHandlingSync]";
94+
9195
SetEnvironmentVariable("DD_TRACE_METHODS", ddTraceMethodsString);
9296
// Don't bother with telemetry in version mismatch scenarios because older versions may only support V1 telemetry
9397
// which we no longer support in our mock telemetry agent
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace Samples.TraceAnnotations
5+
{
6+
/// <summary>
7+
/// Test class with deeply nested try/catch/finally patterns that triggered
8+
/// a bug in the IL rewriter's exception handler sorting logic (APMS-19196).
9+
/// </summary>
10+
public static class ExtremeExceptionHandling
11+
{
12+
private static int _counter = 0;
13+
14+
/// <summary>
15+
/// Async wrapper that calls the sync method with deep EH nesting.
16+
/// </summary>
17+
public static async Task<string> DeepNestedExceptionHandlingAsync()
18+
{
19+
await Task.Yield();
20+
return DeepNestedExceptionHandlingSync();
21+
}
22+
23+
/// <summary>
24+
/// Synchronous method with 9 levels of nested try/catch/finally.
25+
/// This pattern triggers the EH clause sorting bug when instrumented.
26+
/// The EH is directly in this method (not in a state machine).
27+
/// </summary>
28+
public static string DeepNestedExceptionHandlingSync()
29+
{
30+
var requestId = System.Threading.Interlocked.Increment(ref _counter);
31+
32+
try
33+
{
34+
// Level 1
35+
try
36+
{
37+
Console.WriteLine($"[L1] {requestId}");
38+
39+
// Level 5 (skipping L2,L3,L4 - the crashing pattern!)
40+
try
41+
{
42+
Console.WriteLine($"[L5] {requestId}");
43+
44+
// Level 6
45+
try
46+
{
47+
Console.WriteLine($"[L6] {requestId}");
48+
49+
// Level 7
50+
try
51+
{
52+
Console.WriteLine($"[L7] {requestId}");
53+
54+
// Level 8
55+
try
56+
{
57+
Console.WriteLine($"[L8] {requestId}");
58+
59+
// Level 9 - THE CRASH TRIGGER
60+
try
61+
{
62+
Console.WriteLine($"[L9] {requestId}");
63+
System.Threading.Thread.Sleep(1);
64+
Console.WriteLine($"[L9] Success {requestId}");
65+
}
66+
catch (Exception l9Ex)
67+
{
68+
Console.WriteLine($"[L9] Exception: {l9Ex.GetType().Name}");
69+
}
70+
finally
71+
{
72+
Console.WriteLine($"[L9] Finally {requestId}");
73+
}
74+
}
75+
catch (Exception l8Ex)
76+
{
77+
Console.WriteLine($"[L8] Exception: {l8Ex.GetType().Name}");
78+
}
79+
finally
80+
{
81+
Console.WriteLine($"[L8] Finally {requestId}");
82+
}
83+
}
84+
catch (Exception l7Ex)
85+
{
86+
Console.WriteLine($"[L7] Exception: {l7Ex.GetType().Name}");
87+
}
88+
finally
89+
{
90+
Console.WriteLine($"[L7] Finally {requestId}");
91+
}
92+
}
93+
catch (Exception l6Ex)
94+
{
95+
Console.WriteLine($"[L6] Exception: {l6Ex.GetType().Name}");
96+
}
97+
finally
98+
{
99+
Console.WriteLine($"[L6] Finally {requestId}");
100+
}
101+
}
102+
catch (Exception l5Ex)
103+
{
104+
Console.WriteLine($"[L5] Exception: {l5Ex.GetType().Name}");
105+
}
106+
finally
107+
{
108+
Console.WriteLine($"[L5] Finally {requestId}");
109+
}
110+
}
111+
finally
112+
{
113+
Console.WriteLine($"[L1] Finally {requestId}");
114+
}
115+
}
116+
catch (Exception rootEx)
117+
{
118+
Console.WriteLine($"[ROOT] Exception: {rootEx.GetType().Name}");
119+
}
120+
finally
121+
{
122+
Console.WriteLine($"[ROOT] Finally {requestId}");
123+
}
124+
125+
return $"Success {requestId}";
126+
}
127+
}
128+
}

tracer/test/test-applications/integrations/Samples.TraceAnnotations/ProgramHelpers.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ public static async Task RunTestsAsync()
133133
await WaitUsingOfficialAttribute();
134134
await NewRelicTransactionMethodAsync("Hello World");
135135
NewRelicTraceMethod(42);
136+
137+
// Test extreme exception handling patterns (APMS-19196 regression test)
138+
// This exercises the IL rewriter with complex try/catch/finally nesting
139+
await ExtremeExceptionHandling.DeepNestedExceptionHandlingAsync();
136140
}
137141

138142
[OfficialTrace(OperationName = "overridden.attribute", ResourceName = "Program_WaitUsingOfficialAttribute")]

0 commit comments

Comments
 (0)