Skip to content

[Dynamic Instrumentation] Add NullByRefArgAndLocal test#7987

Merged
dudikeleti merged 2 commits intomasterfrom
dudik/add-nullbyref-test
Jan 21, 2026
Merged

[Dynamic Instrumentation] Add NullByRefArgAndLocal test#7987
dudikeleti merged 2 commits intomasterfrom
dudik/add-nullbyref-test

Conversation

@dudikeleti
Copy link
Contributor

@dudikeleti dudikeleti commented Dec 20, 2025

Summary of changes

Add a new test that uncovers two bugs:

  1. When a null address is passed into our instrumentation code.
  2. When locals or arguments exist but are skipped, resulting in an invalid JSON structure.

Implementation details

When a null address is passed to our debugger invoker classes, it must be handled explicitly by checking Unsafe.IsNullRef.

Other details

The test is currently skipped and will be enabled once the following PRs are merged:
#7986
#7988
#7989

@dudikeleti dudikeleti requested a review from a team as a code owner December 20, 2025 12:10
@github-actions github-actions bot added the area:tests unit tests, integration tests label Dec 20, 2025
@dudikeleti dudikeleti changed the title Add NullByRefArgAndLocal test [Dynamic Instrumentation] Add NullByRefArgAndLocal test Dec 20, 2025
@datadog-datadog-prod-us1

This comment has been minimized.

@dd-trace-dotnet-ci-bot
Copy link

dd-trace-dotnet-ci-bot bot commented Dec 20, 2025

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (7987) and master.

✅ No regressions detected - check the details below

Full Metrics Comparison

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration68.23 ± (68.20 - 68.40) ms68.62 ± (68.69 - 68.92) ms+0.6%✅⬆️
.NET Framework 4.8 - Bailout
duration72.17 ± (72.03 - 72.24) ms72.36 ± (72.39 - 72.62) ms+0.3%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration996.48 ± (1000.93 - 1009.17) ms1007.20 ± (1013.53 - 1024.04) ms+1.1%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms21.83 ± (21.81 - 21.86) ms21.94 ± (21.92 - 21.97) ms+0.5%✅⬆️
process.time_to_main_ms78.73 ± (78.56 - 78.90) ms79.72 ± (79.53 - 79.91) ms+1.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.89 ± (10.88 - 10.89) MB10.91 ± (10.91 - 10.92) MB+0.2%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms21.84 ± (21.82 - 21.86) ms21.86 ± (21.84 - 21.89) ms+0.1%✅⬆️
process.time_to_main_ms79.84 ± (79.75 - 79.93) ms80.61 ± (80.50 - 80.72) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.92 ± (10.92 - 10.93) MB10.95 ± (10.95 - 10.95) MB+0.3%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms245.51 ± (242.21 - 248.81) ms252.47 ± (249.51 - 255.43) ms+2.8%✅⬆️
process.time_to_main_ms468.64 ± (468.00 - 469.27) ms473.87 ± (473.30 - 474.44) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.35 ± (48.32 - 48.38) MB48.50 ± (48.48 - 48.52) MB+0.3%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms20.73 ± (20.70 - 20.76) ms20.79 ± (20.76 - 20.82) ms+0.3%✅⬆️
process.time_to_main_ms68.38 ± (68.24 - 68.51) ms69.06 ± (68.93 - 69.19) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.59 ± (10.59 - 10.60) MB10.64 ± (10.63 - 10.64) MB+0.4%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms20.61 ± (20.59 - 20.64) ms20.72 ± (20.69 - 20.75) ms+0.5%✅⬆️
process.time_to_main_ms69.10 ± (69.04 - 69.17) ms69.76 ± (69.68 - 69.83) ms+0.9%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.70 ± (10.69 - 10.70) MB10.73 ± (10.72 - 10.73) MB+0.3%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms244.66 ± (242.33 - 246.99) ms246.76 ± (244.47 - 249.05) ms+0.9%✅⬆️
process.time_to_main_ms444.93 ± (444.51 - 445.35) ms450.27 ± (449.64 - 450.90) ms+1.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed49.17 ± (49.14 - 49.20) MB49.17 ± (49.14 - 49.20) MB+0.0%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.1%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms18.70 ± (18.68 - 18.72) ms19.30 ± (19.25 - 19.34) ms+3.2%✅⬆️
process.time_to_main_ms67.06 ± (66.97 - 67.16) ms71.63 ± (71.24 - 72.03) ms+6.8%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.65 ± (7.64 - 7.66) MB7.71 ± (7.70 - 7.72) MB+0.8%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms18.76 ± (18.74 - 18.78) ms19.13 ± (19.09 - 19.16) ms+2.0%✅⬆️
process.time_to_main_ms68.16 ± (68.10 - 68.23) ms70.67 ± (70.55 - 70.79) ms+3.7%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.71 ± (7.70 - 7.71) MB7.74 ± (7.73 - 7.74) MB+0.4%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms177.10 ± (176.22 - 177.98) ms183.71 ± (182.64 - 184.79) ms+3.7%✅⬆️
process.time_to_main_ms429.37 ± (428.74 - 430.00) ms441.49 ± (440.05 - 442.94) ms+2.8%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.58 ± (36.55 - 36.61) MB36.70 ± (36.67 - 36.73) MB+0.3%✅⬆️
runtime.dotnet.threads.count26 ± (26 - 26)27 ± (27 - 27)+0.1%✅⬆️

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration201.93 ± (200.84 - 201.98) ms198.37 ± (197.57 - 198.54) ms-1.8%
.NET Framework 4.8 - Bailout
duration202.15 ± (201.61 - 202.68) ms200.85 ± (200.24 - 201.16) ms-0.6%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1131.94 ± (1132.88 - 1139.99) ms1132.23 ± (1133.69 - 1143.03) ms+0.0%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms190.77 ± (190.34 - 191.19) ms188.94 ± (188.54 - 189.34) ms-1.0%
process.time_to_main_ms82.44 ± (82.18 - 82.70) ms82.51 ± (82.27 - 82.75) ms+0.1%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.13 ± (16.11 - 16.16) MB16.02 ± (16.00 - 16.05) MB-0.7%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.1%✅⬆️
.NET Core 3.1 - Bailout
process.internal_duration_ms189.83 ± (189.40 - 190.26) ms188.52 ± (188.03 - 189.01) ms-0.7%
process.time_to_main_ms83.69 ± (83.49 - 83.88) ms83.20 ± (82.96 - 83.44) ms-0.6%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.12 ± (16.10 - 16.14) MB16.11 ± (16.09 - 16.14) MB-0.0%
runtime.dotnet.threads.count21 ± (21 - 21)21 ± (21 - 21)-0.3%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms436.24 ± (433.40 - 439.09) ms430.35 ± (427.55 - 433.15) ms-1.4%
process.time_to_main_ms478.27 ± (477.63 - 478.90) ms477.51 ± (476.80 - 478.23) ms-0.2%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed58.54 ± (58.42 - 58.66) MB58.94 ± (58.83 - 59.05) MB+0.7%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 30)+0.1%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms192.89 ± (192.47 - 193.31) ms193.83 ± (193.36 - 194.30) ms+0.5%✅⬆️
process.time_to_main_ms70.68 ± (70.51 - 70.86) ms71.08 ± (70.87 - 71.29) ms+0.6%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.36 ± (16.32 - 16.39) MB16.20 ± (16.09 - 16.31) MB-1.0%
runtime.dotnet.threads.count19 ± (19 - 19)18 ± (18 - 19)-2.1%
.NET 6 - Bailout
process.internal_duration_ms193.30 ± (192.87 - 193.73) ms192.24 ± (191.92 - 192.57) ms-0.5%
process.time_to_main_ms71.71 ± (71.55 - 71.88) ms71.90 ± (71.75 - 72.06) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.27 ± (16.16 - 16.38) MB16.26 ± (16.16 - 16.37) MB-0.0%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.4%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms447.12 ± (443.87 - 450.38) ms441.94 ± (438.57 - 445.31) ms-1.2%
process.time_to_main_ms455.03 ± (454.41 - 455.65) ms453.65 ± (453.09 - 454.21) ms-0.3%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed58.88 ± (58.75 - 59.02) MB58.79 ± (58.67 - 58.91) MB-0.2%
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 29)-0.1%
.NET 8 - Baseline
process.internal_duration_ms191.74 ± (191.35 - 192.13) ms191.40 ± (191.01 - 191.79) ms-0.2%
process.time_to_main_ms70.68 ± (70.53 - 70.84) ms71.16 ± (70.90 - 71.42) ms+0.7%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.68 ± (11.66 - 11.70) MB11.73 ± (11.71 - 11.75) MB+0.4%✅⬆️
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)+0.0%✅⬆️
.NET 8 - Bailout
process.internal_duration_ms190.95 ± (190.65 - 191.25) ms191.10 ± (190.72 - 191.48) ms+0.1%✅⬆️
process.time_to_main_ms71.68 ± (71.54 - 71.82) ms72.15 ± (72.02 - 72.28) ms+0.7%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.73 ± (11.70 - 11.76) MB11.83 ± (11.80 - 11.85) MB+0.8%✅⬆️
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms367.62 ± (366.25 - 368.99) ms370.28 ± (369.07 - 371.50) ms+0.7%✅⬆️
process.time_to_main_ms439.99 ± (439.20 - 440.78) ms439.84 ± (439.15 - 440.54) ms-0.0%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed48.22 ± (48.19 - 48.26) MB48.22 ± (48.19 - 48.26) MB-0.0%
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 29)-0.1%
Comparison explanation

Execution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).

Duration charts
FakeDbCommand (.NET Framework 4.8)
gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (69ms)  : 67, 70
    master - mean (68ms)  : 67, 70

    section Bailout
    This PR (7987) - mean (73ms)  : 71, 74
    master - mean (72ms)  : 71, 73

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (1,019ms)  : 944, 1093
    master - mean (1,005ms)  : 947, 1063

Loading
FakeDbCommand (.NET Core 3.1)
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (107ms)  : 104, 110
    master - mean (106ms)  : 103, 108

    section Bailout
    This PR (7987) - mean (108ms)  : 106, 109
    master - mean (107ms)  : 105, 108

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (751ms)  : 707, 794
    master - mean (741ms)  : 689, 793

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (95ms)  : 93, 97
    master - mean (94ms)  : 92, 96

    section Bailout
    This PR (7987) - mean (95ms)  : 94, 96
    master - mean (94ms)  : 93, 96

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (721ms)  : 683, 759
    master - mean (715ms)  : 679, 751

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (99ms)  : 90, 107
    master - mean (92ms)  : 90, 94

    section Bailout
    This PR (7987) - mean (96ms)  : 94, 98
    master - mean (93ms)  : 92, 94

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (655ms)  : 619, 691
    master - mean (633ms)  : 619, 648

Loading
HttpMessageHandler (.NET Framework 4.8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (198ms)  : 193, 204
    master - mean (201ms)  : 193, 210

    section Bailout
    This PR (7987) - mean (201ms)  : 196, 205
    master - mean (202ms)  : 195, 209

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (1,138ms)  : 1069, 1208
    master - mean (1,136ms)  : 1086, 1187

Loading
HttpMessageHandler (.NET Core 3.1)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (281ms)  : 274, 287
    master - mean (282ms)  : 273, 291

    section Bailout
    This PR (7987) - mean (280ms)  : 274, 287
    master - mean (282ms)  : 273, 292

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (939ms)  : 904, 974
    master - mean (944ms)  : 908, 980

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (274ms)  : 267, 280
    master - mean (272ms)  : 265, 279

    section Bailout
    This PR (7987) - mean (272ms)  : 269, 276
    master - mean (273ms)  : 267, 278

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (927ms)  : 878, 976
    master - mean (931ms)  : 877, 986

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7987) - mean (272ms)  : 267, 278
    master - mean (273ms)  : 266, 279

    section Bailout
    This PR (7987) - mean (273ms)  : 268, 278
    master - mean (272ms)  : 269, 276

    section CallTarget+Inlining+NGEN
    This PR (7987) - mean (842ms)  : 819, 866
    master - mean (840ms)  : 819, 861

Loading

@pr-commenter
Copy link

pr-commenter bot commented Dec 20, 2025

Benchmarks

Benchmark execution time: 2025-12-20 13:09:59

Comparing candidate commit 1660d1e in PR branch dudik/add-nullbyref-test with baseline commit b1bc5a1 in branch master.

Found 10 performance improvements and 4 performance regressions! Performance is the same for 158 metrics, 14 unstable metrics.

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net6.0

  • 🟩 execution_time [-20.666ms; -14.505ms] or [-9.915%; -6.959%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0

  • 🟥 execution_time [+13.063ms; +17.565ms] or [+6.532%; +8.784%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0

  • 🟩 execution_time [-24.847ms; -24.265ms] or [-12.293%; -12.005%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1

  • 🟩 execution_time [-22.122ms; -21.266ms] or [-10.910%; -10.488%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟩 execution_time [-32.803ms; -27.289ms] or [-13.857%; -11.528%]
  • 🟩 throughput [+202.600op/s; +226.663op/s] or [+21.399%; +23.940%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472

  • 🟥 execution_time [+152.215µs; +156.892µs] or [+8.000%; +8.246%]
  • 🟥 throughput [-40.089op/s; -38.880op/s] or [-7.628%; -7.398%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0

  • 🟩 execution_time [-100.565µs; -90.035µs] or [-6.605%; -5.913%]
  • 🟩 throughput [+41.435op/s; +46.281op/s] or [+6.309%; +7.047%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1

  • 🟩 throughput [+133.080op/s; +295.061op/s] or [+7.250%; +16.074%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1

  • 🟩 throughput [+10003.291op/s; +11869.471op/s] or [+6.100%; +7.238%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0

  • 🟩 execution_time [-13.204ms; -12.240ms] or [-6.567%; -6.088%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1

  • 🟥 execution_time [+11.384ms; +16.968ms] or [+5.690%; +8.481%]

@dudikeleti dudikeleti force-pushed the dudik/add-nullbyref-test branch from 1660d1e to 3ca992d Compare January 15, 2026 17:50
dudikeleti added a commit that referenced this pull request Jan 21, 2026
## Reason for change
In some cases, we cannot rely on the method metadata to determine
whether method arguments and locals exist, as they may still be skipped.

## Implementation details
Track open nodes and open/close them as required.

## Test coverage
#7987

## Other details
This PR is part of an effort to make the Snapshot Exploration Test run
successfully end-to-end.
#7986
#7989
dudikeleti added a commit that referenced this pull request Jan 21, 2026
…7989)

## Summary of changes
Add defensive checks for open nodes before closing them, and delay
writing `noCaptureReason` until we are certain that the array node is
closed.

## Test coverage
#7987

## Other details
This PR is part of an effort to make the Snapshot Exploration Test run
successfully end-to-end.

Related PRs:
#7986
#7988
@dudikeleti dudikeleti enabled auto-merge (squash) January 21, 2026 13:58
dudikeleti added a commit that referenced this pull request Jan 21, 2026
…l and LogArg to detect null byrefs (#7986)

## Reason for change
Some methods can legitimately produce null managed byrefs (e.g.,
MemoryMarshal.GetReference(emptySpan)), which makes ref T point to
address 0. Attempting to capture such locals/args would dereference an
invalid reference and could crash in LogLocal/LogArg
(NullReferenceException). This change makes DI runs stable and keeps
probes installed while avoiding unsafe dereferences

## Implementation details
Before reading a ref T capture input, we check Unsafe.IsNullRef(ref
value) and return early to avoid dereferencing an invalid reference.

Current behavior is to skip capturing that member entirely (no
misleading null value for non-nullable types like byte).
Follow-up option: if we decide we want the snapshot to explicitly show
this case, we can reuse the existing snapshot notCapturedReason
mechanism (no new reason added in this PR).

## Test coverage
#7987

## Other details
This PR is part of an effort to make the Snapshot Exploration Test run
successfully end-to-end.
#7988
#7989
@dudikeleti dudikeleti merged commit c846235 into master Jan 21, 2026
152 of 153 checks passed
@dudikeleti dudikeleti deleted the dudik/add-nullbyref-test branch January 21, 2026 15:59
@github-actions github-actions bot added this to the vNext-v3 milestone Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:debugger area:tests unit tests, integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants