Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Tsan】【Bug】Calling siglongjmp in signal handler will cause the ignore_reads_and_writes check to fail #1759

Open
yinchuang-code opened this issue May 29, 2024 · 1 comment

Comments

@yinchuang-code
Copy link

yinchuang-code commented May 29, 2024

Tsan disable ignores in CallUserSignalHandler when ignores are enabled before call signal handler,but it will make "CHECK_GT(thr->ignore_reads_and_writes, 0);" failed in ThreadIgnoreEnd if someone use siglongjmp in signal handler:

dlopen

  • ThreadIgnoreBegin
    • thr->ignore_reads_and_writes++
  • trigger signal
    • CallUserSignalHandler
    • thr->ignore_reads_and_writes = 0
    • Call siglonghmp to jump to a normal position
  • ThreadIgnoreEnd
    • CHECK_GT(thr->ignore_reads_and_writes, 0); // failed!
@yinchuang-code
Copy link
Author

yinchuang-code commented Jun 1, 2024

Demo:

#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/mman.h>

#include <cstdint>
#include <iostream>
#include <optional>

namespace {
sigjmp_buf jump_buffer;

void safe_handler(int) {
  siglongjmp(jump_buffer, 1);
}

std::optional<uint8_t> read_under_sighandler(const uint8_t *p) {
  struct sigaction segv_act{}, old_act{};
  segv_act.sa_handler = &safe_handler;
  sigemptyset(&segv_act.sa_mask);
  sigaction(SIGSEGV, &segv_act, &old_act);

  std::optional<uint8_t> res;
  if (sigsetjmp(jump_buffer, 1) == 0) {
    res = *p;
  }

  sigaction(SIGSEGV, &old_act, NULL);
  return res;
}
}

struct dummy_t {
  dummy_t() {
    auto opt = read_under_sighandler(nullptr);
    if (!opt.has_value()) {
      puts("null opt - ok");
    } else {
      printf("opt: %d", *opt);
    }
  }
} dummy;

#include <dlfcn.h>
#include <cstdio>

int main() {
  auto lib = dlopen("liblib.so", RTLD_NOW | RTLD_GLOBAL);
  printf("%p\n", lib);
  dlclose(lib);
  return 0;
}

./main
null opt - ok
ThreadSanitizer: CHECK failed: tsan_rtl.cpp:1046 "((thr->ignore_reads_and_writes)) > ((0))" (0x0, 0x0) (tid=4515)
    #0 __tsan::CheckUnwind() <null> (main+0xd5c68) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)
    #1 __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) <null> (main+0x47d00) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)
    #2 __tsan::ThreadIgnoreEnd(__tsan::ThreadState*) <null> (main+0xda8e1) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)
    #3 dlopen <null> (main+0xa5c43) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)
    #4 main <null> (main+0xf8d98) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)
    #5 <null> <null> (libc.so.6+0x25ccf) (BuildId: 6542915cee3354fbcf2b3ac5542201faec43b5c9)
    #6 __libc_start_main <null> (libc.so.6+0x25d89) (BuildId: 6542915cee3354fbcf2b3ac5542201faec43b5c9)
    #7 _start <null> (main+0x2f0b4) (BuildId: f6725f3b5ec1829614f9ff48e0780b27120e0c50)



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant