What version of Go are you using (go version
)?
Go 1.21.0
Does this issue reproduce with the latest release?
Haven't yet tried Go 1.21.1.
What operating system and processor architecture are you using (go env
)?
plan9/amd64
What did you do?
A Plan 9 user (@9nut) sent me this crash trying to run Tailscale (go install tailscale.com/cmd/tailscaled
at https://github.com/tailscale/tailscale/commit/6fd1961cd70385568ac02c69a60d4f48314bd767). I don't have enough Plan 9 knowledge to debug or repro:
term% ./tailscaled --statedir $home/lib/tailscale
logtail started
Program starting: v1.49.0-dev20230830-tae747a2e4-dirty, Go 1.21.0: []string{"./tailscaled", "--statedir", "/usr/glenda/lib/tailscale"}
LogID: c07ea905679a33eba472be24f4634bb25d3f96ef1d7bb6fe2600cf86dd17c90a
logpolicy: using UserCacheDir, "/usr/glenda/lib/cache/Tailscale"
runtime: bad pointer in frame tailscale.com/logtail.(*Logger).Write at 0x480f59c0: 0x42
fatal error: invalid pointer found on stack
runtime stack:
runtime.throw({0xac1578?, 0x105cda?})
/Users/fst/go/src/runtime/panic.go:1077 +0x65 fp=0x7fffffffe930 sp=0x7fffffffe900 pc=0x237885
runtime.adjustpointers(0x7fffffffebb8?, 0x7fffffffea00, 0x0?, {0x0?, 0x0?})
/Users/fst/go/src/runtime/stack.go:627 +0x205 fp=0x7fffffffe9a0 sp=0x7fffffffe930 pc=0x24d6a5
runtime.adjustframe(0x7fffffffebb8, 0x7fffffffea98)
/Users/fst/go/src/runtime/stack.go:684 +0xdb fp=0x7fffffffea30 sp=0x7fffffffe9a0 pc=0x24d7db
runtime.copystack(0x4817e680, 0x800000002?)
/Users/fst/go/src/runtime/stack.go:935 +0x2ae fp=0x7fffffffed28 sp=0x7fffffffea30 pc=0x24df6e
runtime.newstack()
/Users/fst/go/src/runtime/stack.go:1116 +0x7e7 fp=0x7fffffffeed0 sp=0x7fffffffed28 pc=0x24e887
runtime.morestack()
/Users/fst/go/src/runtime/asm_amd64.s:593 +0x93 fp=0x7fffffffeed8 sp=0x7fffffffeed0 pc=0x2669d3
goroutine 9 [copystack]:
fmt.(*pp).printArg(0x4807e820?, {0x955f20?, 0x4801a498?}, 0x73?)
/Users/fst/go/src/fmt/print.go:681 +0x6f7 fp=0x480f5540 sp=0x480f5538 pc=0x300db7
fmt.(*pp).doPrintf(0x4807e820, {0xaa9d03, 0x2}, {0x480f58d8?, 0x1, 0x1})
/Users/fst/go/src/fmt/print.go:1077 +0x39e fp=0x480f5638 sp=0x480f5540 pc=0x3037fe
fmt.Appendf({0x481ae000, 0x0, 0x90}, {0xaa9d03, 0x2}, {0x4806f8d8, 0x1, 0x1})
/Users/fst/go/src/fmt/print.go:249 +0x7a fp=0x480f5698 sp=0x480f5638 pc=0x2fdaba
tailscale.com/logpolicy.logWriter.Write.(*Logger).Printf.func1({0x481ae000?, 0x4801a3c0?, 0x0?})
/Users/fst/go/src/log/log.go:269 +0x2c fp=0x480f56e8 sp=0x480f5698 pc=0x6de14c
log.(*Logger).output(0x48118750, 0x0, 0x90?, 0x4806f8e8)
/Users/fst/go/src/log/log.go:238 +0x36a fp=0x480f58b0 sp=0x480f56e8 pc=0x424cea
log.(*Logger).Printf(...)
/Users/fst/go/src/log/log.go:268
tailscale.com/logpolicy.logWriter.Write({0x481ae090?}, {0x481ae090?, 0x3c, 0x480469b0?})
/Users/fst/src/tailscale/logpolicy/logpolicy.go:195 +0xba fp=0x480f5928 sp=0x480f58b0 pc=0x6de0da
tailscale.com/logtail.(*Logger).Write(0x480bafc0, {0x481ae090?, 0x0?, 0x0?})
/Users/fst/src/tailscale/logtail/logtail.go:741 +0x16b fp=0x480f59d8 sp=0x480f5928 pc=0x5e49ab
log.(*Logger).output(0x4803e3f0, 0x0, 0x4e3485?, 0x4806fbc0)
/Users/fst/go/src/log/log.go:245 +0x483 fp=0x480f5ba0 sp=0x480f59d8 pc=0x424e03
log.Printf({0xacb8cc?, 0x48119080?}, {0x480469b0?, 0x1264420?, 0x10?})
/Users/fst/go/src/log/log.go:397 +0x6d fp=0x480f5c00 sp=0x480f5ba0 pc=0x42504d
tailscale.com/types/logger.RateLimitedFnWithClock.func1({0xacb8cc, 0x27}, {0x480469b0, 0x1, 0x1})
/Users/fst/src/tailscale/types/logger/logger.go:220 +0x7db fp=0x480f5cd8 sp=0x480f5c00 pc=0x4e24bb
main.createEngine(0x481239a0, 0x4807da40?)
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:571 +0x17e fp=0x480f5d90 sp=0x480f5cd8 pc=0x8f641e
main.getLocalBackend({0x0?, 0x0?}, 0x481239a0, {0xc0, 0x7e, 0xa9, 0x5, 0x67, 0x9a, 0x33, ...}, ...)
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:481 +0x11a fp=0x480f5ed0 sp=0x480f5d90 pc=0x8f4afa
main.startIPNServer.func2()
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:447 +0x28b fp=0x480f5fe0 sp=0x480f5ed0 pc=0x8f476b
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x480f5fe8 sp=0x480f5fe0 pc=0x268701
created by main.startIPNServer in goroutine 1
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:435 +0x4c5
goroutine 1 [runnable]:
context.WithValue({0xbe5ad8?, 0x481239f0?}, {0x9856a0?, 0x1250ca0?}, {0xa84a60?, 0x481ba000?})
/Users/fst/go/src/context/context.go:708 +0x192 fp=0x480f3a88 sp=0x480f3a80 pc=0x28ca72
net/http.(*Server).Serve(0x481ba000, {0xbe49a0, 0x48048400})
/Users/fst/go/src/net/http/server.go:3054 +0x30b fp=0x480f3bb8 sp=0x480f3a88 pc=0x4a1feb
tailscale.com/ipn/ipnserver.(*Server).Run(0x4804e900, {0xbe5ad8?, 0x481239f0}, {0xbe49a0?, 0x48048400})
/Users/fst/src/tailscale/ipn/ipnserver/server.go:521 +0x3bf fp=0x480f3c80 sp=0x480f3bb8 pc=0x8694df
main.startIPNServer({0xbe5a30, 0x12956a0}, 0x481239a0, {0xc0, 0x7e, 0xa9, 0x5, 0x67, 0x9a, 0x33, ...}, ...)
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:457 +0x4e6 fp=0x480f3d78 sp=0x480f3c80 pc=0x8f4286
main.run()
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:396 +0x49f fp=0x480f3e90 sp=0x480f3d78 pc=0x8f393f
main.main()
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:239 +0x8dd fp=0x480f3f38 sp=0x480f3e90 pc=0x8f31bd
runtime.main()
/Users/fst/go/src/runtime/proc.go:267 +0x2fb fp=0x480f3fe0 sp=0x480f3f38 pc=0x239e7b
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x480f3fe8 sp=0x480f3fe0 pc=0x268701
goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x48071fa0 sp=0x48071f80 pc=0x23a2ee
runtime.goparkunlock(...)
/Users/fst/go/src/runtime/proc.go:404
runtime.forcegchelper()
/Users/fst/go/src/runtime/proc.go:322 +0xa7 fp=0x48071fe0 sp=0x48071fa0 pc=0x23a127
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x48071fe8 sp=0x48071fe0 pc=0x268701
created by runtime.init.6 in goroutine 1
/Users/fst/go/src/runtime/proc.go:310 +0x1a
goroutine 3 [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x48072f78 sp=0x48072f58 pc=0x23a2ee
runtime.goparkunlock(...)
/Users/fst/go/src/runtime/proc.go:404
runtime.bgsweep(0x48052150?)
/Users/fst/go/src/runtime/mgcsweep.go:280 +0x94 fp=0x48072fc8 sp=0x48072f78 pc=0x2250b4
runtime.gcenable.func1()
/Users/fst/go/src/runtime/mgc.go:200 +0x25 fp=0x48072fe0 sp=0x48072fc8 pc=0x219fc5
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x48072fe8 sp=0x48072fe0 pc=0x268701
created by runtime.gcenable in goroutine 1
/Users/fst/go/src/runtime/mgc.go:200 +0x66
goroutine 4 [GC scavenge wait]:
runtime.gopark(0x48052150?, 0xbd70b0?, 0x1?, 0x0?, 0x48006d00?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x48073f70 sp=0x48073f50 pc=0x23a2ee
runtime.goparkunlock(...)
/Users/fst/go/src/runtime/proc.go:404
runtime.(*scavengerState).park(0x12646c0)
/Users/fst/go/src/runtime/mgcscavenge.go:425 +0x49 fp=0x48073fa0 sp=0x48073f70 pc=0x222909
runtime.bgscavenge(0x0?)
/Users/fst/go/src/runtime/mgcscavenge.go:653 +0x3c fp=0x48073fc8 sp=0x48073fa0 pc=0x222efc
runtime.gcenable.func2()
/Users/fst/go/src/runtime/mgc.go:201 +0x25 fp=0x48073fe0 sp=0x48073fc8 pc=0x219f65
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x48073fe8 sp=0x48073fe0 pc=0x268701
created by runtime.gcenable in goroutine 1
/Users/fst/go/src/runtime/mgc.go:201 +0xa5
goroutine 5 [finalizer wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x4806ce28 sp=0x4806ce08 pc=0x23a2ee
runtime.runfinq()
/Users/fst/go/src/runtime/mfinal.go:193 +0x107 fp=0x4806cfe0 sp=0x4806ce28 pc=0x219027
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x4806cfe8 sp=0x4806cfe0 pc=0x268701
created by runtime.createfing in goroutine 1
/Users/fst/go/src/runtime/mfinal.go:163 +0x3d
goroutine 6 [select]:
runtime.gopark(0x48070e08?, 0x2?, 0x2?, 0x0?, 0x48070dd4?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x48070c40 sp=0x48070c20 pc=0x23a2ee
runtime.selectgo(0x48070e08, 0x48070dd0, 0xd4?, 0x0, 0x1201ec0?, 0x1)
/Users/fst/go/src/runtime/select.go:327 +0x725 fp=0x48070d60 sp=0x48070c40 pc=0x249ce5
tailscale.com/logtail.(*Logger).drainBlock(...)
/Users/fst/src/tailscale/logtail/logtail.go:287
tailscale.com/logtail.(*Logger).drainPending(0x480bafc0, {0x48041000?, 0x1000?, 0x1296ac0?})
/Users/fst/src/tailscale/logtail/logtail.go:317 +0x1c5 fp=0x48070e60 sp=0x48070d60 pc=0x5e1c85
tailscale.com/logtail.(*Logger).uploading(0x480bafc0, {0xbe5ad8, 0x48123900})
/Users/fst/src/tailscale/logtail/logtail.go:361 +0xcf fp=0x48070fb8 sp=0x48070e60 pc=0x5e20af
tailscale.com/logtail.NewLogger.func3()
/Users/fst/src/tailscale/logtail/logtail.go:163 +0x28 fp=0x48070fe0 sp=0x48070fb8 pc=0x5e1768
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x48070fe8 sp=0x48070fe0 pc=0x268701
created by tailscale.com/logtail.NewLogger in goroutine 1
/Users/fst/src/tailscale/logtail/logtail.go:163 +0xa0c
goroutine 7 [syscall]:
runtime.notetsleepg(0x129b8e0?, 0x0?)
/Users/fst/go/src/runtime/lock_sema.go:294 +0x29 fp=0x4806dfa0 sp=0x4806df58 pc=0x20b789
os/signal.signal_recv()
/Users/fst/go/src/runtime/sigqueue_plan9.go:110 +0x52 fp=0x4806dfc0 sp=0x4806dfa0 pc=0x264d92
os/signal.loop()
/Users/fst/go/src/os/signal/signal_plan9.go:27 +0x13 fp=0x4806dfe0 sp=0x4806dfc0 pc=0x852193
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x4806dfe8 sp=0x4806dfe0 pc=0x268701
created by os/signal.Notify.func1.1 in goroutine 1
/Users/fst/go/src/os/signal/signal.go:151 +0x1f
goroutine 8 [select]:
runtime.gopark(0x4806efb0?, 0x2?, 0x0?, 0x0?, 0x4806ef7c?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x4806ee20 sp=0x4806ee00 pc=0x23a2ee
runtime.selectgo(0x4806efb0, 0x4806ef78, 0x0?, 0x0, 0x0?, 0x1)
/Users/fst/go/src/runtime/select.go:327 +0x725 fp=0x4806ef40 sp=0x4806ee20 pc=0x249ce5
main.startIPNServer.func1()
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:420 +0xbc fp=0x4806efe0 sp=0x4806ef40 pc=0x8f493c
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x4806efe8 sp=0x4806efe0 pc=0x268701
created by main.startIPNServer in goroutine 1
/Users/fst/src/tailscale/cmd/tailscaled/tailscaled.go:419 +0x2a9
goroutine 10 [select]:
runtime.gopark(0x481b6fb0?, 0x2?, 0x0?, 0x0?, 0x481b6f9c?)
/Users/fst/go/src/runtime/proc.go:398 +0xce fp=0x481b6e40 sp=0x481b6e20 pc=0x23a2ee
runtime.selectgo(0x481b6fb0, 0x481b6f98, 0x0?, 0x0, 0x0?, 0x1)
/Users/fst/go/src/runtime/select.go:327 +0x725 fp=0x481b6f60 sp=0x481b6e40 pc=0x249ce5
tailscale.com/ipn/ipnserver.(*Server).Run.func2()
/Users/fst/src/tailscale/ipn/ipnserver/server.go:491 +0x8c fp=0x481b6fe0 sp=0x481b6f60 pc=0x8698ac
runtime.goexit()
/Users/fst/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0x481b6fe8 sp=0x481b6fe0 pc=0x268701
created by tailscale.com/ipn/ipnserver.(*Server).Run in goroutine 1
/Users/fst/src/tailscale/ipn/ipnserver/server.go:490 +0x1be
term%
term%
What did you expect to see?
Not a crash in runtime.copystack
.
What did you see instead?
A crash.
Comment From: randall77
The offending stack slot is SP+0x98
in tailscale.com/logtail.(*Logger).Write(SB)
.
It is a pointer slot, and is initialized here:
logtail.go:734 0x5e76a2 66440fd6bc2498000000 MOVQ X15, 0x98(SP)
If X15
wasn't properly initialized to 0, that might be the issue. I recall plan9 has some strange interactions with floating-point (can't be used in signal handlers?). This could also be the result of some plan9 assembly that doesn't properly zero X15
on transitions from abi0
to abiInternal
(which would be in assembly somewhere).
The other write to SP+0x98
can't be the problem, as it is of a known stack pointer.
logtail.go:751 0x5e7888 4c8d842488000000 LEAQ 0x88(SP), R8
logtail.go:751 0x5e7890 4c89842498000000 MOVQ R8, 0x98(SP)
Comment From: cherrymui
We should already don't use X15 for zeroing on Plan 9. The rewriting rules for MOVOstoreconst
and DUFFZERO
are guarded with useSSE
and !noDuffDevice
, which are false on Plan 9.
Hmmm, https://cs.opensource.google/go/go/+/master:src/cmd/compile/internal/amd64/ggen.go;l=66 this one is not guarded. Maybe this is the problem.
Comment From: cherrymui
Looks like CL https://go.dev/cl/453536 is the culprit. It added a new use of X15 without the guard.
Comment From: bradfitz
@cherrymui, nice find! I look forward to what a test for this will look like 😅
Comment From: cherrymui
For a test, I guess we could have an assembly function that clobbers X15, then call a function with a certain frame layout which would trigger the zeroing code, then check it is actually zeroed. The ABI wrapper between assembly and Go would zero X15, but I think we don't do that on Plan 9, so we can keep X15 clobbered.
Maybe we could have the compiler just error out if X15 (or any SSE) is used on Plan 9 in compiled code? (We should probably want to allow assembly code.)
Comment From: rminnich
I am wondering, since you are using SSE: should you be testing for buildcfg.GOAMD64 > 1, not isPlan9? I got burned at google by SSE when GOAMD64 got defaulted to v2 and I ran on an amd64 machine that did not have SSE enabled. We fixed the glitch, but added GOAMD64=v1 to the build environment. Is this a similar case? Using x15 without checking GOAMD64 seems dicey to me.
Comment From: randall77
@rminnich I'm not sure what you are referring to - maybe 386? Because our amd64 architecture port requires SSE, and has since Go was released.
Comment From: mdempsky
Removing release blocker since Plan 9 isn't a first class port.
Comment From: 9nut
@bradfitz @cherrymui the change to cmd/compile/internal/amd64/ggen.go:65 didn't fix the crash.
I think I found a second contributor or the cause; it is in runtime/stack.go:72. Both diffs are in go1-21-2-diffs.txt. Does it look reasonable?
Empirically, one or both fixes resolve the issue.
Comment From: randall77
I don't understand what the stack fix is doing. It's just increasing the reserved stack for plan9 from 512 bytes to 4096 bytes. Is there some reason plan9 needs that extra stack? It doesn't sound like it is directly related to the X15
problem.
Comment From: orangecms
Looking at ggen.go's history: https://github.com/golang/go/commit/326df693d700fa42c2740dcc89a14c821d019f52
This commit switches from using R13 to using X15, saying:
Use XORL and X15 for zeroing in ggen's zerorange on AMD64
Prefer a SSE store from X15 over XORL REG REG -> MOVQ.
Use XORL REG, REG to setup 0 for REP STOS.
Comment From: bradfitz
@cherrymui, @randall77, any thoughts on the mentioned ggen.go change?
Comment From: orangecms
See also notes here on how Plan 9 uses X15 as an exception: https://tip.golang.org/src/cmd/compile/abi-internal
Except on Plan 9, where X15 is a scratch register because SSE registers cannot be used in note handlers (so the compiler avoids using them except when absolutely necessary).
Comment From: rsc
@bradfitz pointed this bug out to me. I think we should just fix the Plan 9 kernel and then not have a weird special case to worry about in Go anymore. @9nut where can I get the sources for the kernel you are using? Thanks.
Comment From: rsc
I downloaded the latest cd image from 9p.io and worked on the kernel.
fpnotediffs.txt is the diff I've applied to allow the use of floating-point in note handlers. The note handler starts with a copy of the FP state that the process had when the note came in, but then when the note handler is done, that note-specific state is discarded, leaving the original unmodified.
fptest.c.txt is a test program that now passes.
Comment From: rsc
I've been running a 386 kernel it turns out. https://go.dev/wiki/Plan9 mentions a 9k kernel, but I followed that link and don't see any kernel configs under /sys/src/9k for amd64 kernels. All I see is k10 for objtype=k10. It also links to 9front but I downloaded their qcow2 file and it couldn't run the vga under qemu, which the 386 kernel from 9p.io had no problem with. I guess I should debug the 9front vga?
Comment From: 0intro
The 9k kernel (Jim McKie's kernel + patches) is available as part of 9legacy. It's part of the CD image available here: http://9legacy.org/download/9legacy.iso.bz2 It should run fine on either QEMU or GCE.
Comment From: rsc
I got the 9legacy kernel booted, and I tried the go1.24.0 binaries, and immediately got a crash in runtime.lockVerifyMSize. It appears the padding trick is not quite right for GOOS=plan9 and the m is a little too small.
I tried the go1.23.6 binaries, and they worked, so then I tried editing the m struct padding in go1.24.0 and running make.rc. The (unmodified) 9k10f kernel immediately panicked, and QEMU reset the screen before I could read it. I will have to arrange for serial output. Not a promising start.
Comment From: 0intro
For 9k, you could try to set the available memory to <= 3 GB.
Comment From: rsc
Interesting comment. The kernel panic is in mmuput trying to handle a page fault.
I am running qemu with -m 1G.
At startup the kernel prints: 1020M memory: 2832K+220M kernel, 798M user, 0M lost
, which matches.
So I think I'm <=3GB but the problem is definitely somehow memory related.
term% . stk
src(0xfffffffff011b786); // dumpstack+0x10
src(0xfffffffff0157b6f); // panic+0x122
src(0xfffffffff011b96c); // faultamd64+0x12d
src(0xfffffffff011aee4); // trap+0x124
src(0xfffffffff01104a3); // _intrr
//passing interrupt frame; last pc found at sp=0xfffffffff1bd35f8
src(0xfffffffff0115d4e); // mmuput+0x115
src(0xfffffffff01a4acd); // qunlock+0xbe
src(0xfffffffff019bc08); // fixfault+0x17f
src(0xfffffffff019b977); // fault+0xee
src(0xfffffffff011b91d); // faultamd64+0xde
src(0xfffffffff011aee4); // trap+0x124
src(0xfffffffff01104a3); // _intrr
//passing interrupt frame; last pc found at sp=0xfffffffff1bd3978
term% acid /n/9fat/9k10f
/n/9fat/9k10f:amd64 plan 9 boot image
/sys/lib/acid/port
/sys/lib/acid/amd64
acid: src(0xfffffffff0115d4e); // mmuput+0x115
/sys/src/9k/k10/mmu.c:214
209 }
210 page->daddr = x;
211 page->next = up->mmuptp[l];
212 up->mmuptp[l] = page;
213 page->prev = prev;
>214 *pte = PPN(page->pa)|PteU|PteRW|PteP;
215 if(l == 3 && x >= m->pml4->daddr)
216 m->pml4->daddr = x+1;
217 }
218 prev = page;
219 }
acid: src(0xfffffffff01a4acd); // qunlock+0xbe
/sys/src/9k/port/qlock.c:92
87 ready(p);
88 return;
89 }
90 q->locked = 0;
91 q->qpc = 0;
>92 unlock(&q->use);
93 }
94
95 void
96 rlock(RWlock *q)
97 {
acid: src(0xfffffffff019bc08); // fixfault+0x17f
/sys/src/9k/port/fault.c:197
192 qunlock(&s->lk);
193
194 if(dommuput)
195 mmuput(addr, mmuphys, *pg);
196
>197 return 0;
198 }
199
200 void
201 pio(Segment *s, uintptr addr, uintptr soff, Page **p, int color)
202 {
acid:
Comment From: rsc
For what it's worth, I reproduced this on the 9k amd64 kernel using Go 1.21.0. Then I changed to a kernel that allows floating point and SSE in note handlers and deleted all the isPlan9 code from amd64/ggen.go and related places (full diff below), and that made the crash go away. So that approach seems like a good path forward.
The crash also seems to be gone at current master, although I can't tell whether that's because something got fixed independently or something got stirred around.
The one wrinkle is that I have a basic test of floating point registers surviving interruption by a note during a computation, and it fails on the 9k amd64 kernel, both with and without my kernel patch, at least on qemu (both using tcg on M3 Mac and using kvm on AMD Linux). I wouldn't want to commit to using SSE until we figure out that problem too.
diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
index db98a22a1e..1dc952a455 100644
--- a/src/cmd/compile/internal/amd64/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -10,12 +10,8 @@ import (
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/x86"
- "internal/buildcfg"
)
-// no floating point in note handlers on Plan 9
-var isPlan9 = buildcfg.GOOS == "plan9"
-
// DUFFZERO consists of repeated blocks of 4 MOVUPSs + LEAQ,
// See runtime/mkduff.go.
const (
@@ -64,7 +60,7 @@ func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.
if cnt == 8 {
p = pp.Append(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off)
- } else if !isPlan9 && cnt <= int64(8*types.RegSize) {
+ } else if cnt <= int64(8*types.RegSize) {
for i := int64(0); i < cnt/16; i++ {
p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+i*16)
}
@@ -72,7 +68,7 @@ func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.
if cnt%16 != 0 {
p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+cnt-int64(16))
}
- } else if !isPlan9 && (cnt <= int64(128*types.RegSize)) {
+ } else if cnt <= int64(128*types.RegSize) {
// Save DI to r12. With the amd64 Go register abi, DI can contain
// an incoming parameter, whereas R12 is always scratch.
p = pp.Append(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_DI, 0, obj.TYPE_REG, x86.REG_R12, 0)
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 113875861c..c599188f14 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -6,7 +6,6 @@ package amd64
import (
"fmt"
- "internal/buildcfg"
"math"
"cmd/compile/internal/base"
@@ -1058,9 +1057,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
case ssa.OpAMD64CALLstatic, ssa.OpAMD64CALLtail:
if s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal {
// zeroing X15 when entering ABIInternal from ABI0
- if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9
- opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
- }
+ opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
// set G register from TLS
getgFromTLS(s, x86.REG_R14)
}
@@ -1071,9 +1068,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
s.Call(v)
if s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 {
// zeroing X15 when entering ABIInternal from ABI0
- if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9
- opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
- }
+ opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
// set G register from TLS
getgFromTLS(s, x86.REG_R14)
}
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 43f9f0affc..a1d8edbfd8 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -11,7 +11,6 @@ import (
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
- "internal/buildcfg"
)
// A Config holds readonly compilation information.
@@ -377,18 +376,6 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize)
c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize)
- // On Plan 9, floating point operations are not allowed in note handler.
- if buildcfg.GOOS == "plan9" {
- // Don't use FMA on Plan 9
- c.UseFMA = false
-
- // Don't use Duff's device and SSE on Plan 9 AMD64.
- if arch == "amd64" {
- c.noDuffDevice = true
- c.useSSE = false
- }
- }
-
if ctxt.Flag_shared {
// LoweredWB is secretly a CALL and CALLs on 386 in
// shared mode get rewritten by obj6.go to go through
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index edf0909a77..32b1f7d8a3 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -1668,9 +1668,7 @@ TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
TEXT ·sigpanic0(SB),NOSPLIT,$0-0
get_tls(R14)
MOVQ g(R14), R14
-#ifndef GOOS_plan9
XORPS X15, X15
-#endif
JMP ·sigpanic<ABIInternal>(SB)
// gcWriteBarrier informs the GC about heap pointer writes.