diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp
index 2309e8173d..40ad2d5fa9 100644
--- a/src/SOS/Strike/strike.cpp
+++ b/src/SOS/Strike/strike.cpp
@@ -4408,10 +4408,9 @@ HRESULT PrintThreadsFromThreadStore(BOOL bMiniDump, BOOL bPrintLiveThreadsOnly)
}
BOOL bSwitchedOutFiber = Thread.osThreadId == SWITCHED_OUT_FIBER_OSID;
+ ULONG id = 0;
if (!IsKernelDebugger())
{
- ULONG id = 0;
-
if (bSwitchedOutFiber)
{
table.WriteColumn(0, "<<<< ");
@@ -4456,8 +4455,19 @@ HRESULT PrintThreadsFromThreadStore(BOOL bMiniDump, BOOL bPrintLiveThreadsOnly)
// Apartment state
#ifndef FEATURE_PAL
DWORD_PTR OleTlsDataAddr;
- if (IsWindowsTarget() && !bSwitchedOutFiber
- && SafeReadMemory(TO_TADDR(Thread.teb + offsetof(TEB, ReservedForOle)),
+ ULONG64 teb = 0;
+ if (IsWindowsTarget() && !bSwitchedOutFiber && id != 0)
+ {
+ ULONG curId;
+ if (SUCCEEDED(g_ExtSystem->GetCurrentThreadId(&curId)) &&
+ SUCCEEDED(g_ExtSystem->SetCurrentThreadId(id)))
+ {
+ g_ExtSystem->GetCurrentThreadTeb(&teb);
+ g_ExtSystem->SetCurrentThreadId(curId);
+ }
+ }
+ if (teb != 0
+ && SafeReadMemory(TO_TADDR(teb + offsetof(TEB, ReservedForOle)),
&OleTlsDataAddr,
sizeof(OleTlsDataAddr), NULL) && OleTlsDataAddr != 0)
{
diff --git a/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.cs b/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.cs
new file mode 100644
index 0000000000..7e1045aceb
--- /dev/null
+++ b/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+internal sealed class ThreadApartment
+{
+ private static readonly ManualResetEventSlim s_staReady = new();
+ private static readonly ManualResetEventSlim s_mtaReady = new();
+
+ private static void Main()
+ {
+ // Create an STA thread using SetApartmentState before Start.
+ // The runtime will call CoInitializeEx(COINIT_APARTMENTTHREADED) when the thread starts.
+ Thread staThread = new Thread(() =>
+ {
+ s_staReady.Set();
+ Thread.Sleep(Timeout.Infinite);
+ });
+ staThread.SetApartmentState(ApartmentState.STA);
+ staThread.IsBackground = true;
+ staThread.Start();
+
+ // Create an MTA thread using SetApartmentState before Start.
+ Thread mtaThread = new Thread(() =>
+ {
+ s_mtaReady.Set();
+ Thread.Sleep(Timeout.Infinite);
+ });
+ mtaThread.SetApartmentState(ApartmentState.MTA);
+ mtaThread.IsBackground = true;
+ mtaThread.Start();
+
+ s_staReady.Wait();
+ s_mtaReady.Wait();
+
+ Debugger.Break();
+
+ throw new Exception("ThreadApartment test complete");
+ }
+}
diff --git a/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.csproj b/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.csproj
new file mode 100644
index 0000000000..5438f6aa45
--- /dev/null
+++ b/src/tests/SOS.UnitTests/Debuggees/ThreadApartment/ThreadApartment.csproj
@@ -0,0 +1,9 @@
+
+
+ Exe
+ $(BuildProjectFramework)
+ $(SupportedSubProcessTargetFrameworks)
+
+ $(NoWarn);CA1416
+
+
diff --git a/src/tests/SOS.UnitTests/SOS.cs b/src/tests/SOS.UnitTests/SOS.cs
index 59de9f14ec..88350a0b00 100644
--- a/src/tests/SOS.UnitTests/SOS.cs
+++ b/src/tests/SOS.UnitTests/SOS.cs
@@ -463,6 +463,17 @@ public async Task SimpleThrow(TestConfiguration config)
await SOSTestHelpers.RunTest(config, debuggeeName: "SimpleThrow", scriptName: "SimpleThrow.script", Output, testTriage: true);
}
+ [SkippableTheory, MemberData(nameof(Configurations))]
+ public async Task ThreadApartment(TestConfiguration config)
+ {
+ if (OS.Kind != OSKind.Windows)
+ {
+ throw new SkipTestException("Apartment state is a Windows COM concept");
+ }
+
+ await SOSTestHelpers.RunTest(config, debuggeeName: "ThreadApartment", scriptName: "ThreadApartment.script", Output);
+ }
+
[SkippableTheory, MemberData(nameof(Configurations))]
public async Task AsyncMain(TestConfiguration config)
{
diff --git a/src/tests/SOS.UnitTests/Scripts/ThreadApartment.script b/src/tests/SOS.UnitTests/Scripts/ThreadApartment.script
new file mode 100644
index 0000000000..9fdf82186d
--- /dev/null
+++ b/src/tests/SOS.UnitTests/Scripts/ThreadApartment.script
@@ -0,0 +1,18 @@
+#
+# Tests that clrthreads properly displays COM apartment state (STA/MTA).
+# This test is Windows-only since apartment state is a Windows COM concept.
+#
+
+CONTINUE
+
+LOADSOS
+
+# Verify that clrthreads shows the apartment state column with STA and MTA values.
+# The ThreadApartment debuggee creates one STA and one MTA thread before breaking.
+IFDEF:WINDOWS
+SOSCOMMAND:clrthreads
+VERIFY:\s*ThreadCount:\s+\s+
+VERIFY:\s+ID\s+OSID\s+ThreadOBJ\s+State.*Apt.*
+VERIFY:.*\bSTA\b.*
+VERIFY:.*\bMTA\b.*
+ENDIF:WINDOWS