Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a57dffb1 authored by Yifan Hong's avatar Yifan Hong
Browse files

lshal: Fix timeout causes unexpected exits.

with thread::detach the background thread keeps running even after
the thread object is destroyed; the background thread will access
caller's stack memory, causing segfault. Change it to a thread join
to avoid the issue. To avoid waiting too long on the child thread,
send a SIGINT if timeout (child thread's signal handler will then
call pthread_exit() to terminate the thread).

Since we are using pthread_* functions, change usage of std::thread
to pthread_t for consistency.

Test: lshal
Test: run lshal with IPC_CALL_TIMEOUT set to zero will no longer
      cause SIGSEGV and SIGABRT (test 10 times)

Bug: 35623669
Change-Id: I4eef8ffd8ff399793648e861ca4c1a2bdcc7ec50
parent 52a60e08
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -469,9 +469,17 @@ int Lshal::main(int argc, char **argv) {
    return status;
}

void signalHandler(int sig) {
    if (sig == SIGINT) {
        int retVal;
        pthread_exit(&retVal);
    }
}

}  // namespace lshal
}  // namespace android

int main(int argc, char **argv) {
    signal(SIGINT, ::android::lshal::signalHandler);
    return ::android::lshal::Lshal{}.main(argc, argv);
}
+24 −8
Original line number Diff line number Diff line
@@ -29,7 +29,8 @@ static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};

class BackgroundTaskState {
public:
    BackgroundTaskState(){}
    BackgroundTaskState(std::function<void(void)> &&func)
            : mFunc(std::forward<decltype(func)>(func)) {}
    void notify() {
        std::unique_lock<std::mutex> lock(mMutex);
        mFinished = true;
@@ -42,22 +43,37 @@ public:
        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
        return mFinished;
    }
    void operator()() {
        mFunc();
    }
private:
    std::mutex mMutex;
    std::condition_variable mCondVar;
    bool mFinished = false;
    std::function<void(void)> mFunc;
};

void *callAndNotify(void *data) {
    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
    state();
    state.notify();
    return NULL;
}

template<class R, class P>
bool timeout(std::chrono::duration<R, P> delay, const std::function<void(void)> &func) {
bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
    auto now = std::chrono::system_clock::now();
    BackgroundTaskState state{};
    std::thread t([&state, &func] {
        func();
        state.notify();
    });
    t.detach();
    BackgroundTaskState state{std::forward<decltype(func)>(func)};
    pthread_t thread;
    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
        std::cerr << "FATAL: could not create background thread." << std::endl;
        return false;
    }
    bool success = state.wait(now + delay);
    if (!success) {
        pthread_kill(thread, SIGINT);
    }
    pthread_join(thread, NULL);
    return success;
}