Skip to content

Commit

Permalink
[Sanitizers] Unify the semantics and usage of "exitcode" runtime flag…
Browse files Browse the repository at this point in the history
… across all sanitizers.

Summary:
Merge "exitcode" flag from ASan, LSan, TSan and "exit_code" from MSan
into one entity. Additionally, make sure sanitizer_common now uses the
value of common_flags()->exitcode when dying on error, so that this
flag will automatically work for other sanitizers (UBSan and DFSan) as
well.

User-visible changes:
* "exit_code" MSan runtime flag is now deprecated. If explicitly
  specified, this flag will take precedence over "exitcode".
  The users are encouraged to migrate to the new version.
* __asan_set_error_exit_code() and __msan_set_exit_code() functions
  are removed. With few exceptions, we don't support changing runtime
  flags during program execution - we can't make them thread-safe.
  The users should use __sanitizer_set_death_callback()
  that would call _exit() with proper exit code instead.
* Plugin tools (LSan and UBSan) now inherit the exit code of the parent
  tool. In particular, this means that ASan would now crash the program
  with exit code "1" instead of "23" if it detects leaks.

Reviewers: kcc, eugenis

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D12120

llvm-svn: 245734
  • Loading branch information
vonosmas committed Aug 21, 2015
1 parent dddad10 commit bb79b06
Show file tree
Hide file tree
Showing 24 changed files with 29 additions and 64 deletions.
4 changes: 0 additions & 4 deletions compiler-rt/include/sanitizer/asan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ extern "C" {
void __asan_report_error(void *pc, void *bp, void *sp,
void *addr, int is_write, size_t access_size);

// Sets the exit code to use when reporting an error.
// Returns the old value.
int __asan_set_error_exit_code(int exit_code);

// Deprecated. Call __sanitizer_set_death_callback instead.
void __asan_set_death_callback(void (*callback)(void));

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/include/sanitizer/lsan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extern "C" {

// Check for leaks now. This function behaves identically to the default
// end-of-process leak check. In particular, it will terminate the process if
// leaks are found and the exit_code flag is non-zero.
// leaks are found and the exitcode runtime flag is non-zero.
// Subsequent calls to this function will have no effect and end-of-process
// leak check will not run. Effectively, end-of-process leak check is moved to
// the time of first invocation of this function.
Expand Down
4 changes: 0 additions & 4 deletions compiler-rt/include/sanitizer/msan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ extern "C" {
* is not. */
void __msan_check_mem_is_initialized(const volatile void *x, size_t size);

/* Set exit code when error(s) were detected.
Value of 0 means don't change the program exit code. */
void __msan_set_exit_code(int exit_code);

/* For testing:
__msan_set_expect_umr(1);
... some buggy code ...
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/asan_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ void InitializeFlags() {
cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf.malloc_context_size = kDefaultMallocContextSize;
cf.intercept_tls_get_addr = true;
cf.exitcode = 1;
OverrideCommonFlags(cf);
}
Flags *f = flags();
Expand Down
2 changes: 0 additions & 2 deletions compiler-rt/lib/asan/asan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ ASAN_FLAG(
"bytes that will be filled with malloc_fill_byte on malloc.")
ASAN_FLAG(int, malloc_fill_byte, 0xbe,
"Value used to fill the newly allocated memory.")
ASAN_FLAG(int, exitcode, ASAN_DEFAULT_FAILURE_EXITCODE,
"Override the program exit status if the tool found an error.")
ASAN_FLAG(bool, allow_user_poisoning, true,
"If set, user may manually mark memory regions as poisoned or "
"unpoisoned.")
Expand Down
2 changes: 0 additions & 2 deletions compiler-rt/lib/asan/asan_interface_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ extern "C" {
void __asan_report_error(uptr pc, uptr bp, uptr sp,
uptr addr, int is_write, uptr access_size, u32 exp);

SANITIZER_INTERFACE_ATTRIBUTE
int __asan_set_error_exit_code(int exit_code);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_set_death_callback(void (*callback)(void));
SANITIZER_INTERFACE_ATTRIBUTE
Expand Down
2 changes: 0 additions & 2 deletions compiler-rt/lib/asan/asan_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_libc.h"

#define ASAN_DEFAULT_FAILURE_EXITCODE 1

#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# error "The AddressSanitizer run-time should not be"
" instrumented by AddressSanitizer"
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ class ScopedInErrorReport {
}
// If we're still not dead for some reason, use raw _exit() instead of
// Die() to bypass any additional checks.
internal__exit(flags()->exitcode);
internal__exit(common_flags()->exitcode);
}
if (report) report_data = *report;
report_happened = true;
Expand Down
8 changes: 0 additions & 8 deletions compiler-rt/lib/asan/asan_rtl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ static void AsanDie() {
__sanitizer_cov_dump();
if (flags()->abort_on_error)
Abort();
internal__exit(flags()->exitcode);
}

static void AsanCheckFailed(const char *file, int line, const char *cond,
Expand Down Expand Up @@ -267,7 +266,6 @@ static NOINLINE void force_interface_symbols() {
case 30: __asan_address_is_poisoned(0); break;
case 31: __asan_poison_memory_region(0, 0); break;
case 32: __asan_unpoison_memory_region(0, 0); break;
case 33: __asan_set_error_exit_code(0); break;
case 34: __asan_before_dynamic_init(0); break;
case 35: __asan_after_dynamic_init(); break;
case 36: __asan_poison_stack_memory(0, 0); break;
Expand Down Expand Up @@ -550,12 +548,6 @@ static AsanInitializer asan_initializer;
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT

int NOINLINE __asan_set_error_exit_code(int exit_code) {
int old = flags()->exitcode;
flags()->exitcode = exit_code;
return old;
}

void NOINLINE __asan_handle_no_return() {
int local_stack;
AsanThread *curr_thread = GetCurrentThread();
Expand Down
10 changes: 0 additions & 10 deletions compiler-rt/lib/asan/tests/asan_interface_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,6 @@ static void DoDoubleFree() {
delete Ident(x);
}

TEST(AddressSanitizerInterface, ExitCode) {
int original_exit_code = __asan_set_error_exit_code(7);
EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
EXPECT_EQ(7, __asan_set_error_exit_code(8));
EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
EXPECT_EXIT(DoDoubleFree(),
::testing::ExitedWithCode(original_exit_code), "");
}

static void MyDeathCallback() {
fprintf(stderr, "MyDeathCallback\n");
fflush(0); // On Windows, stderr doesn't flush on crash.
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/lsan/lsan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static void InitializeFlags() {
cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
cf.malloc_context_size = 30;
cf.detect_leaks = true;
cf.exitcode = 23;
OverrideCommonFlags(cf);
}

Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/lsan/lsan_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,10 @@ void DoLeakCheck() {
if (!have_leaks) {
return;
}
if (flags()->exitcode) {
if (common_flags()->exitcode) {
if (common_flags()->coverage)
__sanitizer_cov_dump();
internal__exit(flags()->exitcode);
internal__exit(common_flags()->exitcode);
}
}

Expand Down
2 changes: 0 additions & 2 deletions compiler-rt/lib/lsan/lsan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ LSAN_FLAG(
"Aggregate two objects into one leak if this many stack frames match. If "
"zero, the entire stack trace must match.")
LSAN_FLAG(int, max_leaks, 0, "The number of leaks reported.")
LSAN_FLAG(int, exitcode, 23,
"If nonzero kill the process with this exit code upon finding leaks.")

// Flags controlling the root set of reachable memory.
LSAN_FLAG(bool, use_globals, true,
Expand Down
20 changes: 12 additions & 8 deletions compiler-rt/lib/msan/msan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ static void InitializeFlags() {
// FIXME: test and enable.
cf.check_printf = false;
cf.intercept_tls_get_addr = true;
cf.exitcode = 77;
OverrideCommonFlags(cf);
}

Expand Down Expand Up @@ -185,11 +186,18 @@ static void InitializeFlags() {

if (common_flags()->help) parser.PrintFlagDescriptions();

// Check flag values:
if (f->exit_code < 0 || f->exit_code > 127) {
Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
Die();
// Check if deprecated exit_code MSan flag is set.
if (f->exit_code != -1) {
if (Verbosity())
Printf("MSAN_OPTIONS=exit_code is deprecated! "
"Please use MSAN_OPTIONS=exitcode instead.\n");
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.exitcode = f->exit_code;
OverrideCommonFlags(cf);
}

// Check flag values:
if (f->origin_history_size < 0 ||
f->origin_history_size > Origin::kMaxDepth) {
Printf(
Expand Down Expand Up @@ -421,10 +429,6 @@ void __msan_init() {
msan_inited = 1;
}

void __msan_set_exit_code(int exit_code) {
flags()->exit_code = exit_code;
}

void __msan_set_keep_going(int keep_going) {
flags()->halt_on_error = !keep_going;
}
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/msan/msan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
// MSAN_FLAG(Type, Name, DefaultValue, Description)
// See COMMON_FLAG in sanitizer_flags.inc for more details.

MSAN_FLAG(int, exit_code, 77, "")
MSAN_FLAG(int, exit_code, -1,
"DEPRECATED. Use exitcode from common flags instead.")
MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "")
MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "")
MSAN_FLAG(bool, poison_heap_with_zeroes, false, "")
Expand Down
6 changes: 1 addition & 5 deletions compiler-rt/lib/msan/msan_interface_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __msan_init();

// Print a warning and maybe return.
// This function can die based on flags()->exit_code.
// This function can die based on common_flags()->exitcode.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_warning();

Expand Down Expand Up @@ -106,10 +106,6 @@ int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_on_return();

// Default: -1 (don't exit on error).
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_exit_code(int exit_code);

SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_keep_going(int keep_going);

Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/msan/msan_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@ void MsanDie() {
__sanitizer_cov_dump();
if (death_callback)
death_callback();
internal__exit(flags()->exit_code);
}

static void MsanAtExit(void) {
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
ReportStats();
if (msan_report_count > 0) {
ReportAtExitStatistics();
if (flags()->exit_code) _exit(flags()->exit_code);
if (common_flags()->exitcode)
internal__exit(common_flags()->exitcode);
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void NORETURN Die() {
UserDieCallback();
if (InternalDieCallback)
InternalDieCallback();
internal__exit(1);
internal__exit(common_flags()->exitcode);
}

static CheckFailedCallbackType CheckFailedCallback;
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,5 @@ COMMON_FLAG(bool, strict_memcmp, true,
COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer "
"mappings in /proc/self/maps with "
"user-readable names")
COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool "
"found an error")
1 change: 1 addition & 0 deletions compiler-rt/lib/tsan/rtl/tsan_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ void InitializeFlags(Flags *f, const char *env) {
#endif
cf.print_suppressions = false;
cf.stack_trace_format = " #%n %f %S %M";
cf.exitcode = 66;
OverrideCommonFlags(cf);
}

Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/tsan/rtl/tsan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ TSAN_FLAG(
"If set, all atomics are effectively sequentially consistent (seq_cst), "
"regardless of what user actually specified.")
TSAN_FLAG(bool, print_benign, false, "Print matched \"benign\" races at exit.")
TSAN_FLAG(int, exitcode, 66, "Override exit status if something was reported.")
TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.")
TSAN_FLAG(int, atexit_sleep_ms, 1000,
"Sleep in main thread before exiting for that many ms "
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/tsan/rtl/tsan_rtl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ int Finalize(ThreadState *thr) {
StatOutput(ctx->stat);
#endif

return failed ? flags()->exitcode : 0;
return failed ? common_flags()->exitcode : 0;
}

#ifndef SANITIZER_GO
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
PrintReport(rep);
ctx->nreported++;
if (flags()->halt_on_error)
internal__exit(flags()->exitcode);
internal__exit(common_flags()->exitcode);
return true;
}

Expand Down
6 changes: 0 additions & 6 deletions compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ TEST(Flags, DefaultValues) {
Flags f;

f.enable_annotations = false;
f.exitcode = -11;
InitializeFlags(&f, "");
EXPECT_EQ(66, f.exitcode);
EXPECT_EQ(true, f.enable_annotations);
}

Expand All @@ -46,7 +44,6 @@ static const char *options1 =
" report_atomic_races=0"
" force_seq_cst_atomics=0"
" print_benign=0"
" exitcode=111"
" halt_on_error=0"
" atexit_sleep_ms=222"
" profile_memory=qqq"
Expand All @@ -72,7 +69,6 @@ static const char *options2 =
" report_atomic_races=true"
" force_seq_cst_atomics=true"
" print_benign=true"
" exitcode=222"
" halt_on_error=true"
" atexit_sleep_ms=123"
" profile_memory=bbbbb"
Expand All @@ -98,7 +94,6 @@ void VerifyOptions1(Flags *f) {
EXPECT_EQ(f->report_atomic_races, 0);
EXPECT_EQ(f->force_seq_cst_atomics, 0);
EXPECT_EQ(f->print_benign, 0);
EXPECT_EQ(f->exitcode, 111);
EXPECT_EQ(f->halt_on_error, 0);
EXPECT_EQ(f->atexit_sleep_ms, 222);
EXPECT_EQ(f->profile_memory, std::string("qqq"));
Expand All @@ -124,7 +119,6 @@ void VerifyOptions2(Flags *f) {
EXPECT_EQ(f->report_atomic_races, true);
EXPECT_EQ(f->force_seq_cst_atomics, true);
EXPECT_EQ(f->print_benign, true);
EXPECT_EQ(f->exitcode, 222);
EXPECT_EQ(f->halt_on_error, true);
EXPECT_EQ(f->atexit_sleep_ms, 123);
EXPECT_EQ(f->profile_memory, std::string("bbbbb"));
Expand Down

0 comments on commit bb79b06

Please sign in to comment.