bind: avoid crashes from SIGPIPE
The Go runtime doesn't handle SIGIPE signals from writing to closed
sockets or pipes in c-archive and c-shared mode (issue 17393).
Work around it in gomobile by simply ignoring all SIGPIPE signals;
they're not useful in mobile apps anyway.
Change-Id: Ibd7ee41058856c5eddb4a519345a3851a29e9b44
Reviewed-on: https://go-review.googlesource.com/33771
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java
index 1089fda..156e591 100644
--- a/bind/java/SeqTest.java
+++ b/bind/java/SeqTest.java
@@ -577,4 +577,8 @@
InitCaller initer = Testpkg.newInitCaller();
initer.init();
}
+
+ public void testSIGPIPE() {
+ Testpkg.testSIGPIPE();
+ }
}
diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m
index 8fd15cf..9962c68 100644
--- a/bind/objc/SeqTest.m
+++ b/bind/objc/SeqTest.m
@@ -449,4 +449,8 @@
XCTAssertFalse(GoTestpkgCallEmptyError(empty, &error), @"GoTestpkgCallEmptyError succeeded; want error");
XCTAssertNotNil(error, @"GoTestpkgCallEmptyError returned nil error");
}
+
+- (void)testSIGPIPE {
+ GoTestpkgTestSIGPIPE();
+}
@end
diff --git a/bind/seq.go.support b/bind/seq.go.support
index d2f36d4..1167b6c 100644
--- a/bind/seq.go.support
+++ b/bind/seq.go.support
@@ -14,6 +14,9 @@
import (
"fmt"
+ "os"
+ "os/signal"
+ "syscall"
_seq "golang.org/x/mobile/bind/seq"
)
@@ -32,6 +35,8 @@
}
C.go_seq_inc_ref(C.int32_t(refnum))
}
+ // Workaround for issue #17393.
+ signal.Notify(make(chan os.Signal), syscall.SIGPIPE)
}
// IncGoRef is called by foreign code to pin a Go object while its refnum is crossing
diff --git a/bind/testpkg/testpkg.go b/bind/testpkg/testpkg.go
index 5411f45..2e825c7 100644
--- a/bind/testpkg/testpkg.go
+++ b/bind/testpkg/testpkg.go
@@ -16,7 +16,9 @@
"io/ioutil"
"log"
"math"
+ "os"
"runtime"
+ "syscall"
"time"
"golang.org/x/mobile/asset"
@@ -569,3 +571,28 @@
}
return new(S4), nil
}
+
+// Lifted from TestEPIPE in package os.
+func TestSIGPIPE() {
+ r, w, err := os.Pipe()
+ if err != nil {
+ panic(err)
+ }
+ if err := r.Close(); err != nil {
+ panic(err)
+ }
+
+ _, err = w.Write([]byte("hi"))
+ if err == nil {
+ panic("unexpected success of Write to broken pipe")
+ }
+ if pe, ok := err.(*os.PathError); ok {
+ err = pe.Err
+ }
+ if se, ok := err.(*os.SyscallError); ok {
+ err = se.Err
+ }
+ if err != syscall.EPIPE {
+ panic(fmt.Errorf("got %v, expected EPIPE", err))
+ }
+}