Index: lib/asan/asan_flags.inc =================================================================== --- lib/asan/asan_flags.inc +++ lib/asan/asan_flags.inc @@ -135,3 +135,4 @@ ASAN_FLAG(bool, halt_on_error, true, "Crash the program after printing the first error report " "(WARNING: USE AT YOUR OWN RISK!)") +ASAN_FLAG(bool, print_cmdline, false, "Print cmdline on crash.") Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -238,6 +238,15 @@ DescribeThread(t->context()); } +static void PrintReproducerCmdline() { + char **argv = GetArgv(); + if (!argv) return; + Printf("\nReproducer cmdline: "); + for (uptr i = 0; argv[i] != 0; ++i) + Printf("%s ", argv[i]); + Printf("\n\n"); +} + // ---------------------- Address Descriptions ------------------- {{{1 static bool IsASCII(unsigned char c) { @@ -687,6 +696,9 @@ if (flags()->print_stats) __asan_print_accumulated_stats(); + if (flags()->print_cmdline) + PrintReproducerCmdline(); + // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. InternalScopedBuffer buffer_copy(kErrorMessageBufferSize); Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -282,6 +282,7 @@ u32 GetUid(); void ReExec(); +char **GetArgv(); bool StackSizeIsUnlimited(); void SetStackSizeLimitInBytes(uptr limit); bool AddressSpaceIsUnlimited(); Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ 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: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -666,6 +666,10 @@ LeakyResetEnv(kDyldInsertLibraries, new_env); } +char **GetArgv() { + return *_NSGetArgv(); +} + } // namespace __sanitizer #endif // SANITIZER_MAC Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ 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: test/asan/TestCases/Posix/print_cmdline.cc =================================================================== --- /dev/null +++ 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: Reproducer cmdline: + // CHECK-PRINT: {{Reproducer cmdline: .*-exe first second/third \[fourth\]}} + x[ten] = 1; // BOOM + return 0; +} +