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))
+	}
+}