0XC0000373

Stack Switch Error 0xC0000373: Memory Fixes

This Windows error means a thread couldn't switch stacks because the system ran out of memory. The fix is usually adjusting heap limits or fixing a corrupt process heap.

Heap corruption is the real culprit

The error name is misleading. What's actually happening here is not a simple "out of memory" situation. The system tried to perform a stack switch — which normally happens when a thread triggers a guard page or needs to grow its stack — but the heap that manages thread stacks is corrupted. The code 0xC0000373 is actually STATUS_HEAP_CORRUPTION in the NT status space, even though the win32 error string says "stack switch".

The most common trigger is a buffer overflow or use-after-free bug in a C/C++ application that overwrites the heap metadata for the thread's stack allocation. I've seen this in Visual Studio debug builds that use extensive logging and string formatting — one wrong sprintf overwrites the heap chunk header.

Fix: Enable Application Verifier and page heap

Don't guess. Use Application Verifier (appverif.exe) with page heap enabled. This catches heap corruptions at the exact instruction that caused them.

  1. Run appverif.exe as Administrator
  2. Add your executable under "File" → "Add Application"
  3. Check "Basics" → "Heaps" and enable "Page Heap"
  4. Click "Save"
  5. Reproduce the crash — the debugger will break on the overflow, not the crash

The reason this works: Page heap puts every heap allocation in its own virtual page with a guard page after it. The moment your code writes past the buffer, you get an access violation at the source, not a delayed heap corruption. Without this, the corruption stays latent until the next heap operation, which could be the stack switch attempt.

If you can't repro under AppVerifier, check for race conditions — two threads writing to the same heap-allocated buffer without synchronization is classic.

Thread stack exhaustion from deep recursion or large locals

The second cause: you're running out of stack space, but the system's attempt to commit more stack pages fails because the process's total committed memory is near the limit. This happens in 32-bit processes on 64-bit Windows where the virtual address space is only 2 GB (or 3 GB with /LARGEADDRESSAWARE).

I fixed this once in a server app that processed deeply nested JSON: the recursion wasn't infinite, but each call allocated a char buffer[8192] on the stack. After about 200 levels, the stack hit the default 1 MB reserve and the commit failed.

Fix: Increase stack reserve size or reduce locals

Two ways:

  1. Change linker stack size: In Visual Studio, add /STACK:4194304,1048576 (4 MB reserve, 1 MB initial commit) under Project → Properties → Linker → System → Stack Reserve Size. Or pass -Wl,--stack,4194304 to GCC/MinGW.
  2. Move large local buffers to heap: Change char buffer[8192] to char* buffer = malloc(8192) and free it. This reduces per-call stack usage from 8 KB to maybe 8 bytes (pointer).

Don't just bump the stack to 10 MB blindly. That increases commit charge per thread. If you have 100 threads, that's 1 GB committed just for stacks. Keep them small and use heap for large data.

Exhaustion of thread stack slots in kernel

The third less common cause: the Windows kernel maintains a cache of stack slots for each process, and you've run out. This is rare but I've seen it in high-load servers that spawn thousands of threads in rapid succession.

Windows has a limit of about 2000 stacks per process before the system denies stack allocations. You hit 0xC0000373 instead of a clean STATUS_NO_MEMORY because the internal allocation routine corrupts the stack's heap entry when it can't find a free slot.

Fix: Throttle thread creation or use thread pool

  1. Replace CreateThread with QueueUserWorkItem or the newer ThreadPool API (Windows Vista+). The thread pool reuses stack slots efficiently.
  2. If you must create threads manually, limit the total to under 500 and use a semaphore to serialize spawning.

The thread pool avoids this entirely because it pre-allocates a fixed pool of stacks and recycles them. It's also faster — context switches cost less when threads are warm.

Quick-reference summary

Cause Symptom Fix
Heap corruption (buffer overflow on heap) Crash random, hard to repro, possible only in release builds Enable AppVerifier with page heap, fix overflow at instruction
Stack exhaustion from deep recursion or large locals Crash after specific call depth, works fine with small inputs Increase stack reserve size or move locals to heap
Thread stack slot exhaustion Crash under high concurrent thread count (500+) Use thread pool or cap manual thread creation

One last thing: if you're running a .NET application and see this, the stack switch error usually comes from native code interop (P/Invoke) or the CLR's own heap corruption — which is rare but possible. Run gflags.exe /p /enable /full to enable full page heap on the process. Same logic as AppVerifier, different tool.

Related Errors in Programming & Dev Tools
0X000000CF Fix ERROR_RING2_STACK_IN_USE (0X000000CF) on Windows 10/11 0X0000021E ERROR_UNWIND 0X0000021E: Exception unwind code in Windows 10/11 fixes 0X000002B1 ERROR_DBG_REPLY_LATER (0X000002B1) Fix – Debugger Blocked 0X00000300 Fix ERROR_CALLBACK_POP_STACK 0x00000300 on Windows 10/11

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.