Use _exit(1) instead of exit(1) after DB is open to avoid UAF#14850
Use _exit(1) instead of exit(1) after DB is open to avoid UAF#14850pdillinger wants to merge 2 commits into
Conversation
Summary: When `FinishInitDb()` or `Open()` calls `exit(1)` after the DB has been opened, background compaction/flush threads are still running. `exit()` triggers static object destruction (including the `KillPoint` singleton and its `rocksdb_kill_exclude_prefixes` vector) while those threads are still accessing them via `TestKillRandom()`, causing a heap-use-after-free detected by ASAN. This became more likely to trigger after the multi-DB support commit (3d0d60101e7f) which runs `RunStressTestImpl` on worker threads, making the race window larger when one DB fails initialization while other DBs background threads are active. The fix replaces `exit(1)` with `_exit(1)` in all error paths that fire after the DB has been opened. `_exit()` terminates immediately without running atexit handlers or destroying static objects, avoiding the race with background threads. Differential Revision: D108298839
|
@pdillinger has exported this pull request. If you are a Meta employee, you can view the originating Diff in D108298839. |
✅ clang-tidy: No findings on changed linesCompleted in 81.8s. |
|
@pdillinger has imported this pull request. If you are a Meta employee, you can view this in D108298839. |
🟡 Codex Code ReviewAuto-triggered after CI passed — reviewing commit b503ace ❌ Codex review failed before producing findings. ℹ️ About this responseGenerated by Codex CLI. Limitations:
Commands:
|
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit b503ace SummaryCorrect fix for a real ASAN-detected UAF bug. The approach ( High-severity findings (1):
Full review (click to expand)Findings🔴 HIGHH1. Incomplete scope -- many post-DB-open
|
| Context | Does code execute? | Assumptions hold? | Action needed? |
|---|---|---|---|
| Windows/MSVC | YES | YES -- _exit() via <process.h> |
None |
| MinGW cross-compile | YES | YES -- same <process.h> |
None |
| ASAN builds | YES | YES -- _exit() skips ASAN leak report but that's acceptable for error exits |
None |
| TSAN builds | YES | YES -- skips TSAN cleanup but acceptable for error exits | None |
| Multi-DB worker threads | YES | Partially -- only 4 of many exit calls fixed | Fix remaining calls (H1) |
Positive Observations
- The port abstraction pattern (
port::ImmediateExit) is well-chosen and consistent with existing patterns likeport::Crash. [[noreturn]]attribute is correctly applied and has precedent indb_bench_tool.cc:1380.- The documentation comment in
port_posix.his thorough and clearly explains the motivation. - Include dependencies are already satisfied (
<unistd.h>in port_posix.cc,<process.h>in port_win.h). - The fix correctly addresses the root cause (static destructor UAF) rather than trying to join threads before exit, which would be far more complex and error-prone.
ℹ️ About this response
Generated by Claude Code.
Review methodology: claude_md/code_review.md
Limitations:
- Claude may miss context from files not in the diff
- Large PRs may be truncated
- Always apply human judgment to AI suggestions
Commands:
/claude-review [context]— Request a code review/claude-query <question>— Ask about the PR or codebase
|
@pdillinger merged this pull request in 77d9ed7. |
Summary:
When
FinishInitDb()orOpen()callsexit(1)after the DB has been opened, background compaction/flush threads are still running.exit()triggers static object destruction (including theKillPointsingleton and itsrocksdb_kill_exclude_prefixesvector) while those threads are still accessing them viaTestKillRandom(), causing a heap-use-after-free detected by ASAN.This became more likely to trigger after the multi-DB support commit (3d0d60101e7f) which runs
RunStressTestImplon worker threads, making the race window larger when one DB fails initialization while other DBs background threads are active.The fix replaces
exit(1)with_exit(1)in all error paths that fire after the DB has been opened._exit()terminates immediately without running atexit handlers or destroying static objects, avoiding the race with background threads.Differential Revision: D108298839