Skip to content

Commit f37ab00

Browse files
Remove TEB field from Thread, DAC, and cDAC (#126902)
> [!NOTE] > This PR was generated with the assistance of GitHub Copilot. ## Summary Remove the TEB (Thread Environment Block) pointer from the DAC/cDAC Thread data contract. Consumers should look up the TEB from the OS thread ID via the debugger's native API instead. ## Background The `Thread::m_pTEB` field was exposed through `DacpThreadData.teb` and through the cDAC `ThreadData.TEB` contract field. Analysis of all consumers shows: - **SOS** reads `DacpThreadData.teb` in one place (`strike.cpp:4460`) to display COM apartment state in `!Threads`. A companion PR in dotnet/diagnostics switches this to use `IDebuggerServices::GetThreadTeb(osThreadId)` instead. - **ClrMD** reads `DacpThreadData.Teb` to derive `StackBase`/`StackLimit`. A companion PR in microsoft/clrmd switches this to use `IThreadReader.GetThreadTeb(osThreadId)` instead. - **NativeAOT** already returns `TargetPointer.Null` for TEB. - **Non-Windows** platforms already return NULL for TEB. ## Changes - `request.cpp`: Always set `threadData->teb = NULL` (field retained for binary layout compatibility) - `datadescriptor.inc`: Remove TEB field from Thread type descriptor - `threads.h`: Remove TEB from `cdac_data<Thread>` - `Data/Thread.cs`: Remove TEB property and reading logic - `Thread_1.cs`: Remove TEB from ThreadData construction - `IThread.cs`: Remove TEB from ThreadData record - `SOSDacImpl.cs`: Set `data->teb = 0`, remove debug assertion - `Thread.md`: Remove TEB from data contract documentation - Test mocks: Remove TEB from mock thread descriptors ## Companion PRs - dotnet/diagnostics#5804 — SOS switches to `GetThreadTeb(osThreadId)` for apartment state display + new ThreadApartment regression test - microsoft/clrmd#1419 — `DacRuntime` switches to `IThreadReader.GetThreadTeb(osThreadId)` for stack bounds ## Validation - cDAC build: 0 warnings, 0 errors - cDAC tests: 1586/1586 passed - cdb verification: `!Threads` output identical between legacy DAC and cDAC (Release) - Manual cdb verification: STA/MTA apartment state displays correctly with both old and new SOS --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3024b5a commit f37ab00

13 files changed

Lines changed: 4 additions & 45 deletions

File tree

docs/design/datacontracts/Thread.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ record struct ThreadData (
3636
TargetPointer AllocContextLimit;
3737
TargetPointer Frame;
3838
TargetPointer FirstNestedException;
39-
TargetPointer TEB;
4039
TargetPointer LastThrownObjectHandle;
4140
TargetPointer NextThread;
4241
);
@@ -97,7 +96,6 @@ The contract additionally depends on these data descriptors
9796
| `Thread` | `Frame` | Pointer to current frame |
9897
| `Thread` | `CachedStackBase` | Pointer to the base of the stack |
9998
| `Thread` | `CachedStackLimit` | Pointer to the limit of the stack |
100-
| `Thread` | `TEB` | Thread Environment Block pointer |
10199
| `Thread` | `LastThrownObject` | Handle to last thrown exception object |
102100
| `Thread` | `LinkNext` | Pointer to get next thread |
103101
| `Thread` | `ExceptionTracker` | Pointer to exception tracking information |
@@ -184,7 +182,6 @@ ThreadData GetThreadData(TargetPointer address)
184182
AllocContextPointer: allocContextPointer,
185183
AllocContextLimit: allocContextLimit,
186184
Frame: target.ReadPointer(address + /* Thread::Frame offset */),
187-
TEB : /* Has Thread::TEB offset */ ? target.ReadPointer(address + /* Thread::TEB offset */) : TargetPointer.Null,
188185
LastThrownObjectHandle : target.ReadPointer(address + /* Thread::LastThrownObject offset */),
189186
FirstNestedException : firstNestedException,
190187
NextThread: target.ReadPointer(address + /* Thread::LinkNext offset */) - threadLinkOffset;

src/coreclr/debug/daccess/enummem.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,10 +1227,6 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
12271227
// Write out the Thread instance
12281228
DacEnumHostDPtrMem(pThread);
12291229

1230-
// @TODO
1231-
// write TEB pointed by the thread
1232-
// DacEnumHostDPtrMem(pThread->GetTEB());
1233-
12341230
// @TODO
12351231
// If CLR is hosted, we want to write out fiber data
12361232

src/coreclr/debug/daccess/request.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -890,11 +890,9 @@ HRESULT ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThre
890890
threadData->context = PTR_CDADDR(AppDomain::GetCurrentDomain());
891891
threadData->domain = PTR_CDADDR(AppDomain::GetCurrentDomain());
892892
threadData->lockCount = (DWORD)-1;
893-
#ifndef TARGET_UNIX
894-
threadData->teb = TO_CDADDR(thread->m_pTEB);
895-
#else
893+
// TEB is no longer provided by the runtime. Consumers should look up the TEB
894+
// from the OS thread ID via the debugger's native API (e.g., IDebuggerServices::GetThreadTeb).
896895
threadData->teb = (CLRDATA_ADDRESS)NULL;
897-
#endif
898896
threadData->lastThrownObjectHandle =
899897
TO_CDADDR(thread->m_LastThrownObjectHandle);
900898
threadData->nextThread =

src/coreclr/vm/datadescriptor/datadescriptor.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ CDAC_TYPE_FIELD(Thread, TYPE(GCHandle), LastThrownObject, cdac_data<Thread>::Las
5353
CDAC_TYPE_FIELD(Thread, T_POINTER, LinkNext, cdac_data<Thread>::Link)
5454
CDAC_TYPE_FIELD(Thread, T_POINTER, ThreadLocalDataPtr, cdac_data<Thread>::ThreadLocalDataPtr)
5555
#ifndef TARGET_UNIX
56-
CDAC_TYPE_FIELD(Thread, T_POINTER, TEB, cdac_data<Thread>::TEB)
5756
CDAC_TYPE_FIELD(Thread, T_POINTER, UEWatsonBucketTrackerBuckets, cdac_data<Thread>::UEWatsonBucketTrackerBuckets)
5857
#endif
5958
CDAC_TYPE_END(Thread)

src/coreclr/vm/threads.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,8 +1513,6 @@ void Thread::InitThread()
15131513
#ifndef TARGET_UNIX
15141514
(void) _controlfp_s( NULL, _RC_NEAR, _RC_CHOP|_RC_UP|_RC_DOWN|_RC_NEAR );
15151515

1516-
m_pTEB = (struct _NT_TIB*)NtCurrentTeb();
1517-
15181516
#endif // !TARGET_UNIX
15191517

15201518
if (m_CacheStackBase == 0)

src/coreclr/vm/threads.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -912,20 +912,6 @@ class Thread
912912
InterpThreadContext* GetOrCreateInterpThreadContext();
913913
#endif // FEATURE_INTERPRETER
914914

915-
#ifndef TARGET_UNIX
916-
private:
917-
_NT_TIB *m_pTEB;
918-
public:
919-
_NT_TIB *GetTEB() {
920-
LIMITED_METHOD_CONTRACT;
921-
return m_pTEB;
922-
}
923-
PEXCEPTION_REGISTRATION_RECORD *GetExceptionListPtr() {
924-
WRAPPER_NO_CONTRACT;
925-
return &GetTEB()->ExceptionList;
926-
}
927-
#endif // !TARGET_UNIX
928-
929915
inline void SetTHAllocContextObj(TypeHandle th) {LIMITED_METHOD_CONTRACT; m_thAllocContextObj = th; }
930916

931917
inline TypeHandle GetTHAllocContextObj() {LIMITED_METHOD_CONTRACT; return m_thAllocContextObj; }
@@ -3786,7 +3772,6 @@ struct cdac_data<Thread>
37863772
static constexpr size_t ProfilerFilterContext = offsetof(Thread, m_pProfilerFilterContext);
37873773
#endif // PROFILING_SUPPORTED
37883774
#ifndef TARGET_UNIX
3789-
static constexpr size_t TEB = offsetof(Thread, m_pTEB);
37903775
static constexpr size_t UEWatsonBucketTrackerBuckets = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_UEWatsonBucketTracker)
37913776
+ offsetof(EHWatsonBucketTracker, m_WatsonUnhandledInfo.m_pUnhandledBuckets);
37923777
#endif

src/coreclr/vm/threadsuspend.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,12 +2893,8 @@ BOOL Thread::RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt)
28932893
#ifdef _DEBUG
28942894
// In some rare cases the stack pointer may be outside the stack limits.
28952895
// SetThreadContext would fail assuming that we are trying to bypass CFG.
2896-
//
2897-
// NB: the check here is slightly more strict than what OS requires,
2898-
// but it is simple and uses only documented parts of TEB
2899-
auto pTeb = this->GetTEB();
29002896
void* stackPointer = (void*)GetSP(pCtx);
2901-
if ((stackPointer < pTeb->StackLimit) || (stackPointer > pTeb->StackBase))
2897+
if ((stackPointer < this->GetCachedStackLimit()) || (stackPointer > this->GetCachedStackBase()))
29022898
{
29032899
return (FALSE);
29042900
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IThread.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public record struct ThreadData(
3838
TargetPointer AllocContextLimit,
3939
TargetPointer Frame,
4040
TargetPointer FirstNestedException,
41-
TargetPointer TEB,
4241
TargetPointer LastThrownObjectHandle,
4342
TargetPointer NextThread);
4443

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ ThreadData IThread.GetThreadData(TargetPointer threadPointer)
9898
thread.RuntimeThreadLocals?.AllocContext.GCAllocationContext.Limit ?? TargetPointer.Null,
9999
thread.Frame,
100100
firstNestedException,
101-
thread.TEB,
102101
thread.LastThrownObject.Handle,
103102
GetThreadFromLink(thread.LinkNext));
104103
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Thread.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ public Thread(Target target, TargetPointer address)
2323
CachedStackBase = target.ReadPointerField(address, type, nameof(CachedStackBase));
2424
CachedStackLimit = target.ReadPointerField(address, type, nameof(CachedStackLimit));
2525

26-
// TEB does not exist on certain platforms
27-
TEB = target.ReadPointerFieldOrNull(address, type, nameof(TEB));
2826
LastThrownObject = target.ProcessedData.GetOrAdd<ObjectHandle>(
2927
target.ReadPointerField(address, type, nameof(LastThrownObject)));
3028
LinkNext = target.ReadPointerField(address, type, nameof(LinkNext));
@@ -46,7 +44,6 @@ public Thread(Target target, TargetPointer address)
4644
public TargetPointer Frame { get; init; }
4745
public TargetPointer CachedStackBase { get; init; }
4846
public TargetPointer CachedStackLimit { get; init; }
49-
public TargetPointer TEB { get; init; }
5047
public ObjectHandle LastThrownObject { get; init; }
5148
public TargetPointer LinkNext { get; init; }
5249
public TargetPointer ExceptionTracker { get; init; }

0 commit comments

Comments
 (0)