Skip to content
This repository was archived by the owner on Feb 15, 2025. It is now read-only.

Add a new RunWithFaultHandler utility#127

Merged
mmdriley merged 1 commit intomasterfrom
mattdr/meltdown-fault-handler
Jun 3, 2020
Merged

Add a new RunWithFaultHandler utility#127
mmdriley merged 1 commit intomasterfrom
mattdr/meltdown-fault-handler

Conversation

@mmdriley
Copy link
Member

This avoids the need for a global afterspeculation label.

Use to rewrite the Meltdown example.

@mmdriley mmdriley requested a review from ssbr May 29, 2020 02:11
@googlebot googlebot added the cla: yes authors signed CLA label May 29, 2020
@mmdriley
Copy link
Member Author

This is based on #126. Will update the base branch to master once #126 lands.

Copy link
Contributor

@ssbr ssbr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I learned a lot today. The memories of call/cc just come flooding back, don't they? :)

@@ -0,0 +1,62 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is tricky, is it a reasonable request to ask for unit tests? (Thinking of like three tests, one which sends no signal, one which sends SIGSEGV, and one which sends some other signal.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely reasonable. Tests added in next revision.

demos/faults.h Outdated

// See "The siginfo_t argument to a SA_SIGINFO handler"
// at https://www.man7.org/linux/man-pages/man2/sigaction.2.html
using PosixFaultHandler = std::function<void(int, siginfo_t*, void*)>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be used yet except with an empty callback. Will we need it, or can callers always check the return value instead?

Signal handlers are super scary / hard to do right thing (signal safety is high impossible), so I'd prefer if we didn't expose it at all, if at all possible.

And here's a case in point: if we do want to support it, we must not use std::function, because std::function::operator() does not document itself as signal safe, which makes it UB to call per the rules of [support.signal] (3.1).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, this seems vestigial at this point. Initially I was concerned that sigsetjmp would disrupt the cache enough we wouldn't be able to read the sidechannel, but testing doesn't seem to show that's the case. I'll remove this knob for now; we can add it back if need be.

demos/faults.cc Outdated

namespace {

// The fault handler that should be called from the signal handler, and the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, making them thread_local makes them UB to access within a signal handler, per [support.signal] (3.2). Since it was only ever aspirational anyway, just delete.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, a few things about this and other comments on signal safety.

First, yes, getting async signal safety right, to the standards of the sort of systems where it usually comes up, is very hard. That puts us in tension because the more we work to make this "right", the harder it is to understand.

For our application, here, I think the right tradeoff is to be very easy to understand, and at least mostly right. Obviously we'll fix bugs or unreliability we hit on the platforms we support.

There are some other mitigating factors for us, aside from the obvious ones like "our entire repository is predicated on the existence of undefined but predictable behavior". The signals we care about, faults like SIGSEGV, are synchronous -- they are caused by instructions in the program, rather than external events.

These signals are also usually fatal, so we can say with some confidence that they are not normally raised by code not under our control, like the standard library. They also will not be raised during execution of the signal handler itself unless we have a bug, in which case we get the failure we wanted.

All this to say: for now, however distasteful it might seem, I suggest we use "works as expected in concrete implementations" as our standard rather than "works on the abstract machine". I would be fine adding comments to the code to that effect.

Fun trivia - Rust also accesses thread-local data in a SIGSEGV handler. rust-lang/rust#43146

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still removed thread_local.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I think atomics would be likely to work with our use case, without any undefined, unspecified, or implementation-defined behavior.

There's one other issue that made me cautious that I should've mentioned first: different platforms send signals to different threads, so the moment we have thread-local signal handlers, even if there's no signals raised during assignment to the threadlocal we're in Very Difficult territory, which makes it harder, rather than easier, to understand.

thread_local PosixFaultHandler fault_handler;
thread_local sigjmp_buf signal_handler_jmpbuf;

void SignalHandler(int signal, siginfo_t *info, void *ucontext) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think this should be extern "C" per https://en.cppreference.com/w/cpp/utility/program/signal "Signal handlers are expected to have C linkage and, in general, only use the features from the common subset of C and C++. It is implementation-defined if a function with C++ linkage can be used as a signal handler."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@mmdriley mmdriley changed the base branch from mattdr/meltdown-debugfs to master May 29, 2020 20:35
@mmdriley mmdriley force-pushed the mattdr/meltdown-fault-handler branch from 60f6a82 to 77ba3a5 Compare May 29, 2020 20:35
@mmdriley mmdriley changed the base branch from master to mattdr/meltdown-debugfs May 29, 2020 20:36
@mmdriley mmdriley force-pushed the mattdr/meltdown-fault-handler branch from 77ba3a5 to fea1d09 Compare May 29, 2020 20:36
@mmdriley mmdriley requested a review from ssbr May 29, 2020 20:59
@mmdriley mmdriley force-pushed the mattdr/meltdown-debugfs branch from fbdb0b5 to 27a3a90 Compare June 3, 2020 06:30
Base automatically changed from mattdr/meltdown-debugfs to master June 3, 2020 06:34
@mmdriley mmdriley force-pushed the mattdr/meltdown-fault-handler branch from fea1d09 to f9e7bb5 Compare June 3, 2020 06:59
This avoids the need for a global `afterspeculation` label.

Use to rewrite the Meltdown example.
@mmdriley mmdriley force-pushed the mattdr/meltdown-fault-handler branch from f9e7bb5 to b9dbc6f Compare June 3, 2020 06:59
@mmdriley
Copy link
Member Author

mmdriley commented Jun 3, 2020

Added one last tweak to run the new unit test in CI.

@mmdriley mmdriley merged commit e2e23b8 into master Jun 3, 2020
@mmdriley mmdriley deleted the mattdr/meltdown-fault-handler branch June 3, 2020 07:04
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes authors signed CLA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants