What version of Go are you using (go version
)?
$ go version go version go1.16.5 darwin/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/Users/juancivile/Library/Caches/go-build" GOENV="/Users/juancivile/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/juancivile/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/Cellar/go/1.16.5/libexec" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/Cellar/go/1.16.5/libexec/pkg/tool/darwin_amd64" GOVCS="" GOVERSION="go1.16.5" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/ln/73tvl7md2l7gqpbkzq439dcc0000gn/T/go-build3867799831=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
I have an iOS project using a go library via gomobile:
* Running on an arm64 device (any modern iPhone)
* Calling a method that takes and returns []byte
* A ton of invocations. This is affecting randomly about 1-2% of users of our app.
The golang code is simple:
type Panicker interface {
Panic([]byte) ([]byte, error)
}
type PanickerImpl struct {
}
func (p *PanickerImpl) Panic(b []byte) ([]byte, error) {
return make([]byte, len(b)), nil
}
func Init() {
debug.SetTraceback("crash")
}
And on swift:
PanickerInit()
let p = PanickerPanickerImpl()
let d = Data(repeating: 1, count: 10)
for _ in 1...10_000_000 {
let r = try p.panic(d)
XCTAssertEqual(r.count, d.count)
}
A full working reproduction project is at https://github.com/champo/gomobile_panic
What did you expect to see?
No crash.
What did you see instead?
It sometimes crashes inside bulkBarrierPreWrite
:
fatal error: bulkBarrierPreWrite: unaligned arguments
goroutine 17 [running, locked to thread]:
runtime.throw(0x1014aeaa4, 0x28)
runtime/panic.go:1117 +0x54 fp=0x130582d30 sp=0x130582d00 pc=0x1014373d4
runtime.bulkBarrierPreWrite(0x16f5e483c, 0x130582e68, 0x8)
runtime/mbitmap.go:554 +0x44c fp=0x130582dd0 sp=0x130582d30 pc=0x101419f0c
runtime.typedmemmove(0x1014e0000, 0x16f5e483c, 0x130582e68)
runtime/mbarrier.go:161 +0xa4 fp=0x130582e10 sp=0x130582dd0 pc=0x1014190c4
_cgoexp_59f89a9c1f1d_proxypanicker_PanickerImpl_Panic(0x16f5e4824)
_cgo_gotypes.go:183 +0xe8 fp=0x130582e80 sp=0x130582e10 pc=0x1014a3068
runtime.cgocallbackg1(0x1014a2f80, 0x16f5e4824, 0x0)
runtime/cgocall.go:292 +0x140 fp=0x130582f40 sp=0x130582e80 pc=0x10140a9e0
runtime.cgocallbackg(0x1014a2f80, 0x16f5e4824, 0x0)
runtime/cgocall.go:228 +0xb0 fp=0x130582fb0 sp=0x130582f40 pc=0x10140a810
runtime.cgocallback(0x0, 0x0, 0x0)
runtime/asm_arm64.s:1055 +0x98 fp=0x130582fe0 sp=0x130582fb0 pc=0x1014687f8
runtime.goexit()
runtime/asm_arm64.s:1130 +0x4 fp=0x130582fe0 sp=0x130582fe0 pc=0x1014688d4
I tried exposing a free function with a similar signature but no crashers there. Removing the paramters or return values seems to avoid the crash too.
Comment From: rayvbr
I've encountered this problem as well in the past, issue started with Go 1.16 (1.15 seems unaffected). In my case I had a function signature func DoSomething(i int32, s string) (string, error)
. Changing that to func DoSomething(s string, i int32) (string, error)
resolved the issue. I never really understood why
Comment From: hilariocoelho
I had the same issue using Go 1.16. Reverted to Go 1.13 and it works fine. Also just affected a few users and couldn't reproduce it consistently.
Comment From: marinthiercelin
I have experienced the same issue using https://github.com/ProtonMail/gopenpgp in an iOS app (with gomobile). The issue has been reproduced when building the library with golang 1.16, 1.16.5 and 1.16.6. Building with golang 1.15.14 works fine.
Comment From: elagergren-spideroak
Can consistently repro with 1.17.x on iOS. It occurs when calling into Go from C. The stack frame C sets up for Go is four-byte aligned, which makes it likely that the address of the results aren't properly aligned, and therefore casues typedmemmove
to crash. For exampe: _cgoexp_432d4433717a_proxygolib_Client_Query(0x16f8557d4)
.
I think this is a cmd/cgo
problem, not x/mobile
. cc: @ianlancetaylor
Comment From: elagergren-spideroak
An update: we patched cmd/cgo
with __attribute__((aligned(8)))
and it fixes the problem.
Comment From: hilariocoelho
@elagergren-spideroak when should we expect a release that fixes it, do you have any idea?
Comment From: elagergren-spideroak
I am not a member of the Go team, so I am not the person to ask. However, I'm going to submit a CL with the patch to get things started.
Comment From: sanderdekoning
Bump - just ran into this: fatal error: bulkBarrierPreWrite: unaligned arguments
Comment From: sanderdekoning
@elagergren-spideroak just to know if I/we can assist in any way, the current status is what exactly? Thanks for letting us know how you fixed it!
Comment From: champo
@elagergren-spideroak thanks for looking into this! Did you get a chance to make the CL? If you didn't, I'd really appreciate a gist so I can patch locally for the time being. I just got a new batch of ocurrences of this I can't seem to sidestep :(
Comment From: elagergren-spideroak
How we've fixed it for our iOS builds is by replacing https://github.com/golang/go/blob/97e740e8b0ff1b32b164b0cbef06c12c4d591f3f/src/cmd/cgo/out.go#L1005 with
fmt.Fprintf(fgcc, "\ttypedef %s %v __attribute__((aligned(8))) _cgo_argtype;\n", ctype, p.packedAttribute())
Comment From: champo
Thanks @elagergren-spideroak! Just tested it out and works great 👌
Comment From: alock
I am not a member of the Go team, so I am not the person to ask. However, I'm going to submit a CL with the patch to get things started.
@elagergren-spideroak Where you able to create a CL? If so can you share the link to follow here.
Comment From: gopherbot
Change https://go.dev/cl/408395 mentions this issue: cmd/cgo: fix unaligned arguments typedmemmove crash on iOS
Comment From: lixin9311
Thanks for the fix. It fixed our runtime.raise_trampoline
crashed.
Comment From: junyang100
I just started using Golang. Can anyone tell me if I need to recompile the Golang or just need to rebuild my project after I change the source code
Comment From: jeffrrogers
@gopherbot This still seems to be an issue when running on ARM architecture (MacOS M1 or iOS devices). We compiled our framework with Go version 1.19.4 on both Intel and M1 machines, and it runs fine on Intel machine simulators, but crashes intermittently on M1 machine simulators and iOS devices. This was supposed to be fixed in 1.19.2 right? Here is the stack trace we get for our crash:
fatal error: bulkBarrierPreWrite: unaligned arguments
goroutine 17 [running, locked to thread]: runtime.throw({0x1013583ac?, 0x1300ddd08?}) /usr/local/go/src/runtime/panic.go:1047 +0x40 fp=0x1300ddce0 sp=0x1300ddcb0 pc=0x101095a90 runtime.bulkBarrierPreWrite(0x1300ddd78?, 0x0?, 0x130543530?) /usr/local/go/src/runtime/mbitmap.go:582 +0x420 fp=0x1300ddd50 sp=0x1300ddce0 pc=0x1010759c0 runtime.typedmemmove(0x1014ba460, 0x16f4eb6bc, 0x1300ddde8) /usr/local/go/src/runtime/mbarrier.go:162 +0x48 fp=0x1300ddd90 sp=0x1300ddd50 pc=0x101074bd8 _cgoexp_409b037657a8_proxyswiftgold_SwiftGoLD_Normalize(0x16f4eb6a4) _cgo_gotypes.go:168 +0xa4 fp=0x1300dde00 sp=0x1300ddd90 pc=0x1012900d4 runtime.cgocallbackg1(0x101290030, 0x1300ddfe0?, 0x0) /usr/local/go/src/runtime/cgocall.go:316 +0x244 fp=0x1300ddef0 sp=0x1300dde00 pc=0x1010653a4 runtime.cgocallbackg(0x0?, 0x0?, 0x0?) /usr/local/go/src/runtime/cgocall.go:235 +0xd8 fp=0x1300ddf80 sp=0x1300ddef0 pc=0x1010650d8 runtime.cgocallbackg(0x101290030, 0x16f4eb6a4, 0x0) :1 +0x1c fp=0x1300ddfb0 sp=0x1300ddf80 pc=0x1010c694c runtime.cgocallback(0x0, 0x0, 0x0) /usr/local/go/src/runtime/asm_arm64.s:1094 +0xa0 fp=0x1300ddfe0 sp=0x1300ddfb0 pc=0x1010c52b0 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1300ddfe0 sp=0x1300ddfe0 pc=0x1010c5384
goroutine 21 [GC worker (idle)]: runtime.gopark(0x18ff8289ace30?, 0x2?, 0x70?, 0x31?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x13003cf40 sp=0x13003cf20 pc=0x1010983d4 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1235 +0xec fp=0x13003cfd0 sp=0x13003cf40 pc=0x10107c20c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x13003cfd0 sp=0x13003cfd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
goroutine 2 [force gc (idle)]: runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x13003ffa0 sp=0x13003ff80 pc=0x1010983d4 runtime.goparkunlock(...) /usr/local/go/src/runtime/proc.go:369 runtime.forcegchelper() /usr/local/go/src/runtime/proc.go:302 +0xac fp=0x13003ffd0 sp=0x13003ffa0 pc=0x10109826c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x13003ffd0 sp=0x13003ffd0 pc=0x1010c5384 created by runtime.init.6 /usr/local/go/src/runtime/proc.go:290 +0x24
goroutine 3 [GC sweep wait]: runtime.gopark(0x1?, 0x0?, 0x0?, 0x0?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x130040f70 sp=0x130040f50 pc=0x1010983d4 runtime.goparkunlock(...) /usr/local/go/src/runtime/proc.go:369 runtime.bgsweep(0x0?) /usr/local/go/src/runtime/mgcsweep.go:297 +0x10c fp=0x130040fb0 sp=0x130040f70 pc=0x10108586c runtime.gcenable.func1() /usr/local/go/src/runtime/mgc.go:178 +0x28 fp=0x130040fd0 sp=0x130040fb0 pc=0x10107a0a8 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x130040fd0 sp=0x130040fd0 pc=0x1010c5384 created by runtime.gcenable /usr/local/go/src/runtime/mgc.go:178 +0x74
goroutine 4 [GC scavenge wait]: runtime.gopark(0x1f4dfcc?, 0xbf69ca?, 0x0?, 0x0?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x130041f50 sp=0x130041f30 pc=0x1010983d4 runtime.goparkunlock(...) /usr/local/go/src/runtime/proc.go:369 runtime.(*scavengerState).park(0x10171be40) /usr/local/go/src/runtime/mgcscavenge.go:389 +0x5c fp=0x130041f80 sp=0x130041f50 pc=0x1010837bc runtime.bgscavenge(0x0?) /usr/local/go/src/runtime/mgcscavenge.go:622 +0xac fp=0x130041fb0 sp=0x130041f80 pc=0x101083dcc runtime.gcenable.func2() /usr/local/go/src/runtime/mgc.go:179 +0x28 fp=0x130041fd0 sp=0x130041fb0 pc=0x10107a048 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x130041fd0 sp=0x130041fd0 pc=0x1010c5384 created by runtime.gcenable /usr/local/go/src/runtime/mgc.go:179 +0xb8
goroutine 18 [finalizer wait]: runtime.gopark(0x10171c6e0?, 0x130082340?, 0x0?, 0x0?, 0x1?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x13003ed80 sp=0x13003ed60 pc=0x1010983d4 runtime.goparkunlock(...) /usr/local/go/src/runtime/proc.go:369 runtime.runfinq() /usr/local/go/src/runtime/mfinal.go:180 +0x124 fp=0x13003efd0 sp=0x13003ed80 pc=0x1010792d4 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x13003efd0 sp=0x13003efd0 pc=0x1010c5384 created by runtime.createfing /usr/local/go/src/runtime/mfinal.go:157 +0x84
goroutine 19 [select, locked to thread]: runtime.gopark(0x13003afa0?, 0x2?, 0x88?, 0xae?, 0x13003af9c?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x13003ae30 sp=0x13003ae10 pc=0x1010983d4 runtime.selectgo(0x13003afa0, 0x13003af98, 0x0?, 0x0, 0x0?, 0x1) /usr/local/go/src/runtime/select.go:328 +0x68c fp=0x13003af50 sp=0x13003ae30 pc=0x1010a821c runtime.ensureSigM.func1() /usr/local/go/src/runtime/signal_unix.go:991 +0x190 fp=0x13003afd0 sp=0x13003af50 pc=0x1010ac2c0 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x13003afd0 sp=0x13003afd0 pc=0x1010c5384 created by runtime.ensureSigM /usr/local/go/src/runtime/signal_unix.go:974 +0xf4
goroutine 20 [syscall]: runtime.sigNoteSleep(0x0) /usr/local/go/src/runtime/os_darwin.go:123 +0x20 fp=0x13003bf90 sp=0x13003bf50 pc=0x101092c70 os/signal.signal_recv() /usr/local/go/src/runtime/sigqueue.go:149 +0x2c fp=0x13003bfb0 sp=0x13003bf90 pc=0x1010c183c os/signal.loop() /usr/local/go/src/os/signal/signal_unix.go:23 +0x1c fp=0x13003bfd0 sp=0x13003bfb0 pc=0x10128f74c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x13003bfd0 sp=0x13003bfd0 pc=0x1010c5384 created by os/signal.Notify.func1.1 /usr/local/go/src/os/signal/signal.go:151 +0x2c
goroutine 35 [runnable]: runtime.gcMarkDone() /usr/local/go/src/runtime/mgc.go:784 +0x304 fp=0x1305e6f40 sp=0x1305e6f40 pc=0x10107b044 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1367 +0x3c0 fp=0x1305e6fd0 sp=0x1305e6f40 pc=0x10107c4e0 runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1305e6fd0 sp=0x1305e6fd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
goroutine 36 [GC worker (idle)]: runtime.gopark(0x18ff819afa669?, 0x13045c800?, 0x18?, 0x14?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x1305e7f40 sp=0x1305e7f20 pc=0x1010983d4 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1235 +0xec fp=0x1305e7fd0 sp=0x1305e7f40 pc=0x10107c20c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1305e7fd0 sp=0x1305e7fd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
goroutine 5 [GC worker (idle)]: runtime.gopark(0x18ff7e15e0483?, 0x2?, 0x44?, 0x4f?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x1305e2f40 sp=0x1305e2f20 pc=0x1010983d4 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1235 +0xec fp=0x1305e2fd0 sp=0x1305e2f40 pc=0x10107c20c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1305e2fd0 sp=0x1305e2fd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
goroutine 37 [GC worker (idle)]: runtime.gopark(0x18ff82e592446?, 0x2?, 0x5e?, 0xa0?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x1305e8f40 sp=0x1305e8f20 pc=0x1010983d4 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1235 +0xec fp=0x1305e8fd0 sp=0x1305e8f40 pc=0x10107c20c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1305e8fd0 sp=0x1305e8fd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
goroutine 38 [GC worker (idle)]: runtime.gopark(0x18ff82e55881f?, 0x1?, 0x84?, 0x8f?, 0x0?) /usr/local/go/src/runtime/proc.go:363 +0xe4 fp=0x1305e9f40 sp=0x1305e9f20 pc=0x1010983d4 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1235 +0xec fp=0x1305e9fd0 sp=0x1305e9f40 pc=0x10107c20c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1172 +0x4 fp=0x1305e9fd0 sp=0x1305e9fd0 pc=0x1010c5384 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1159 +0x28
Comment From: randall77
I don't think this has actually been fixed yet. There is a CL (https://go-review.googlesource.com/c/go/+/408395) but it hasn't been checked in yet.
55122 has been fixed and backported, but I don't think that's the same issue as this one. This one has to do with cgo.
Comment From: stoffen
This issue persist on 1.21.5.
A slightly simpler repro of the issue (fatal error: bulkBarrierPreWrite: unaligned arguments
), run this in a tight loop from iOS on Apple Silicon:
func (p *Server) GoPanicIssue(_ string) ([]byte, error) {
return []byte{0}, nil
}
Not able to repro with the suggested cgo alignment fix
Comment From: arantes555
I ran into the same issue for the Go library we are writing: random crashes on iOS, with similar error messages.
I can confirm that a build done with a Go toolchain that includes the suggested fix does not crash.
Comment From: creamwhip
This is still an issue with the latest go 1.22.1 on arm64.
We've been running the suggested patch for some time, with no adverse effects, so why we can't just get it merged in is a complete mystery.
Is anyone watching these issues?
Comment From: randall77
The patch was never finished by the author. @ianlancetaylor
Comment From: creamwhip
@randall77 this is completely perfect as a fix:
How we've fixed it for our iOS builds is by replacing
https://github.com/golang/go/blob/97e740e8b0ff1b32b164b0cbef06c12c4d591f3f/src/cmd/cgo/out.go#L1005
with
fmt.Fprintf(fgcc, "\ttypedef %s %v __attribute__((aligned(8))) _cgo_argtype;\n", ctype, p.packedAttribute())
Comment From: randall77
Sure, it works, but that doesn't mean the patch is perfect. If you read the CL comments, it's not right for 32-bit systems, and there's no test.
Comment From: gopherbot
Change https://go.dev/cl/571375 mentions this issue: cmd/cgo: fix unaligned arguments typedmemmove crash on iOS
Comment From: stoffen
Our users can confirm this is a showstopper for us using GoMobile. Our apps renders useless without that patch. Have no idea how to express it in a test or fix it for 32-bits, though
ons. 13. mars 2024 kl. 20:25 skrev GopherBot @.***>:
Change https://go.dev/cl/571375 mentions this issue: cmd/cgo: fix unaligned arguments typedmemmove crash on iOS
— Reply to this email directly, view it on GitHub https://github.com/golang/go/issues/46893#issuecomment-1995484485, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJRBNRFEVHHQHNGE742JW3YYCR23AVCNFSM47GHEIEKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOJZGU2DQNBUHA2Q . You are receiving this because you commented.Message ID: @.***>
Comment From: ianlancetaylor
Although the patch seems to focus on forcing the alignment of a variable in cgo-generated code, the problem seems to be that the stack is not aligned to what Go expects. Is that correct? That suggests that a better fix would be to align the stack pointer when calling from C to Go.
Comment From: andrewmostello
To bump this issue: we ran into it in our first few days of experimenting with gomobile for our iOS project. As noted above, this (abandoned?) fix resolves the problem: https://go-review.googlesource.com/c/go/+/571375/5/src/cmd/cgo/out.go
I would not have expected to need to modify and compile the toolchain, but it seems like gomobile doesn't work without this for iOS. We're not doing anything special as far as I can tell, just a gomobile bind
library for an iOS app.
Comment From: notatestuser
For anyone still stuck with this issue, we have had luck upgrading to Go 1.24 which also fixed the possibly related #68760 with CL 600296.
Comment From: wcsiu
For anyone still stuck with this issue, we have had luck upgrading to Go 1.24 which also fixed the possibly related #68760 with CL 600296.
Hi @notatestuser . May I know which commit did you use to solve this issue? I have used 1.24.0 but the issue still persisted.
I could still see the "fatal error: bulkBarrierPreWrite: unaligned arguments" error using the test code provided above.
Comment From: notatestuser
@wcsiu are you running it on an iOS device? If so, which and how?
Comment From: MihaMarkic
I have a similar issue on Android where I would create a (go 1.24/gomobile provided) struct and when call it's function that returns me a string it'd crash with fatal error: bulkBarrierPreWrite: unaligned arguments
. If the crash doesn't happen at first call, that everything works fine.
Go struct is created in go code through a static method (I'm calling it through kotlin code like Target.newTarget(config)).
It happens randomly, like 5% of the times. So, to reproduce it, I'd call struct creation and this call in a loop (like 1000 times) and it'll happen 99,99%. It seems like it happens based on where the struct is created (aligned?). Testing on arm64 native and emulator.
Any idea what can I try or to provide more info?
Comment From: arantes555
I have recently also started seeing this problem pop up on Android also, though much more randomly than on iOS. It started on go 1.23 i believe. On iOS, it would crash almost all the time, whereas on Android it would be much more rare.
The same patch that fixes the crash on iOS also fixes it on Android for me.
Comment From: MihaMarkic
@arantes555 How reliable is that patch, though - I mean can it cause weird issues in other places?
Comment From: arantes555
@MihaMarkic been running with the patch more than a year, no problems
Comment From: arantes555
@MihaMarkic https://github.com/seald/docker-gomobile if you are interested
Comment From: wcsiu
@wcsiu are you running it on an iOS device? If so, which and how?
I ran the test code provided by champo using MacOS with emulator. The issue mentioned by champo still persisted.
Comment From: wcsiu
@arantes555 How reliable is that patch, though - I mean can it cause weird issues in other places?
Yes. I have the same concern. It seems @ianlancetaylor didn't think the patch was solving the root cause.
Comment From: notatestuser
@wcsiu are you running it on an iOS device? If so, which and how?
I ran the test code provided by champo using MacOS with emulator. The issue mentioned by champo still persisted.
Ok, I've tested that again and you're right- the issue is still there in that test project when using the latest Go & gomobile. We have seen the issue disappear from our project but I think it may be due to recent changes in the React Native JS-native bridge and the way it's passing down arguments to the Go library.
Comment From: ignoramous
I have a similar issue on Android where I would create a (go 1.24/gomobile provided) ... happens randomly ... happens based on where the struct is created (aligned?). Testing on arm64 native and emulator.
Any idea what can I try or to provide more info?
Can confirm this happens on Android SDK level 35 and NDK version 28b (which builds 0x4000-aligned ELFs) on go1.24.3. Probably because Android mandates all apps distributed via the Play Store support 16kb page sizes by Nov 2025.
Moving to prior NDK versions is something we're considering as a workaround, but then Nov 2025 deadline isn't that far off.
fatal error: bulkBarrierPreWrite: unaligned arguments
goroutine 71 gp=0x4000337c00 m=16 mp=0x4000099808 [running, locked to thread]:
runtime.throw({0x7b1117f068?, 0x21?})
/golang/go/src/runtime/panic.go:1101 +0x38 fp=0x4000037d50 sp=0x4000037d20 pc=0x7b1138b258
- runtime.bulkBarrierPreWrite(0x40003563c0?, 0x0?, 0x7b8264c2a0?, 0x42?)
- /golang/go/src/runtime/mbitmap.go:419 +0x318 fp=0x4000037dc0 sp=0x4000037d50 pc=0x7b1132fb18
- runtime.wbMove(0x7b8264c2a0?, 0x42?, 0x4000037e38?)
- /golang/go/src/runtime/mbarrier.go:197 +0x24 fp=0x4000037df0 sp=0x4000037dc0 pc=0x7b1132f0e4
_cgoexp_29b0ac2c73f7_proxybackend_Proxies_RefreshProxies(0x7ab5b1bae4)
_cgo_gotypes.go:7523 +0x58 fp=0x4000037e40 sp=0x4000037df0 pc=0x7b119daf68
runtime.cgocallbackg1(0x7b119daf10, 0x7ab5b1bae4, 0x0)
/golang/go/src/runtime/cgocall.go:446 +0x264 fp=0x4000037f10 sp=0x4000037e40 pc=0x7b11324fd4
runtime.cgocallbackg(0x7b119daf10, 0x7ab5b1bae4, 0x0)
/golang/go/src/runtime/cgocall.go:350 +0x10c fp=0x4000037f80 sp=0x4000037f10 pc=0x7b11324c9c
runtime.cgocallbackg(0x7b119daf10, 0x7ab5b1bae4, 0x0)
<autogenerated>:1 +0x1c fp=0x4000037fb0 sp=0x4000037f80 pc=0x7b11394d1c
runtime.cgocallback(0x0, 0x0, 0x0)
/golang/go/src/runtime/asm_arm64.s:1131 +0xb0 fp=0x4000037fe0 sp=0x4000037fb0 pc=0x7b11392ff0
runtime.goexit({})
/golang/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4000037fe0 sp=0x4000037fe0 pc=0x7b113930e4
Comment From: randall77
@ignoramous I don't see what this issue has to do with 16KB page sizes.
This issue has to do with smaller alignments (addresses %8 != 0? %16 != 0? Not sure which).
Comment From: ignoramous
@ignoramous I don't see what this issue has to do with 16KB page sizes.
Gotcha. I based my guess on the fact that we started observing this misalignment only after moving to ndk28b (and on ndk27 with CGO_LDFLAGS="$(CGO_LDFLAGS) -s -w -Wl,-z,max-page-size=16384"
; on ndk22, ndk23 we've never hit this).
Comment From: gopherbot
Change https://go.dev/cl/692935 mentions this issue: cmd/cgo: fix unaligned arguments typedmemmove crash on iOS
Comment From: cherrymui
@ianlancetaylor
the problem seems to be that the stack is not aligned to what Go expects.
From the stack traces, the SP looks aligned. Generally the Go runtime doesn't require a stack alignment more than what the C ABI requires. So I guess the stack alignment is fine.
Comment From: ianlancetaylor
I think I made the stack alignment comment based on https://github.com/golang/go/issues/46893#issuecomment-996543189.
In any case bulkBarrierPreWrite
requires a pointer that is aligned to the pointer size, which in this case is 8. The test cases included in this issue are peculiar. They are cases in which Go code returns a slice ([]byte
) to C code. That is explicitly not permitted by cgo; see https://pkg.go.dev/cmd/cgo#hdr-Passing_pointers which says
A Go function called by C code may return a Go pointer to pinned memory (which implies that it may not return a string, slice, channel, and so forth).
But I'm not very familiar with how gomobile works, and perhaps there is something there that mitigates this.
Setting that issue aside, the generated C code for the original example will look something like this:
CGO_NO_SANITIZE_THREAD
struct Fn_return Fn(void)
{
size_t _cgo_ctxt = _cgo_wait_runtime_init_done();
typedef struct {
GoSlice r0;
GoInterface r1;
} __attribute__((__packed__, __gcc_struct__)) _cgo_argtype;
static _cgo_argtype _cgo_zero;
_cgo_argtype _cgo_a = _cgo_zero;
struct Fn_return r;
_cgo_tsan_release();
crosscall2(_cgoexp_3ca6191ef8c0_Fn, &_cgo_a, 40, _cgo_ctxt);
_cgo_tsan_acquire();
_cgo_release_context(_cgo_ctxt);
r.r0 = _cgo_a.r0;
r.r1 = _cgo_a.r1;
return r;
}
The GoInterface
and GoSlice
types are
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
Since they contain pointers, the _cgo_a
value should be aligned to a pointer boundary. But, it is marked as __packed__
so it is theoretically possible for it to have any alignment. That said, it's very odd that it would have anything other than the stack alignment. On amd64 the normal stack alignment on entry to a function is a 16 byte boundary. But this can be controlled using the C compiler option -mpreferred-stack-boundary
, and maybe gomobile is using that somewhere, or maybe the alignment is different on iOS.
We are using the __packed__
attributed to ensure that the struct we are writing in C matches the struct we expect in Go. Specifically, the Go code looks like this:
func _cgoexp_3ca6191ef8c0_Fn(a *struct {
r0 []byte
r1 error
}) {
a.r0, a.r1 = Fn()
_cgoCheckResult(a.r0)
_cgoCheckResult(a.r1)
}
The struct
used in that Go code must match _cgo_argtype
in the C code. Using __packed__
helps ensure that in general. But that ignores the alignment.
We actually have all the information we need to compute the alignment, so a likely-correct fix would be to change (*Package).writeExports
in cmd/cgo/out.go to compute the desired alignment of the struct, and to use that in the attribute list for _cgo_argtype
.
It would still be nice to have a test case that follows the cgo pointer passing rules.
Comment From: timcooijmans
I'm working on a test-case but so far no avail. Also fixed the PR.