From: Evgeniy Stepanov Date: Thu, 20 Mar 2014 14:58:36 +0000 (+0000) Subject: [msan] -fsanitize-memory-track-origins=[level] flag and docs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=100624f4302982b5d5cc554cb9ba106186f77246;p=clang [msan] -fsanitize-memory-track-origins=[level] flag and docs. This change turns -fsanitize-memory-track-origins into -fsanitize-memory-track-origins=[level] flag (keeping the old one for compatibility). Possible levels are 0 (off), 1 (default) and 2 (incredibly detailed). See docs (part of this patch) for more info. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204346 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst index f769cc9bf1..9d6c22d8af 100644 --- a/docs/MemorySanitizer.rst +++ b/docs/MemorySanitizer.rst @@ -56,12 +56,10 @@ future). .. code-block:: console - % ./a.out 2>log - % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt - ==30106== WARNING: MemorySanitizer: UMR (uninitialized-memory-read) + % ./a.out + WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x7f45944b418a in main umr.cc:6 #1 0x7f45938b676c in __libc_start_main libc-start.c:226 - Exiting By default, MemorySanitizer exits on the first detected error. @@ -101,6 +99,13 @@ checks for certain source files and functions. All "Use of uninitialized value" warnings will be suppressed and all values loaded from memory will be considered fully initialized. +Report symbolization +==================== + +MemorySanitizer uses an external symbolizer to print files and line numbers in +reports. Make sure that ``llvm-symbolizer`` binary is in ``PATH``, +or set environment variable ``MSAN_SYMBOLIZER_PATH`` to point to it. + Origin Tracking =============== @@ -112,29 +117,59 @@ the example above, .. code-block:: console % clang -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2 umr.cc - % ./a.out 2>log - % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt - ==14425== WARNING: MemorySanitizer: UMR (uninitialized-memory-read) - ==14425== WARNING: Trying to symbolize code, but external symbolizer is not initialized! - #0 0x7f8bdda3824b in main umr.cc:6 - #1 0x7f8bdce3a76c in __libc_start_main libc-start.c:226 - raw origin id: 2030043137 - ORIGIN: heap allocation: - #0 0x7f8bdda4034b in operator new[](unsigned long) msan_new_delete.cc:39 - #1 0x7f8bdda3814d in main umr.cc:4 - #2 0x7f8bdce3a76c in __libc_start_main libc-start.c:226 - Exiting - -Origin tracking has proved to be very useful for debugging UMR + % ./a.out + WARNING: MemorySanitizer: use-of-uninitialized-value + #0 0x7f7893912f0b in main umr2.cc:6 + #1 0x7f789249b76c in __libc_start_main libc-start.c:226 + + Uninitialized value was created by a heap allocation + #0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44 + #1 0x7f7893912e06 in main umr2.cc:4 + +Origin tracking has proved to be very useful for debugging MemorySanitizer reports. It slows down program execution by a factor of 1.5x-2x on top of the usual MemorySanitizer slowdown. +MemorySanitizer can provide even more information with +``-fsanitize-memory-track-origins=2`` flag. In this mode reports +include information about intermediate stores the uninitialized value went +through. + +.. code-block:: console + + % cat umr2.cc + #include + + int main(int argc, char** argv) { + int* a = new int[10]; + a[5] = 0; + volatile int b = a[argc]; + if (b) + printf("xx\n"); + return 0; + } + + % clang -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O2 umr2.cc + % ./a.out + WARNING: MemorySanitizer: use-of-uninitialized-value + #0 0x7f7893912f0b in main umr2.cc:7 + #1 0x7f789249b76c in __libc_start_main libc-start.c:226 + + Uninitialized value was stored to memory at + #0 0x7f78938b5c25 in __msan_chain_origin msan.cc:484 + #1 0x7f7893912ecd in main umr2.cc:6 + + Uninitialized value was created by a heap allocation + #0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44 + #1 0x7f7893912e06 in main umr2.cc:4 + + Handling external code ============================ MemorySanitizer requires that all program code is instrumented. This also includes any libraries that the program depends on, even libc. -Failing to achieve this may result in false UMR reports. +Failing to achieve this may result in false reports. Full MemorySanitizer instrumentation is very difficult to achieve. To make it easier, MemorySanitizer runtime library includes 70+ diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index e58093831b..43a8717c9b 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -968,12 +968,17 @@ are listed below. Extra features of MemorySanitizer (require explicit ``-fsanitize=memory``): - - ``-fsanitize-memory-track-origins``: Enables origin tracking in + - ``-fsanitize-memory-track-origins[=level]``: Enables origin tracking in MemorySanitizer. Adds a second section to MemorySanitizer reports pointing to the heap or stack allocation the uninitialized bits came from. Slows down execution by additional 1.5x-2x. + Possible values for level are 0 (off), 1 (default), 2. Level 2 adds more + sections to MemorySanitizer reports describing the order of memory stores + the uninitialized value went through. Beware, this mode may use a lot of + extra memory. + Extra features of UndefinedBehaviorSanitizer: - ``-fno-sanitize-recover``: By default, after a sanitizer diagnoses diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 84a863ca55..b3afd7a0b8 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -485,11 +485,15 @@ def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">, def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">, Group, HelpText<"Don't use blacklist file for sanitizers">; +def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">, + Group, Flags<[CC1Option]>, + HelpText<"Enable origins tracking in MemorySanitizer">; def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">, Group, Flags<[CC1Option]>, HelpText<"Enable origins tracking in MemorySanitizer">; def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">, - Group; + Group, Flags<[CC1Option]>, + HelpText<"Disable origins tracking in MemorySanitizer">; def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group; def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h index d12e5faf4e..2080e1c468 100644 --- a/include/clang/Driver/SanitizerArgs.h +++ b/include/clang/Driver/SanitizerArgs.h @@ -48,7 +48,7 @@ class SanitizerArgs { unsigned Kind; std::string BlacklistFile; - bool MsanTrackOrigins; + int MsanTrackOrigins; bool AsanZeroBaseShadow; bool UbsanTrapOnError; diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index 400591a08a..9c9847314d 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -98,7 +98,7 @@ CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero ///< offset in AddressSanitizer. -CODEGENOPT(SanitizeMemoryTrackOrigins, 1, 0) ///< Enable tracking origins in +CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in ///< MemorySanitizer CODEGENOPT(SanitizeUndefinedTrapOnError, 1, 0) ///< Set on /// -fsanitize-undefined-trap-on-error diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index a4b32df9e3..d66f3b4a01 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -23,7 +24,7 @@ using namespace llvm::opt; void SanitizerArgs::clear() { Kind = 0; BlacklistFile = ""; - MsanTrackOrigins = false; + MsanTrackOrigins = 0; AsanZeroBaseShadow = false; UbsanTrapOnError = false; } @@ -146,12 +147,27 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, BlacklistFile = BLPath; } - // Parse -f(no-)sanitize-memory-track-origins options. - if (NeedsMsan) - MsanTrackOrigins = - Args.hasFlag(options::OPT_fsanitize_memory_track_origins, - options::OPT_fno_sanitize_memory_track_origins, - /* Default */false); + // Parse -f[no-]sanitize-memory-track-origins[=level] options. + if (NeedsMsan) { + if (Arg *A = + Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, + options::OPT_fsanitize_memory_track_origins, + options::OPT_fno_sanitize_memory_track_origins)) { + if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { + MsanTrackOrigins = 1; + } else if (A->getOption().matches( + options::OPT_fno_sanitize_memory_track_origins)) { + MsanTrackOrigins = 0; + } else { + StringRef S = A->getValue(); + if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || + MsanTrackOrigins > 2) { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S; + } + } + } + } + if (NeedsAsan) AsanZeroBaseShadow = (TC.getTriple().getEnvironment() == llvm::Triple::Android); @@ -175,7 +191,8 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, } if (MsanTrackOrigins) - CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); + CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + + llvm::utostr(MsanTrackOrigins))); // Workaround for PR16386. if (needsMsanRt()) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 79d81511c3..f31c8c0933 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -451,9 +451,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist); Opts.SanitizeMemoryTrackOrigins = - Args.hasArg(OPT_fsanitize_memory_track_origins); + getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeUndefinedTrapOnError = - Args.hasArg(OPT_fsanitize_undefined_trap_on_error); + Args.hasArg(OPT_fsanitize_undefined_trap_on_error); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c index eebcc1b81f..aa9dfa22bb 100644 --- a/test/Driver/fsanitize.c +++ b/test/Driver/fsanitize.c @@ -76,8 +76,27 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -pie %s -### 2>&1 // OK -// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins -pie %s -### 2>&1 -// OK +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-1 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=1 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-1 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-1 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fno-sanitize-memory-track-origins -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-1 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=0 -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-1 + +// CHECK-TRACK-ORIGINS-1: -fsanitize-memory-track-origins=1 + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fno-sanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=0 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins -fno-sanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins -fsanitize-memory-track-origins=0 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-sanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-memory-track-origins=0 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TRACK-ORIGINS +// CHECK-NO-TRACK-ORIGINS-NOT: sanitize-memory-track-origins + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=2 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-2 +// CHECK-TRACK-ORIGINS-2: -fsanitize-memory-track-origins=2 + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=3 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-3 +// CHECK-TRACK-ORIGINS-3: error: invalid value '3' in '-fsanitize-memory-track-origins=3' // RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-sanitize=vptr -fsanitize=undefined,address %s -### 2>&1 // OK