go: runtime: mallocs cause "base outside usable address space" panic when running on iOS 14
What version of Go are you using (go version
)?
$ go version go version go1.16.5 darwin/amd64 (also reproducible on 1.15 and 1.14)
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
ios/arm64
What did you do?
Create a simple Go package, doing a few medium sized allocs (creating a few byte slices of several tens of MB will do, as long as it forces the Go runtime to ask the OS for more memory), compile it with gomobile to an iOS .framework file, use the resulting framework in an iOS project and compile and run for iOS 14.
If the iOS project doesn’t do a lot of memory allocs itself, everything works fine. If the iOS project does use reserve a lot of memory (either for CPU or GPU) before initialising the Go framework, the Go runtime crashes with the following panic.
runtime: memory allocated by OS [0x2ac000000, 0x2b0000000) not in usable address space: base outside usable address space
fatal error: memory reservation exceeds address space limit
Note that the exact amount of memory needed seems to be device dependent, although in all cases the panic happens way before the typical OOM point for the device in question. Issues was reproduced using iPhone 12 (allocating 1.1GB of RAM in the iOS project is sufficient to make it crash), iPhone 12 Pro and iPhone SE 2020. Note that everything works fine when compiling with pre-iOS 14 versions of XCode.
Although I’m way out of my league here, the addresses indicated in the panic seem to indicate that iOS no longer has a 33-bit memory address limit, as assumed by the Go runtime. Perhaps related to iPhone 12 Pro having 6GB of RAM, which would mean the 4GB limit assumed by the Go runtime would no longer be sufficient?
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 45 (18 by maintainers)
Commits related to this issue
- [release-branch.go1.16] runtime: set iOS addr space to 40 bits with incremental pagealloc In iOS <14, the address space is strictly limited to 8 GiB, or 33 bits. As a result, the page allocator also ... — committed to golang/go by mknyszek 3 years ago
- [release-branch.go1.17] runtime: set iOS addr space to 40 bits with incremental pagealloc In iOS <14, the address space is strictly limited to 8 GiB, or 33 bits. As a result, the page allocator also ... — committed to golang/go by mknyszek 3 years ago
Great news: it was just a test issue, and relatively easy to fix at that. Passed the trybots just fine. Hopefully I’ll land this soon.
The timeline looks like this: if it lands before the beta goes out, then it’ll be in that, otherwise it’ll be part of the first release candidate in about a month (probably mid-January because of the holidays). I’ll get the backported fix in ASAP and that’ll also be out in about a month, since the last minor releases just went out yesterday.
Builders are back. Going to take another stab at this.
We think this is potentially release-blocking, let us know what you think.
@brunomunizaf Go 1.17.6 released 2 days ago has the fix. (See https://go.dev/doc/devel/release#go1.17.minor and https://github.com/golang/go/issues?q=milestone%3AGo1.17.6+label%3ACherryPickApproved)
Thanks @mknyszek , awesome to see this fixed!
@eliasnaur @rayvbr The 2 MiB of address space is never committed, so it shouldn’t count toward that 15 MiB limit, even on older versions iOS (I think, maybe Tailscale folks can chime in, but I’d be surprised if it’s limited it by address space). It just matters in this case because old iOS versions have a very small address space, so we need to keep that small to maintain compatibility across this change in address space size iOS is doing. In the future this won’t matter – it’ll just be like any other arm64 platform.
@joshblum Unfortunately I’m still blocked on having a working builder. I’ll see if there’s anything else we can do about it.
I think what this has to look like is switching to the 64-bit implementation on iOS (for all versions) but adding a case to limit the address space used for iOS < 14. I can’t think of anything better, and this workaround is pretty unfortunate. The workaround would then disappear once we no longer supported iOS < 14.
I’ll ask around this week and see if anyone else has any ideas. I’ll also see if it’s possible to make a small, safe change so this is fixable in a minor release. For a major release, I’m going to start considering eliminating the separate 32-bit implementation and just have every platform do the dynamic mapping. That should make this fix cleaner going forward.