runtime: kevent on fd 8 failed with 14
To reproduce, run a go http server (i used the one here: https://github.com/emc-advanced-dev/unik/tree/master/docs/examples/example_go_httpd)
and perform a lot of requests:
while true; do curl http://192.168.4.141:8080/ ; done (192.168.4.141 is the address of the rumprun unikernel in my setup)
This issue happens due to a mismatch in assembly calling conventions.
In go:
func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
in c (rumprun/src-netbsd/sys/kern/kern_event.c):
int kevent1(register_t *retval, int fd,
const struct kevent *changelist, size_t nchanges,
struct kevent *eventlist, size_t nevents,
const struct timespec *timeout,
const struct kevent_ops *keops)
The variables fd, nchanges, nevents are 32 bit in go BUT are 64 bit in C. When they are copied to the stack as arguments, they take 8 bytes from the stack (as this is 64bit), but only 4 bytes are copied. leaving 4 bytes of garbage. If the garbage is not zero, the c system call gets the wrong value for the variable. in my case, i had nchanges = 0x2100000000 while changelist was null, and hense the EFAULT error (number 14)
As a hacky solution, I modified runtime·kevent in runtime/sys_rumprun_amd64.s right after the line
ADDQ $0x18, SI // args
I added:
MOVL $0, 0x04(SI)
MOVL $0, 0x14(SI)
MOVL $0, 0x24(SI)
to zero out the garbage part of the stack.
ehh.. this is unfortunate - since this is isolated to a rumprun file want to open a pull request for now? this sounds like something that should change in the go calling code later on though