Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/mobile: accessing field on nil on iOS raises exception instead of panicking (gomobile) #23511

Open
cvermilion opened this issue Jan 22, 2018 · 11 comments
Labels
mobile Android, iOS, and x/mobile NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@cvermilion
Copy link

The spec says accessing a field (x.foo) should panic if x is nil, but it seems that in an iOS library built with gomobile, the result is an EXC_BAD_ACCESS exception being raised.

Please answer these questions before submitting your issue. Thanks!

What did you do?

If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.

Here's an example that works fine in a regular Go program but the equivalent compiled into an iOS app crashes: https://play.golang.org/p/KsIyVll7NE0.

What did you expect to see?

Accessing a field on nil panics, and is handled by a surrounding defer/recover block.

What did you see instead?

Accessing a field on nil raises a native exception, crashing the program unrecoverably.

System details

go version go1.9.2 darwin/amd64
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/verm/remix/amp"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.9.2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.9.2/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/36/92jbhtpj41s6q3w4fcq2v01w0000gn/T/go-build431793073=/tmp/go-build -gno-record-gcc-switches -fno-common"
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"
GOROOT/bin/go version: go version go1.9.2 darwin/amd64
GOROOT/bin/go tool compile -V: compile version go1.9.2
uname -v: Darwin Kernel Version 16.7.0: Mon Nov 13 21:56:25 PST 2017; root:xnu-3789.72.11~1/RELEASE_X86_64
ProductName:	Mac OS X
ProductVersion:	10.12.6
BuildVersion:	16G1114
lldb --version: lldb-900.0.64
  Swift-4.0
@ianlancetaylor ianlancetaylor changed the title Accessing field on nil on iOS raises exception instead of panicking (gomobile) x/mobile: accessing field on nil on iOS raises exception instead of panicking (gomobile) Jan 23, 2018
@gopherbot gopherbot added this to the Unreleased milestone Jan 23, 2018
@gopherbot gopherbot added the mobile Android, iOS, and x/mobile label Jan 23, 2018
@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jan 23, 2018
@eliasnaur
Copy link
Contributor

Have you tried to run your program outside the (Xcode) debugger or simply continuing execution after the exception is raised? I believe that the Go runtime will catch the exception and enable your recover to catch the panic.

@cvermilion
Copy link
Author

Ah, interesting! I hadn't tried running it outside of Xcode. Continuing execution in Xcode doesn't work (just stays at the same exception), but if I run outside of Xcode, catching the panic works and the program functions normally.

So it seems like the issue is that Xcode's debugger is probably installing a signal handler that conflicts with how panics get caught.

OK, so to summarize then, there are two distinct ways this is a (minor) problem:

  1. Debugging a program in Xcode that links a Go library, an uncaught nil de-ref that would normally be trivial to debug can be a bit trickier to figure out, since you don't get the expected Go error response and stack trace. Xcode does show you the correct code location, though, so once you've run into this before it's not very hard to figure out what's going on. But if you don't spend a ton of time in Xcode on non-Go stuff it might be confusing.

  2. Running a program in Xcode, if you're relying on panic/defer/recover for normal execution flow, you may be out of luck if a panic you expect to happen occurs because of a nil deref. This seems like bad practice generally but I can't speak to how often this comes up in the wild.

@HaidyCao
Copy link

I found it will crash when it run on RAM32 device like iPhone 5c, even not running outside of Xcode

@eliasnaur
Copy link
Contributor

@HaidyCao, is that reproducible on an arm64 device running arm32 gomobile? You can restrict gomobile bind with the -target ios/arm flag

@HaidyCao
Copy link

HaidyCao commented Dec 17, 2018

@eliasnaur Yes. I tried:
gomobile bind -target=ios/arm package/path
still crashed.

My go version is go1.11 and gomobile is newest.

my test go file:

package test

type str struct {
	s string
}

// Test he
func Test() (i int) {
	defer func() {
		if err := recover(); err != nil {
			i = -1
		}
	}()

	testInner() 
	return 0
}

func testInner() {
	s := &str{}
	s = nil
	println(s.s)
}

One other thing. When I catched a panic in go code, iOS system still report a crash log, but app not crash.

crash log:

Incident Identifier: 9FF41C4A-8BE0-41A1-B264-D446BC73B1DF
CrashReporter Key: 80e63ddc11107f07137eaf82db2379c281de30ab
Hardware Model: iPhone11,8
Process: *** [4642]
Path: /var/containers/Bundle/Application/66D02A90-9C57-4B6E-AF57-ABE66D103BBE/***
Identifier: ***
Version: ****
Code Type: ARM-64
Parent Process: ? [1]

Date/Time: 2018-12-12 18:59:35.000 +0800
OS Version: iOS 12.1 (16B93)
Report Version: 104

Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x00000000 at 0x0000000000000040
Crashed Thread: 13

@eliasnaur
Copy link
Contributor

I see. So your app is actually able to continue (outside Xcode) if you catch the panic? If so, that's expected and not likely to change in the near future. Perhaps the Go runtime will need to use mach exception handlers for for panics instead of using the posix signal functions.

@eliasnaur
Copy link
Contributor

It just occurred to me that the lldbbuild tag might be a viable workaround for you. The Go runtime use that tag to work around a similar issue when running go test binaries on iOS. Could you try gomobile bind --tags lldb target=ios/arm package/path in Xcode and see if panics are properly caught?
Note that the lldbbuild tag triggers the use of a private symbol and binaries built with it enabled won't be accepted in the App Store. See issue #10646.

@HaidyCao
Copy link

Thank you. I tried use gomobile bind --tags lldb target=ios/arm package/path, but it till crash on iPhone5c (iOS 10.3.3) when catch a panic.

Catch crash report is another ARM64 device and it able to continue (outside Xcode) if catch the panic.

@nbrownus
Copy link

I hit this today, a simple example:

func WillFatal() {
	var ip *net.IPNet
	fmt.Printf("%v", ip)
}

If you disable Debug executable in your xcode scheme it will work fine, but then you lose the ability to debug. Adding --tags lldb did not change the outcome.

I have not found a way to catch and ignore this in swift. It would be ideal if gomobile could avoid the scenario.

@arjenveenhuizen
Copy link

Is there any update regarding this problem? This is still an issue on go 1.16.15 and most recent gomobile on iOS (arm64). Recover() works correctly on Android.

@hsjoberg
Copy link

FWIW, I've also set up a demo project here for Swift macOS showcasing this issue:
https://github.com/hsjoberg/GoNilPointerDerefCrash

But the problem as far as I can tell is not really in the go runtime, rather that the debugger lldb does not like the nil pointer usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mobile Android, iOS, and x/mobile NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

8 participants