fix(tng): 防止 SIGABRT 跳 LR 死循环,改 pc+4 与 streak freeze
吞 ABRT 时若跳回近距 LR 会瞬间再 abort 刷屏;改为优先 pc+4,同 tid+pc 超阈值后冻结工作线程,主线程仅 bail。
This commit is contained in:
@@ -123,21 +123,64 @@ static void promon_segv_handler(int sig, siginfo_t *info, void *ctx) {
|
|||||||
raise(SIGSEGV);
|
raise(SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** libc++abi __cxa_guard_acquire 递归初始化 → abort;跳回 LR 继续而非杀进程。 */
|
static std::atomic<pid_t> g_main_tid{0};
|
||||||
|
static std::atomic<int> g_abrt_swallow{0};
|
||||||
|
static std::atomic<pid_t> g_abrt_last_tid{0};
|
||||||
|
static std::atomic<uintptr_t> g_abrt_last_pc{0};
|
||||||
|
static std::atomic<int> g_abrt_streak{0};
|
||||||
|
static constexpr int kMaxAbrtStreak = 3;
|
||||||
|
|
||||||
|
/** ABRT/TRAP:pc+4 或远距 LR;同 tid+pc 连触发则 freeze,避免 LR 自旋死循环。 */
|
||||||
static void fatal_skip_handler(int sig, siginfo_t *info, void *ctx) {
|
static void fatal_skip_handler(int sig, siginfo_t *info, void *ctx) {
|
||||||
(void)info;
|
(void)info;
|
||||||
ucontext_t *uc = reinterpret_cast<ucontext_t *>(ctx);
|
ucontext_t *uc = reinterpret_cast<ucontext_t *>(ctx);
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
uintptr_t pc = uc->uc_mcontext.pc;
|
uintptr_t pc = uc->uc_mcontext.pc;
|
||||||
uintptr_t lr = uc->uc_mcontext.regs[30];
|
uintptr_t lr = uc->uc_mcontext.regs[30];
|
||||||
LOGI("swallowed signal %d tid=%d pc=%lx lr=%lx", sig, (int)gettid(),
|
pid_t tid = gettid();
|
||||||
(unsigned long)pc, (unsigned long)lr);
|
|
||||||
if (lr != 0) {
|
if (sig == SIGABRT) {
|
||||||
uc->uc_mcontext.pc = lr;
|
int streak = 1;
|
||||||
|
if (g_abrt_last_tid.load() == tid && g_abrt_last_pc.load() == pc) {
|
||||||
|
streak = g_abrt_streak.fetch_add(1) + 1;
|
||||||
|
} else {
|
||||||
|
g_abrt_last_tid.store(tid);
|
||||||
|
g_abrt_last_pc.store(pc);
|
||||||
|
g_abrt_streak.store(1);
|
||||||
|
}
|
||||||
|
if (streak > kMaxAbrtStreak) {
|
||||||
|
if (tid == g_main_tid.load()) {
|
||||||
|
LOGI("ABRT main-thread streak cap tid=%d pc=%lx — pc+4 bail", (int)tid,
|
||||||
|
(unsigned long)pc);
|
||||||
|
uc->uc_mcontext.pc = pc + 4;
|
||||||
|
g_abrt_streak.store(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOGI("ABRT streak cap tid=%d pc=%lx n=%d — freeze thread", (int)tid,
|
||||||
|
(unsigned long)pc, streak);
|
||||||
|
freeze_forever();
|
||||||
|
}
|
||||||
|
uintptr_t delta = (pc > lr) ? (pc - lr) : (lr - pc);
|
||||||
|
uintptr_t target = pc + 4;
|
||||||
|
/* lr 距 pc 很近时仍在 abort/epilogue 内,跳 LR 会 instant 再 ABRT */
|
||||||
|
if (lr != 0 && delta > 64) {
|
||||||
|
target = lr;
|
||||||
|
}
|
||||||
|
int n = ++g_abrt_swallow;
|
||||||
|
if (n <= 3 || n % 100 == 0) {
|
||||||
|
LOGI("ABRT skip tid=%d pc=%lx lr=%lx streak=%d -> %lx", (int)tid,
|
||||||
|
(unsigned long)pc, (unsigned long)lr, streak,
|
||||||
|
(unsigned long)target);
|
||||||
|
}
|
||||||
|
uc->uc_mcontext.pc = target;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pc != 0) {
|
|
||||||
uc->uc_mcontext.pc = pc + 4;
|
if (sig == SIGTRAP) {
|
||||||
|
uintptr_t target = pc != 0 ? pc + 4 : lr;
|
||||||
|
LOGI("TRAP skip tid=%d pc=%lx -> %lx", (int)tid, (unsigned long)pc,
|
||||||
|
(unsigned long)target);
|
||||||
|
uc->uc_mcontext.pc = target;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -151,7 +194,7 @@ static void install_fatal_skip_handlers() {
|
|||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sigaction(SIGABRT, &sa, nullptr);
|
sigaction(SIGABRT, &sa, nullptr);
|
||||||
sigaction(SIGTRAP, &sa, nullptr);
|
sigaction(SIGTRAP, &sa, nullptr);
|
||||||
LOGI("fatal skip handlers (ABRT+TRAP→LR)");
|
LOGI("fatal skip handlers (ABRT pc+4/streak-freeze + TRAP pc+4)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void install_promon_segv_handler() {
|
static void install_promon_segv_handler() {
|
||||||
@@ -177,7 +220,7 @@ static void install_soft_signals() {
|
|||||||
sigaction(SIGABRT, &sa, nullptr);
|
sigaction(SIGABRT, &sa, nullptr);
|
||||||
sigaction(SIGTRAP, &sa, nullptr);
|
sigaction(SIGTRAP, &sa, nullptr);
|
||||||
if (g_soft_sig_logged.fetch_add(1) == 0) {
|
if (g_soft_sig_logged.fetch_add(1) == 0) {
|
||||||
LOGI("soft signals (ABRT+TRAP skip→LR)");
|
LOGI("soft signals (ABRT streak-freeze + TRAP pc+4)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +385,9 @@ static void *phase_thread(void *) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void install_all(zygisk::Api *api) {
|
static void install_all(zygisk::Api *api) {
|
||||||
LOGI("install pid=%d (PLT+ABRT/TRAP-skip+pc==lr-SEGV+exit_group@400ms)", getpid());
|
g_main_tid.store(gettid());
|
||||||
|
LOGI("install pid=%d main_tid=%d (PLT+ABRT-streak-freeze+TRAP+pc==lr-SEGV+exit_group@400ms)",
|
||||||
|
getpid(), (int)g_main_tid.load());
|
||||||
install_fatal_skip_handlers();
|
install_fatal_skip_handlers();
|
||||||
install_soft_signals();
|
install_soft_signals();
|
||||||
install_plt(api);
|
install_plt(api);
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user