| /* |
| * 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 |