runtime: mark OpenBSD raise function nosplit

It is called by the signal handler before switching to gsignal
(sigtrampgo -> sigfwdgo -> dieFromSignal -> raise)
which means that it must not split the stack.

All other instances of raise are already marked nosplit.

Fixes #40076

Change-Id: I4794491331af48c46d0d8ebc82d34c6483f0e6cd
Reviewed-on: https://go-review.googlesource.com/c/go/+/241121
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 2e93e39..429bd81 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -104,6 +104,25 @@
 			}
 		}
 	}
+
+	// Test redirecting stdout but not stderr.  Issue 40076.
+	cmd := osexec.Command(os.Args[0], "-test.run", "TestStdPipeHelper")
+	cmd.Stdout = w
+	var stderr bytes.Buffer
+	cmd.Stderr = &stderr
+	cmd.Env = append(os.Environ(), "GO_TEST_STD_PIPE_HELPER=1")
+	if err := cmd.Run(); err == nil {
+		t.Errorf("unexpected success of write to closed stdout")
+	} else if ee, ok := err.(*osexec.ExitError); !ok {
+		t.Errorf("unexpected exec error type %T: %v", err, err)
+	} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
+		t.Errorf("unexpected wait status type %T: %v", ee.Sys(), ee.Sys())
+	} else if !ws.Signaled() || ws.Signal() != syscall.SIGPIPE {
+		t.Errorf("unexpected exit status %v for write to closed stdout", err)
+	}
+	if output := stderr.Bytes(); len(output) > 0 {
+		t.Errorf("unexpected output on stderr: %s", output)
+	}
 }
 
 // This is a helper for TestStdPipe. It's not a test in itself.
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index b486b83..cd3565d 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -340,6 +340,7 @@
 	}
 }
 
+//go:nosplit
 func raise(sig uint32) {
 	thrkill(getthrid(), int(sig))
 }