Skip to content

__errno_location crash after call to __cxa_guard_acquire #2268

Description

@MagnusS

When enabling SMP the initial call to RNG::get().init() in apic_revenant crashes. RNG::get().init() returns a static variable that is initialised by the first call to get() (here). After stepping through the code I see that the crash is caused by a surrounding call to __cxa_guard_acquire that protects the initialisation of the static variable, which then calls a syscall that returns ENOSYS. This value is written to __errno_location by musl, which then triggers a CPU exception.

There seems to be multiple issues here:

__cxa_guard_acquire is added by the compiler to protect the initialisation of static variables at runtime (such as in RNG). The implementation is here. Depending on whether we have threads enabled in LIBCXX it will call various locking mechanisms in libc/musl, which have to be initialised first. If this happens early in the boot process, the kernel/musl may be unable to handle them. I'm not sure what the best approach to fix this would be, but ideally we shouldn't use code that relied on this feature until we get far enough in the boot process.

__errno_location isn't set up properly, at least not on other cores than core 0, and syscalls will write to the memory location it points to. In combination with the __cxa_guard_acquire issue above, this may happen unexpectedly. After a call to syscall, musl's syscall_ret writes errno to the location stored in __errno_location function from the pthread struct. The struct is retrieved from %fs:0 here. It looks like TLS may not be properly set up, there's a function in IncludeOS to do it here -- but it doesn't look like it's called from apic_revenant.

I'm not sure why this has worked previously, but perhaps the new toolchain/build system happens to make errno_val point outside valid memory, so we now get a crash instead of potential instability? Could this have been causing issues such as #2252?

To reproduce, first enable SMP, then run nix-shell --argstr unikernel test/kernel/integration/smp --run ./test.py

(this is on v0.16.0-release branch)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions