Index: compiler-rt/trunk/lib/asan/asan_report.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_report.cc +++ compiler-rt/trunk/lib/asan/asan_report.cc @@ -687,6 +687,9 @@ if (flags()->print_stats) __asan_print_accumulated_stats(); + if (common_flags()->print_cmdline) + PrintCmdline(); + // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. InternalScopedBuffer buffer_copy(kErrorMessageBufferSize); Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h @@ -282,6 +282,8 @@ u32 GetUid(); void ReExec(); +char **GetArgv(); +void PrintCmdline(); bool StackSizeIsUnlimited(); void SetStackSizeLimitInBytes(uptr limit); bool AddressSpaceIsUnlimited(); Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc @@ -487,6 +487,15 @@ 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 Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc @@ -200,3 +200,5 @@ 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).") Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc @@ -424,7 +424,7 @@ } #endif -static void GetArgsAndEnv(char*** argv, char*** envp) { +static void GetArgsAndEnv(char ***argv, char ***envp) { #if !SANITIZER_GO if (&__libc_stack_end) { #endif @@ -441,6 +441,12 @@ #endif } +char **GetArgv() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return argv; +} + void ReExec() { char **argv, **envp; GetArgsAndEnv(&argv, &envp); Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc @@ -666,6 +666,10 @@ LeakyResetEnv(kDyldInsertLibraries, new_env); } +char **GetArgv() { + return *_NSGetArgv(); +} + } // namespace __sanitizer #endif // SANITIZER_MAC Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc @@ -770,6 +770,11 @@ // No need to re-exec on Windows. } +char **GetArgv() { + // FIXME: Actually implement this function. + return 0; +} + } // namespace __sanitizer #endif // _WIN32 Index: compiler-rt/trunk/test/asan/TestCases/Posix/print_cmdline.cc =================================================================== --- compiler-rt/trunk/test/asan/TestCases/Posix/print_cmdline.cc +++ compiler-rt/trunk/test/asan/TestCases/Posix/print_cmdline.cc @@ -0,0 +1,18 @@ +// Check that ASan can print reproducer cmdline for failed binary if desired. +// +// RUN: %clang_asan %s -o %t-exe +// +// RUN: env not %run %t-exe 2>&1 | FileCheck %s +// RUN: %env_asan_opts=print_cmdline=false not %run %t-exe 2>&1 | FileCheck %s +// RUN: %env_asan_opts=print_cmdline=true not %run %t-exe first second/third [fourth] 2>&1 | FileCheck %s --check-prefix CHECK-PRINT + +volatile int ten = 10; + +int main() { + char x[10]; + // CHECK-NOT: Command: + // CHECK-PRINT: {{Command: .*-exe first second/third \[fourth\]}} + x[ten] = 1; // BOOM + return 0; +} +