blob: 39cb0c61598ab7634088e7d8b8839b639d0dc63b [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "incfs_support/signal_handling.h"
#if defined(__BIONIC__) && !INCFS_SUPPORT_DISABLED
#include <errno.h>
namespace incfs {
static void enableSignal(int code) {
sigset_t allowed;
sigemptyset(&allowed);
sigaddset(&allowed, code);
pthread_sigmask(SIG_UNBLOCK, &allowed, nullptr);
}
ScopedJmpBuf::~ScopedJmpBuf() { SignalHandler::mJmpBuf = mPrev; }
SignalHandler& SignalHandler::instance() {
static SignalHandler self;
return self;
}
SignalHandler::SignalHandler() {
const struct sigaction action = {
.sa_sigaction = &handler,
.sa_flags = SA_SIGINFO,
};
if (sigaction(SIGBUS, &action, &mOldSigaction)) {
LOG_ALWAYS_FATAL("sigaction(SIGBUS) failed: %d", errno);
// not much can be done now
return;
}
// ensure SIGBUS is unblocked, so the process won't get insta-killed
enableSignal(SIGBUS);
}
void SignalHandler::handler(int sig, siginfo_t* info, void* ucontext) {
if (sig != SIGBUS) {
LOG_FATAL("SIGBUS handler called for unexpected signal %d", sig);
return;
}
if (!mJmpBuf.armed) {
// No error handler installed - run the previous one
if (mOldSigaction.sa_handler == SIG_DFL) {
// reset the action to default and re-raise the signal. It will kill the
// process
signal(sig, SIG_DFL);
raise(sig);
return;
}
if (mOldSigaction.sa_handler == SIG_IGN) {
// ignoring SIGBUS won't help us much, as we'll get back right here after
// retrying.
return;
}
if (mOldSigaction.sa_flags & SA_SIGINFO) {
mOldSigaction.sa_sigaction(sig, info, ucontext);
} else {
mOldSigaction.sa_handler(sig);
}
// Returning from a signal handler for SIGBUS is undefined, but if it
// happens better to at least forward that undefined thing further. Who are
// we to argue with the user?
return;
}
// restore SIGBUS as signal handling blocks it before running the callback
enableSignal(SIGBUS);
longjmp(mJmpBuf.buf, 1);
}
} // namespace incfs
#endif