Backport ASan reports deduplication in recovery mode.
Backport from LLVM upstream r255228.
Optionally print reproducer cmdline in ASan reports.
Backport from LLVM upstream r258037.
Fix internal CHECK failure on double free in recovery mode.
Backport from LLVM upstream r259473.
Bail out on stack overflow in ASan recovery mode.
Backport from LLVM upstream r268713.
Change-Id: I11ad0ddf94e803a0f240bf76cdff529e1b72f576
Signed-off-by: Maxim Ostapenko <m.ostapenko@samsung.com>
return res;
}
- void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ // Set quarantine flag if chunk is allocated, issue ASan error report on
+ // available and quarantined ones. Return true on success, false otherwise.
+ bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr,
BufferedStackTrace *stack) {
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
- if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
- CHUNK_QUARANTINE, memory_order_acquire))
+ if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state,
+ CHUNK_QUARANTINE,
+ memory_order_acquire)) {
ReportInvalidFree(ptr, old_chunk_state, stack);
+ // It's not safe to push a chunk in quarantine on invalid free.
+ return false;
+ }
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+ return true;
}
// Expects the chunk to already be marked as quarantined by using
- // AtomicallySetQuarantineFlag.
+ // AtomicallySetQuarantineFlagIfAllocated.
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
}
ASAN_FREE_HOOK(ptr);
// Must mark the chunk as quarantined before any changes to its metadata.
- AtomicallySetQuarantineFlag(m, ptr, stack);
+ // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
+ if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
QuarantineChunk(m, ptr, stack, alloc_type);
}
static char *error_message_buffer = nullptr;
static uptr error_message_buffer_pos = 0;
static uptr error_message_buffer_size = 0;
+static const unsigned kAsanBuggyPcPoolSize = 25;
+static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
struct ReportData {
uptr pc;
// Print memory stats.
if (flags()->print_stats)
__asan_print_accumulated_stats();
+ if (common_flags()->print_cmdline)
+ PrintCmdline();
if (error_report_callback) {
error_report_callback(error_message_buffer);
}
u32 ScopedInErrorReport::reporting_thread_tid_;
void ReportStackOverflow(const SignalContext &sig) {
- ScopedInErrorReport in_report;
+ ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
Decorator d;
Printf("%s", d.Warning());
Report(
DescribeHeapAddress(addr, 1);
}
+// -------------- SuppressErrorReport -------------- {{{1
+// Avoid error reports duplicating for ASan recover mode.
+static bool SuppressErrorReport(uptr pc) {
+ if (!common_flags()->suppress_equal_pcs) return false;
+ for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
+ uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
+ if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
+ pc, memory_order_relaxed))
+ return false;
+ if (cmp == pc) return true;
+ }
+ Die();
+}
+
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal) {
+ if (!fatal && SuppressErrorReport(pc)) return;
ENABLE_FRAME_POINTER;
// Optimization experiments.
return name_len;
}
+void PrintCmdline() {
+ char **argv = GetArgv();
+ if (!argv) return;
+ Printf("\nCommand: ");
+ for (uptr i = 0; argv[i]; ++i)
+ Printf("%s ", argv[i]);
+ Printf("\n\n");
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
u32 GetUid();
void ReExec();
+char **GetArgv();
+void PrintCmdline();
bool StackSizeIsUnlimited();
void SetStackSizeLimitInBytes(uptr limit);
bool AddressSpaceIsUnlimited();
bool, abort_on_error, SANITIZER_MAC,
"If set, the tool calls abort() instead of _exit() after printing the "
"error report.")
+COMMON_FLAG(bool, suppress_equal_pcs, true,
+ "Deduplicate multiple reports for single source location in "
+ "halt_on_error=false mode (asan only).")
+COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash "
+ "(asan only).")
}
#endif
-static void GetArgsAndEnv(char*** argv, char*** envp) {
+static void GetArgsAndEnv(char ***argv, char ***envp) {
#if !SANITIZER_GO
if (&__libc_stack_end) {
#endif
#endif
}
+char **GetArgv() {
+ char **argv, **envp;
+ GetArgsAndEnv(&argv, &envp);
+ return argv;
+}
+
void ReExec() {
char **argv, **envp;
GetArgsAndEnv(&argv, &envp);
# endif
}
+char **GetArgv() {
+ return *_NSGetArgv();
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
// Do nothing.
}
+char **GetArgv() {
+ // FIXME: Actually implement this function.
+ return 0;
+}
+
} // namespace __sanitizer
#endif // _WIN32