# glibc-abort源码阅读

## 问题

1. abort是退出当前线程还是退出当前进程?
2. abortraise/exit的区别是什么?

## 测试

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38  #include #include #include #include #include using namespace std; int main() { thread t1([]() { int cnt = 20; while (cnt-- > 0) { cout << "cnt=" << cnt << endl; this_thread::sleep_for(std::chrono::seconds(1)); } }); thread t2([]() { this_thread::sleep_for(std::chrono::seconds(2)); cout << "t2 abort" << endl; try { abort(); } catch (exception &e) { } }); if (t1.joinable()) t1.join(); if (t2.joinable()) t2.join(); return 1; } 

 1  g++ main.cpp -o main --std=c++11 -lpthread 

 1 2 3 4  cnt=19 cnt=18 t2 abort Aborted (core dumped) 

## 源码

 1 2 3 4 5  /* We must avoid to run in circles. Therefore we remember how far we already got. */ static int stage; /* We should be prepared for multiple threads trying to run abort. */ __libc_lock_define_initialized_recursive (static, lock); 

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33  /* Cause an abnormal program termination with core-dump. */ void abort (void) { struct sigaction act; sigset_t sigs; /* First acquire the lock. */ __libc_lock_lock_recursive (lock); /* Now it's for sure we are alone. But recursive calls are possible. */ /* Unblock SIGABRT. */ if (stage == 0) { ++stage; __sigemptyset (&sigs); __sigaddset (&sigs, SIGABRT); __sigprocmask (SIG_UNBLOCK, &sigs, 0); } /* Send signal which possibly calls a user handler. */ if (stage == 1) { /* This stage is special: we must allow repeated calls of abort' when a user defined handler for SIGABRT is installed. This is risky since the raise' implementation might also fail but I don't see another p ossibility. */ int save_stage = stage; stage = 0; __libc_lock_unlock_recursive (lock); raise (SIGABRT); __libc_lock_lock_recursive (lock); stage = save_stage + 1; } //... 

SIG_DFL是默认信号处理函数, 其值是0, 调用SIG_DFL相当于是访问0地址, 被禁止访问, 这时候就会退出进程了.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16   /* There was a handler installed. Now remove it. */ if (stage == 2) { ++stage; memset (&act, '\0', sizeof (struct sigaction)); act.sa_handler = SIG_DFL; __sigfillset (&act.sa_mask); act.sa_flags = 0; __sigaction (SIGABRT, &act, NULL); } /* Try again. */ if (stage == 3) { ++stage; raise (SIGABRT); } 

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19   /* Now try to abort using the system specific command. */ if (stage == 4) { ++stage; ABORT_INSTRUCTION; } /* If we can't signal ourselves and the abort instruction failed, exit. */ if (stage == 5) { ++stage; _exit (127); } /* If even this fails try to use the provided instruction to crash or otherwise make sure we never return. */ while (1) /* Try for ever and ever. */ ABORT_INSTRUCTION; }