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 · 8 comments

Comments

Projects
None yet
5 participants
@cvermilion
Copy link

commented Jan 22, 2018

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 label Jan 23, 2018

@eliasnaur

This comment has been minimized.

Copy link
Contributor

commented Mar 15, 2018

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

This comment has been minimized.

Copy link
Author

commented Apr 1, 2018

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

This comment has been minimized.

Copy link

commented Dec 14, 2018

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

@eliasnaur

This comment has been minimized.

Copy link
Contributor

commented Dec 14, 2018

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

@HaidyCao

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

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

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

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

This comment has been minimized.

Copy link

commented Dec 18, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.