Skip to content

Implement ucontext_t parameter in signal handlers #1975

@sporksmith

Description

@sporksmith

We currently pass NULL as the 3rd parameter to sa_sigaction signal handlers. This ought to instead be a valid ucontext_t*.

In Linux, this would normally contain state about the running thread just before the signal was delivered. Its contents are described in getcontext(3).

Parts of ucontext_t are opaque, making it difficult to construct completely synthetically. We can obtain one though by calling getcontext, swapcontext, or handling a native signal ourselves.

I think the main important use-case to support is being able to use it to call swapcontext or setcontext from the managed
program's signal handler. golang does this (or some equivalent) to implement its preemptive goroutine scheduling. For this purpose, some possibilities are:

  • Call the managed process signal handler via swapcontext, and pass the pointer to the swapped-out context. We already use swapcontext when the signal handler is configured to run on an alternate stack. I've locally confirmed this produces the desired behavior in snowflake simulations. Doing this is a little tricky though in the case where the handler doesn't run on a different stack, since swapcontext always switches stacks. Maybe we could set up an appropriate stack starting from the current position in the current stack, but this seems fragile.
  • Set up a signal handler for some signal, like SIGUSR1, and raise that signal to kick off our signal handling. We could then pass the ucontext_t from our own signal handler on to the managed process signal handlers. I think this would correctly handle both the cases where the handler is or isn't configured to run on an alternate stack, but I haven't tried it yet.

There's another use-case where the handler might deeply inspect the ucontext_t itself, e.g. to see register values at the point where the signal was raised. We do this ourselves in our SIGSYS handler to extract the syscall parameters of the syscall that raised the signal. It's also possible to mutate individual register values there, which will cause those to be restored when the handler returns.

AFAIK this use case only really makes sense for "synchronous" signals like SIGSYS, SIGSEGV, and SIGILL. We don't really support these at all yet. It'd be straightforward though to support them by installing our own handlers for those signals, which then delegate to the managed process configured handler (if any). In that case I think it'd make sense to pass through the ucontext_t that our handler received.

Metadata

Metadata

Assignees

Labels

Type: BugError or flaw producing unexpected results

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions