diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -231,6 +231,9 @@ ENUM_CODEGENOPT(SanitizeAddressDtor, llvm::AsanDtorKind, 2, llvm::AsanDtorKind::Global) ///< Set how ASan global ///< destructors are emitted. +CODEGENOPT(SanitizeMemoryParamRetval, 1, 0) ///< Enable detection of uninitialized + ///< parameters and return values + ///< in MemorySanitizer CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection ///< in MemorySanitizer CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1669,6 +1669,13 @@ NormalizedValuesScope<"llvm::AsanDtorKind">, NormalizedValues<["None", "Global"]>, MarshallingInfoEnum, "Global">; +defm sanitize_memory_param_retval + : BoolOption<"f", "sanitize-memory-param-retval", + CodeGenOpts<"SanitizeMemoryParamRetval">, + DefaultFalse, + PosFlag, NegFlag, + BothFlags<[], " detection of uninitialized parameters and return values">>, + Group; // Note: This flag was introduced when it was necessary to distinguish between // ABI for correct codegen. This is no longer needed, but the flag is // not removed since targeting either ABI will behave the same. diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -33,6 +33,7 @@ int CoverageFeatures = 0; int MsanTrackOrigins = 0; bool MsanUseAfterDtor = true; + bool MsanParamRetval = false; bool CfiCrossDso = false; bool CfiICallGeneralizePointers = false; bool CfiCanonicalJumpTables = false; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -358,7 +358,8 @@ int TrackOrigins = CGOpts.SanitizeMemoryTrackOrigins; bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Memory); PM.add(createMemorySanitizerLegacyPassPass( - MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, + CGOpts.SanitizeMemoryParamRetval != 0})); // MemorySanitizer inserts complex instrumentation that mostly follows // the logic of the original code, but operates on "shadow" values. @@ -1163,11 +1164,11 @@ int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins; bool Recover = CodeGenOpts.SanitizeRecover.has(Mask); - MPM.addPass( - ModuleMemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); + MemorySanitizerOptions options(TrackOrigins, Recover, CompileKernel, + CodeGenOpts.SanitizeMemoryParamRetval); + MPM.addPass(ModuleMemorySanitizerPass(options)); FunctionPassManager FPM; - FPM.addPass( - MemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); + FPM.addPass(MemorySanitizerPass(options)); if (Level != OptimizationLevel::O0) { // MemorySanitizer inserts complex instrumentation that mostly // follows the logic of the original code, but operates on diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -641,10 +641,14 @@ Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor); + MsanParamRetval = Args.hasFlag( + options::OPT_fsanitize_memory_param_retval, + options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); } else { MsanUseAfterDtor = false; + MsanParamRetval = false; } if (AllAddedKinds & SanitizerKind::Thread) { @@ -1096,6 +1100,9 @@ if (MsanUseAfterDtor) CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); + if (MsanParamRetval) + CmdArgs.push_back("-fsanitize-memory-param-retval"); + // FIXME: Pass these parameters as function attributes, not as -llvm flags. if (!TsanMemoryAccess) { CmdArgs.push_back("-mllvm"); diff --git a/clang/test/CodeGen/msan-param-retval.c b/clang/test/CodeGen/msan-param-retval.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/msan-param-retval.c @@ -0,0 +1,19 @@ +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -fsanitize=memory -o - %s | \ +// RUN: FileCheck %s --check-prefix=CLEAN +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -fsanitize=memory -Xclang -enable-noundef-analysis -o - %s | \ +// RUN: FileCheck %s --check-prefixes=NOUNDEF,NOUNDEF_ONLY +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -fsanitize=memory -Xclang -enable-noundef-analysis -mllvm -msan-eager-checks -o - %s | \ +// RUN: FileCheck %s --check-prefixes=NOUNDEF,EAGER +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -fsanitize=memory -fsanitize-memory-param-retval -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CLEAN +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -fsanitize=memory -Xclang -enable-noundef-analysis -fsanitize-memory-param-retval -o - %s | \ +// RUN: FileCheck %s --check-prefixes=NOUNDEF,EAGER + +void bar(int x) { +} + +// CLEAN: define dso_local void @bar(i32 %x) #0 { +// NOUNDEF: define dso_local void @bar(i32 noundef %x) #0 { +// CLEAN: @__msan_param_tls +// NOUNDEF_ONLY: @__msan_param_tls +// EAGER-NOT: @__msan_param_tls diff --git a/clang/test/Driver/fsanitize-memory-param-retval.c b/clang/test/Driver/fsanitize-memory-param-retval.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/fsanitize-memory-param-retval.c @@ -0,0 +1,12 @@ +// RUN: %clang -target i386-gnu-linux %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck %s +// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck %s +// RUN: %clang -target aarch64-linux-gnu %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck %s +// RUN: %clang -target riscv32-linux-gnu %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck %s +// RUN: %clang -target riscv64-linux-gnu %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck %s +// CHECK: "-fsanitize-memory-param-retval" + +// RUN: %clang -target aarch64-linux-gnu -fsyntax-only %s -fsanitize=memory -fsanitize-memory-param-retval -c -### 2>&1 | FileCheck --check-prefix=11 %s +// 11: "-fsanitize-memory-param-retval" + +// RUN: not %clang -target x86_64-linux-gnu -fsyntax-only %s -fsanitize=memory -fsanitize-memory-param-retval=1 2>&1 | FileCheck --check-prefix=EXCESS %s +// EXCESS: error: unknown argument: '-fsanitize-memory-param-retval=