Skip to content

Conversation

mdh1418
Copy link
Member

@mdh1418 mdh1418 commented Oct 9, 2025

On Win-x86, FindRootsOlderGeneration failed with double counting the same GC Root. My guess is that the same GCRoot was found on multiple subheaps, so adding deduplication logic during counting would account for that.

Example failing test

SOSRunner processing SOS.FindRootsOlderGeneration
{
    Running Process: D:\a\_work\1\s\.packages\cdb-sos\10.0.26100.1\runtimes\win-x86\native\cdb.exe  -y "D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0" -c ".load D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\runcommand.dll" -Gsins D:\a\_work\1\s\.dotnet-test\x86\dotnet.exe --fx-version 10.0.0-rtm.25476.104 D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0\FindRootsOlderGeneration.dll
    Working Directory: 
    Additional Environment Variables: DOTNET_ROOT=D:\a\_work\1\s\.dotnet-test\x86, DOTNET_ENABLED_SOS_LOGGING=D:\a\_work\1\s\artifacts\TestResults\Release\sos.unittests_2025_10_06_09_09_31_9438\SOS.FindRootsOlderGeneration.projectk.sdk.prebuilt.10.0.0-rtm.25476.104.soslog, DOTNET_EnableWriteXorExecute=0, COMPlus_EnableWriteXorExecute=0, DOTNET_gcServer=1
    {
        00:00.133: 
        00:00.133: ************* Preparing the environment for Debugger Extensions Gallery repositories **************
        00:00.133:    ExtensionRepository : Implicit
        00:00.133:    UseExperimentalFeatureForNugetShare : true
        00:00.133:    AllowNugetExeUpdate : true
        00:00.133:    NonInteractiveNuget : true
        00:00.133:    AllowNugetMSCredentialProviderInstall : true
        00:00.133:    AllowParallelInitializationOfLocalRepositories : true
        00:00.133: 
        00:00.133:    EnableRedirectToV8JsProvider : false
        00:00.133: 
        00:00.133:    -- Configuring repositories
        00:00.133:       ----> Repository : LocalInstalled, Enabled: true
        00:00.133:       ----> Repository : UserExtensions, Enabled: true
        00:00.133: 
        00:00.133: >>>>>>>>>>>>> Preparing the environment for Debugger Extensions Gallery repositories completed, duration 0.000 seconds
        00:00.133: 
        00:00.133: ************* Waiting for Debugger Extensions Gallery to Initialize **************
        00:00.144: 
        00:00.144: >>>>>>>>>>>>> Waiting for Debugger Extensions Gallery to Initialize completed, duration 0.015 seconds
        00:00.144:    ----> Repository : UserExtensions, Enabled: true, Packages count: 0
        00:00.144:    ----> Repository : LocalInstalled, Enabled: true, Packages count: 0
        00:00.144: 
        00:00.144: Microsoft (R) Windows Debugger Version 10.0.26100.1 X86
        00:00.144: Copyright (c) Microsoft Corporation. All rights reserved.
        00:00.144: 
        00:00.144: CommandLine: D:\a\_work\1\s\.dotnet-test\x86\dotnet.exe --fx-version 10.0.0-rtm.25476.104 D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0\FindRootsOlderGeneration.dll
        00:00.149: Unable to add extension DLL: ntsdexts
        00:00.149: Unable to add extension DLL: uext
        00:00.149: Unable to add extension DLL: exts
        00:00.150: Unable to add extension DLL: wow64exts
        00:00.150: 
        00:00.150: ************* Path validation summary **************
        00:00.150: Response                         Time (ms)     Location
        00:00.150: OK                                             D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0
        00:00.150: Symbol search path is: D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0
        00:00.150: Executable search path is: 
        00:00.150: ModLoad: 00310000 00334000   dotnet.exe
        00:00.151: ModLoad: 775e0000 77789000   ntdll.dll
        00:00.154: ModLoad: 77020000 77110000   C:\Windows\SysWOW64\KERNEL32.DLL
        00:00.155: ModLoad: 759e0000 75c31000   C:\Windows\SysWOW64\KERNELBASE.dll
        00:00.156: ModLoad: 76720000 76833000   C:\Windows\SysWOW64\ucrtbase.dll
        00:00.157: (c68.2610): Break instruction exception - code 80000003 (first chance)
        00:00.164: eax=00000000 ebx=030cd000 ecx=ab570000 edx=00000000 esi=ffffffff edi=003100f8
        00:00.164: eip=77695c51 esp=0337f334 ebp=0337f360 iopl=0         nv up ei pl zr na pe nc
        00:00.164: cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
        00:00.164: ntdll!LdrInitShimEngineDynamic+0x6b1:
        00:00.164: 77695c51 cc              int     3
        00:00.164: 0:000> cdb: Reading initial command '.load D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\runcommand.dll'
        00:00.164: <END_COMMAND_OUTPUT>
        00:00.164: 0:000> 
        STDIN: 00:00.164: !runcommand sxd dz
        00:00.164: <END_COMMAND_OUTPUT>
        00:00.164: 0:000> 
        STDIN: 00:00.165: !runcommand sxd iov
        00:00.165: <END_COMMAND_OUTPUT>
        00:00.165: 0:000> 
        STDIN: 00:00.165: !runcommand .extpath D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release
        00:00.165: Extension search path is: D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release
        00:00.165: <END_COMMAND_OUTPUT>
        00:00.165: 0:000> 
        STDIN: 00:00.165: !runcommand .outmask- 0x244
        00:00.165: Client 06703CF8 mask is 1B3
        00:00.165: <END_COMMAND_OUTPUT>
        00:00.165: 0:000> 
        STDIN: 00:00.165: !runcommand !sym quiet
        00:00.165: quiet mode - symbol prompts off
        00:00.165: <END_COMMAND_OUTPUT>
        00:00.165: 0:000> 
        STDIN: 00:00.165: !runcommand .lines
        00:00.165: Line number information will be loaded
        00:00.166: <END_COMMAND_OUTPUT>
        00:00.166: 0:000> 
        STDIN: 00:00.166: !runcommand dx @Debugger.Settings.EngineInitialization.SecureLoadDotNetExtensions=false
        00:00.166: @Debugger.Settings.EngineInitialization.SecureLoadDotNetExtensions=false : false
        00:00.166: <END_COMMAND_OUTPUT>
        STARTING SCRIPT: D:\a\_work\1\s\src\SOS\SOS.UnitTests\Scripts\FindRootsOlderGeneration.script
        %DEBUGGEE_EXE% => D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0\FindRootsOlderGeneration.dll
        %DUMP_NAME% => D:\a\_work\1\s\artifacts\tmp\Release\dumps\ProjectK\10.0.0-rtm.25476.104\net10.0\SOS.FindRootsOlderGeneration.Heap.dmp
        %DEBUG_ROOT% => D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0
        %TEST_NAME% => SOS.FindRootsOlderGeneration
        %LOG_PATH% => D:\a\_work\1\s\artifacts\TestResults\Release\sos.unittests_2025_10_06_09_09_31_9438
        %LOG_SUFFIX% => projectk.sdk.prebuilt.10.0.0-rtm.25476.104
        %SOS_PATH% => D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\sos.dll
        %DESKTOP_RUNTIME_PATH% => 
        <DEBUGGEE_EXE> => D:\\a\\_work\\1\\s\\artifacts\\bin\\FindRootsOlderGeneration\\Release\\net10.0\\FindRootsOlderGeneration.dll
        <DEBUG_ROOT> => D:\\a\\_work\\1\\s\\artifacts\\bin\\FindRootsOlderGeneration\\Release\\net10.0
        <SOURCE_PATH> => D:\\a\\_work\\1\\s\\src\\SOS\\SOS.UnitTests\\Debuggees\\FindRootsOlderGeneration
        <HEXVAL> => [A-Fa-f0-9]+(`[A-Fa-f0-9]+)?
        <DECVAL> => [,0-9]+(`[,0-9]+)?
        CDB
        WINDOWS
        PROJECTK
        X86
        MAJOR_RUNTIME_VERSION_10
        MAJOR_RUNTIME_VERSION_GE_3
        MAJOR_RUNTIME_VERSION_GE_5
        MAJOR_RUNTIME_VERSION_GE_6
        MAJOR_RUNTIME_VERSION_GE_7
        MAJOR_RUNTIME_VERSION_GE_8
        MAJOR_RUNTIME_VERSION_GE_9
        LIVE
        32BIT
        NETCORE_OR_DOTNETDUMP
        00:00.166: 0:000> 
        STDIN: 00:00.166: g
        00:00.171: ModLoad: 6f760000 6f7ad000   D:\a\_work\1\s\.dotnet-test\x86\host\fxr\10.0.0-rtm.25476.104\hostfxr.dll
        00:00.171: ModLoad: 75430000 754ae000   C:\Windows\SysWOW64\ADVAPI32.dll
        00:00.171: ModLoad: 77110000 771d2000   C:\Windows\SysWOW64\msvcrt.dll
        00:00.172: ModLoad: 761f0000 7626d000   C:\Windows\SysWOW64\sechost.dll
        00:00.172: ModLoad: 76610000 76629000   C:\Windows\SysWOW64\bcrypt.dll
        00:00.172: ModLoad: 76390000 7644c000   C:\Windows\SysWOW64\RPCRT4.dll
        00:00.175: ModLoad: 6f710000 6f75f000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\hostpolicy.dll
        00:00.186: ModLoad: 69960000 69d1a000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\coreclr.dll
        00:00.186: ModLoad: 75550000 7563a000   C:\Windows\SysWOW64\ole32.dll
        00:00.187: ModLoad: 77490000 7750e000   C:\Windows\SysWOW64\msvcp_win.dll
        00:00.187: ModLoad: 772f0000 77314000   C:\Windows\SysWOW64\GDI32.dll
        00:00.187: ModLoad: 75cc0000 75cda000   C:\Windows\SysWOW64\win32u.dll
        00:00.187: ModLoad: 771e0000 772c9000   C:\Windows\SysWOW64\gdi32full.dll
        00:00.188: ModLoad: 76e70000 77015000   C:\Windows\SysWOW64\USER32.dll
        00:00.188: ModLoad: 75750000 759d7000   C:\Windows\SysWOW64\combase.dll
        00:00.189: ModLoad: 764e0000 7657d000   C:\Windows\SysWOW64\OLEAUT32.dll
        00:00.190: ModLoad: 754b0000 754d5000   C:\Windows\SysWOW64\IMM32.DLL
        00:00.204: ModLoad: 76120000 76185000   C:\Windows\SysWOW64\bcryptPrimitives.dll
        00:00.207: (c68.2610): Unknown exception - code 04242420 (first chance)
        00:00.209: ModLoad: 752c0000 752d2000   C:\Windows\SysWOW64\kernel.appcore.dll
        00:00.213: ModLoad: 68a80000 6995f000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Private.CoreLib.dll
        00:00.240: ModLoad: 27170000 27178000   D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0\FindRootsOlderGeneration.dll
        00:00.241: ModLoad: 27170000 27178000   D:\a\_work\1\s\artifacts\bin\FindRootsOlderGeneration\Release\net10.0\FindRootsOlderGeneration.dll
        00:00.241: ModLoad: 26fb0000 26fbe000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Runtime.dll
        00:00.242: ModLoad: 26fb0000 26fbe000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Runtime.dll
        00:00.242: ModLoad: 6f480000 6f63b000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\clrjit.dll
        00:00.243: ModLoad: 6f6b0000 6f6d4000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Console.dll
        00:00.244: (c68.2610): Break instruction exception - code 80000003 (first chance)
        00:00.251: eax=00000001 ebx=0337efb4 ecx=00000008 edx=03719638 esi=03766038 edi=0337efb4
        00:00.251: eip=75b87f12 esp=0337ee70 ebp=0337eea0 iopl=0         nv up ei pl nz na po nc
        00:00.251: cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
        00:00.251: KERNELBASE!DebugBreak+0x2:
        00:00.251: 75b87f12 cc              int     3
        00:00.251: <END_COMMAND_OUTPUT>
        00:00.251: 0:000> 
        STDIN: 00:00.251: !runcommand .unload sos
        00:00.251: No extension named 'sos' in chain
        00:00.251: <END_COMMAND_OUTPUT>
        00:00.251: 0:000> 
        STDIN: 00:00.251: !runcommand .load D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\sos.dll
        00:00.252: <END_COMMAND_OUTPUT>
        00:00.252: 0:000> 
        STDIN: 00:00.252: !runcommand .reload
        00:00.252: Reloading current modules
        00:00.253: .............................
        00:00.265: 
        00:00.265: ************* Symbol Loading Error Summary **************
        00:00.265: Module name            Error
        00:00.265: System.Private.CoreLib The system cannot find the file specified
        00:00.265: KERNELBASE             The system cannot find the file specified
        00:00.265: ntdll                  The system cannot find the file specified
        00:00.265: 
        00:00.265: You can troubleshoot most symbol related issues by turning on symbol loading diagnostics (!sym noisy) and repeating the command that caused symbols to be loaded.
        00:00.265: You should also verify that your symbol search path (.sympath) is correct.
        00:00.265: <END_COMMAND_OUTPUT>
        00:00.265: 0:000> 
        STDIN: 00:00.265: !runcommand .chain
        00:00.266: Extension DLL search Path:
        00:00.266:     D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release
        00:00.266: Extension DLL chain:
        00:00.266:     D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\sos.dll: image 9,0,13,603 @Commit: f40e210b5da69e3c7585917137322cac01f0dffc, API 2.0.0, built Mon Oct  6 21:02:28 2025
        00:00.266:         [path: D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\sos.dll]
        00:00.266:     D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\runcommand.dll: API 1.0.0, built Mon Oct  6 21:02:23 2025
        00:00.266:         [path: D:\a\_work\1\s\artifacts\bin\Windows_NT.x86.Release\runcommand.dll]
        00:00.266:     dbghelp: image 10.0.26100.1, API 10.0.6, 
        00:00.266:         [path: D:\a\_work\1\s\.packages\cdb-sos\10.0.26100.1\runtimes\win-x86\native\dbghelp.dll]
        00:00.266: <END_COMMAND_OUTPUT>
        00:00.266: 0:000> 
        STDIN: 00:00.266: !runcommand !SetHostRuntime D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104
        00:00.266: Using .NET Core runtime (version 10.0) to host the managed SOS code
        00:00.266: Host runtime path: D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104
        00:00.266: <END_COMMAND_OUTPUT>
        00:00.266: 0:000> 
        STDIN: 00:00.266: g
        00:00.269: ModLoad: 6fa50000 6fa61000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Threading.dll
        00:00.270: ModLoad: 26fe0000 26fe8000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Text.Encoding.Extensions.dll
        00:00.270: ModLoad: 26fe0000 26fe8000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Text.Encoding.Extensions.dll
        00:00.271: ModLoad: 6f640000 6f658000   D:\a\_work\1\s\.dotnet-test\x86\shared\Microsoft.NETCore.App\10.0.0-rtm.25476.104\System.Runtime.InteropServices.dll
        00:00.273: Enable CLRN notifications: SXE CLRN
        00:00.273: (c68.2610): Break instruction exception - code 80000003 (first chance)
        00:00.274: eax=00000001 ebx=0337efb4 ecx=00000008 edx=03719638 esi=03766038 edi=0337efb4
        00:00.274: eip=75b87f12 esp=0337ee70 ebp=0337eea0 iopl=0         nv up ei pl nz na po nc
        00:00.274: cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
        00:00.274: KERNELBASE!DebugBreak+0x2:
        00:00.274: 75b87f12 cc              int     3
        00:00.274: <END_COMMAND_OUTPUT>
        00:00.274: 0:000> 
        STDIN: 00:00.274: !runcommand !FindRoots -gen any
        00:00.519: <END_COMMAND_OUTPUT>
        00:00.519: 0:000> 
        STDIN: 00:00.519: !runcommand sxe CLRN
        00:00.519: <END_COMMAND_OUTPUT>
        00:00.519: 0:000> 
        STDIN: 00:00.519: g
        00:00.521: Before GC - Array Gen: 2, Thing Gen: 0
        00:00.521: Forcing GC...
        00:00.522: (c68.12a4): CLR notification exception - code e0444143 (first chance)
        00:00.529: CLR notification: GC - Performing a gen 0 collection. Determined surviving objects...
        00:00.529: First chance exceptions are reported before any exception handling.
        00:00.529: This exception may be expected and handled.
        00:00.530: eax=0577f670 ebx=69cea834 ecx=00000003 edx=00000000 esi=00000003 edi=0577f73c
        00:00.530: eip=75b195f2 esp=0577f670 ebp=0577f6c8 iopl=0         nv up ei pl nz ac po nc
        00:00.530: cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
        00:00.530: KERNELBASE!RaiseException+0x62:
        00:00.530: 75b195f2 8b4c2454        mov     ecx,dword ptr [esp+54h] ss:002b:0577f6c4=323253bd
        00:00.530: <END_COMMAND_OUTPUT>
        00:00.530: 0:007> 
        STDIN: 00:00.530: !runcommand !clrstack -all
        00:00.537: OS Thread Id: 0x2740
        00:00.545: Child SP       IP Call Site
        00:00.545: 05ABFB08 77653e8c [DebuggerU2MCatchHandlerFrame: 05abfb08] 
        00:00.545: OS Thread Id: 0x2610
        00:00.545: Child SP       IP Call Site
        00:00.545: 0337EE84 77653e8c [InlinedCallFrame: 0337ee84] 
        00:00.546: 0337EE84 68cec380 [InlinedCallFrame: 0337ee84] 
        00:00.546: 0337EE78 68CEC380 System.GC.Collect(Int32, System.GCCollectionMode, Boolean, Boolean, Boolean)
        00:00.559: 0337EED4 68CEC2B2 System.GC.Collect(Int32, System.GCCollectionMode, Boolean)
        00:00.560: 0337EEE8 26F7195E FindRootsOlderGeneration.Program.Main() [/_/src/SOS/SOS.UnitTests/Debuggees/FindRootsOlderGeneration/Program.cs @ 36]
        00:00.564: OS Thread Id: 0x195c
        00:00.564: Child SP       IP Call Site
        00:00.564: 26F6F880 776541ac [DebuggerU2MCatchHandlerFrame: 26f6f880] 
        00:00.564: <END_COMMAND_OUTPUT>
        00:00.564: 0:007> 
        STDIN: 00:00.564: ~0s
        00:00.565: eax=00000001 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=000002a8
        00:00.565: eip=77653e8c esp=0337ed30 ebp=0337eda0 iopl=0         nv up ei pl nz ac pe nc
        00:00.565: cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
        00:00.565: ntdll!NtWaitForSingleObject+0xc:
        00:00.565: 77653e8c c20c00          ret     0Ch
        00:00.565: <END_COMMAND_OUTPUT>
        00:00.565: 0:000> 
        STDIN: 00:00.565: !runcommand !DumpStackObjects
        00:00.632: OS Thread Id: 0x2610 (0)
        00:00.637:   SP/REG   Object Name
        00:00.686: 0337eef4 05b5812c System.String
        00:00.694: 0337ef00 19ac1020 FindRootsOlderGeneration.Thing[]
        00:00.694: 0337ef3c 05b576fc FindRootsOlderGeneration.Thing
        00:00.694: 0337ef40 19ac1020 FindRootsOlderGeneration.Thing[]
        00:00.695: 0337f264 11acbed0 System.String[]
        00:00.695: 0337f2f4 11acbed0 System.String[]
        00:00.696: 0337f2f8 11acbee0 System.String[]
        00:00.696: 0337f308 11acbed0 System.String[]
        00:00.696: 0337f438 11acbee0 System.String[]
        00:00.696: <END_COMMAND_OUTPUT>
        00:00.696: 0:000> 
        STDIN: 00:00.696: !runcommand !FindRoots 05b576fc
        00:00.740: Older Generation:
        00:00.740:     19ac1020
        00:00.745: Caching GC roots, this may take a while.
        00:00.745: Subsequent runs of this command will be faster.
        00:00.745: 
        00:00.751:           -> 19ac1020 FindRootsOlderGeneration.Thing[] 
        00:00.751:           -> 05b576fc FindRootsOlderGeneration.Thing 
        00:00.751: 
        00:00.751: Older Generation:
        00:00.751:     19ac1020
        00:00.751:           -> 19ac1020 FindRootsOlderGeneration.Thing[] 
        00:00.751:           -> 05b576fc FindRootsOlderGeneration.Thing 
        00:00.751: 
        00:00.763: Found 2 unique roots.
        00:00.763: <END_COMMAND_OUTPUT>
    SOSRunner error at D:\a\_work\1\s\src\SOS\SOS.UnitTests\Scripts\FindRootsOlderGeneration.script:34
    Excerpt from D:\a\_work\1\s\src\SOS\SOS.UnitTests\Scripts\FindRootsOlderGeneration.script:
       32 
       33 SOSCOMMAND:FindRoots <POUT>\w+\s+(<HEXVAL>)\s+(FindRootsOlderGeneration.Thing)(?!\[\])<POUT>
       34 VERIFY:Found 1 unique roots.
       35 
       36 COMMAND:sxn CLRN
        00:00.763: 0:000> <END_COMMAND_ERROR>
        STDIN: 00:00.763: !runcommand !SOSStatus
    System.Exception: Debugger output did not match the expression: Found 1 unique roots.
   at SOSRunner.VerifyOutput(String verifyLine, Boolean match) in /_/src/SOS/SOS.UnitTests/SOSRunner.cs:line 1252
   at SOSRunner.RunScript(String scriptRelativePath) in /_/src/SOS/SOS.UnitTests/SOSRunner.cs:line 905
   at SOSRunner.RunScript(String scriptRelativePath) in /_/src/SOS/SOS.UnitTests/SOSRunner.cs:line 942
    Killing process 9104: 00:00.773 - Kill() was called
}

@mdh1418 mdh1418 requested a review from max-charlamb October 9, 2025 16:33
@mdh1418 mdh1418 requested a review from a team as a code owner October 9, 2025 16:33
@mdh1418
Copy link
Member Author

mdh1418 commented Oct 9, 2025

If anyone has a more appropriate fix, I'm all ears. I'm not familiar with SOS tests/heaps logic.

@mdh1418 mdh1418 requested a review from hoyosjs October 9, 2025 16:36
@max-charlamb
Copy link
Member

This change looks good to me. The idea of a 'unique' root depends on how you think about objects being rooted in multiple heaps. Do we care about 'unique' roots per heap or per object. This approach makes sense to me as counting the same object as multiple roots is confusing. However, I don't have much experience with the GC behavior either.

If we don't want to change the commands behavior, we can update the test to verify that FindRootsOlderGeneration.Thing[] is listed in the roots.

Is this behavior change okay @hoyosjs ?

@mdh1418
Copy link
Member Author

mdh1418 commented Oct 13, 2025

From some more digging of how GCRoots works, my current mental model is that PrintNonStackRoots and PrintAllRoots will enumerate unique ClrRoots (RootCache.EnumerateRoots() for AllRoots, and RootCache.GetHandleRoots + RootCache.GetFinalizerQueueRoots() for NonStackRoots) in attempt to find a path to the target object.

That way, in all paths outside the one calling PrintOlderGenerationRoots, theres a claim its all unique roots.

                if (gen < 0 || gen > 1)
                {
                    // If not gen0 or gen1, treat it as a normal !gcroot
                    if (NoStacks)
                    {
                        count = PrintNonStackRoots(gcroot, limit); <- Unique
                    }
                    else
                    {
                        count = PrintAllRoots(gcroot, limit); <- Unique
                    }
                }
======================
               else
                {
                    count = PrintOlderGenerationRoots(gcroot, gen, limit);
                   count += PrintNonStackRoots(gcroot, limit);
                }
======================
            }
            else if (NoStacks)
            {
                count = PrintNonStackRoots(gcroot, limit); <- Unique
            }
            else
            {
                count = PrintAllRoots(gcroot, limit); <- Unique
            }

            Console.WriteLine($"Found {count:n0} unique roots.");

On the other hand, PrintOlderGenerationRoots doesn't operate by enumerating unique ClrRoots, but by iterating over memory addresses in the GC's internal tracking. So from the tests failures (win x86), there are instances where the same object objAddress appears in multiple heaps. And as Max mentioned, I think it makes sense to only associate one root per object, so adding deduplication for PrintOlderGenerationRoots seems to align with the intent of finding unique roots.

I'm not caught up with how the test validates this runtime change dotnet/runtime#119396, but if just checking FindRootsOlderGeneration.Thing isn't sufficient, I can add the check for FindRootsOlderGeneration.Thing[]. But if it's not necessary, we can just merge this as is to unblock CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants