Repository navigation
runtime: windows: a fault while printing an exception hangs the process instead of exiting #81944
Description
Go version
go1.27.1 and master (be1160f), windows/386.
What operating system and processor architecture are you using?
Windows Server 2025 (WoW64), Intel Xeon 8488C.
What did you do?
Ran this program, built with GOARCH=386, on 64-bit Windows. It triggers #71818 / #79249, which hands Go's exception handler a garbage exception record and context.
package main
import (
"fmt"
"io"
"runtime"
"runtime/pprof"
"sync"
"time"
)
func fault() {
defer func() { recover() }()
var p *int
*p = 1
}
func main() {
// Profile at 1 kHz so threads are suspended often. (StartCPUProfile
// then warns that the rate is already set; that is expected.)
runtime.SetCPUProfileRate(1000)
pprof.StartCPUProfile(io.Discard)
go func() {
for {
runtime.GC()
}
}()
for start := time.Now(); time.Since(start) < time.Minute; {
var wg sync.WaitGroup
for i := 0; i < 8; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 50; j++ {
fault()
}
}()
}
wg.Wait()
}
fmt.Println("OK")
}What did you see happen?
Every run (go1.27.1: 4/4; master: 5/5) printed a complete crash report and then hung, using no CPU, until it was killed. Abridged:
Exception 0x100c7 0xf68f88e8 0x8c483ff 0x0
PC=0x0
fatal error: unexpected signal during runtime execution
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x8020c8]
runtime stack:
runtime.throw(...)
runtime.sigpanic()
runtime.(*unwinder).initAt(...)
runtime.traceback1(...)
runtime.tracebacktrap(...)
runtime.winthrow(...)
runtime.lastcontinuehandler(...)
...
[all goroutines]
<hang>
The #71818 builder logs show the same thing: a crash report, then "Test killed: ran too long (4m0s)".
The hang has nothing to do with WoW64. Any fault inside winthrow can trigger it:
winthrowmarks the process as panicking withpanicking.Store(1)directly, som.dyingstays 0.- Its
tracebacktrapfaults on the garbage context (PC=0, SP=0). The nestedthrow→startpanic_mseesdying == 0, so it incrementspanickingto 2. dopanic_mdecrements it to 1, concludes that "some other m is panicking", and callslock(&deadlock)twice. That thread waits forever for itself.
A full dump of a hung process shows the throwing thread in dopanic_m → lock2 → semasleep.
What did you expect to see?
The process exits with status 2 after printing the crash report.
Fix
https://go.dev/cl/423137 (@prattmic, 2022) changes winthrow to use startpanic_m, which fixes this hang for the reproducer (its 2022 TryBot run failed TestG0StackOverflow on Windows, so it needs re-checking against current master). With it applied to master be1160f, all 237 runs exited promptly with status 2. 235 showed the Exception 0x100c7 crash; the other 2 failed with "unexpected return pc", which is the same corruption.
Possibly related: #50144.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
gabyhelp commentedon Oct 1, 2026
Related Issues
Related Code Changes
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
dmitshur commentedon Oct 5, 2026
CC @golang/windows, @golang/runtime.