Consider the following program:

package main

var f func(int)

//go:nosplit
func x(y int) { f(y+1) }

func main() {
  f = x
  f(0)
}

When run, this program segfaults. This is because taking the address of a nosplit function completely avoids the linker's nosplit stack size check, meaning that this program very quickly exausts g0's stack and does a hard segfault.

All that this program prints is signal: segmentation fault, and occasionally random debugging spew before the runtime kills itself.

I think this is a good case for making using nosplit require import "unsafe", because I can't see another way to fix this without violating the "calling a nosplit functions does not preempt" invariant.

Comment From: Jorropo

We can keep nosplit as is and make grabbing function pointers of nosplit functions disallowed, or make that require unsafe if it can be used in some way.

Comment From: mcy

If you want to go that direction it also needs to cover making a value with a nosplit method into an interface, because that will silently turn all of its methods into function pointers, no matter the interface. And that seems like it will be very messy.

No matter the fix it's a breaking change, and I think it's hard to argue that this isn't covered by compatibility requirements... so probably means a GOEXPERIMENT?

Comment From: randall77

Then don't use //go:nosplit? Problem solved.

(It is a directive intended for runtime internal functions that can't be preempted - unfortunately it wasn't implemented as runtime-only at the start, so now it has escaped to user code and we get problems like this...)