https://github.com/bjosv created https://github.com/llvm/llvm-project/pull/201803
Adds `-fsanitize-compilation-dir=<dir>` to set the compilation directory for sanitizer metadata. Absolute source paths that start with the given directory are made relative to it, affecting ASan module names and UBSan diagnostic source locations. This enables reproducible builds when using AddressSanitizer or UndefinedBehaviorSanitizer from different build directories. The flag follows the established `-f*-compilation-dir` pattern used by `-fdebug-compilation-dir` and `-fcoverage-compilation-dir`. It is also implied by `-ffile-compilation-dir=`, which sets the compilation directory for debug info, coverage, and now sanitizer metadata in a single flag. This addresses the issue where ASan and UBSan embed absolute source file paths in binary metadata (.rodata), causing non-reproducible builds when compiling from different directories. This flag was suggeted in https://github.com/llvm/llvm-project/pull/186908#issuecomment-4071226467 as an alternative to adding a `-fsanitize-prefix-map` flag. A short summary of the changes: - New driver and CC1 flag -fsanitize-compilation-dir= - -ffile-compilation-dir= implies -fsanitize-compilation-dir= (last-on-command-line wins) - ASan module name (___asan_gen_module) is made relative when the flag is set - UBSan source locations (EmitCheckSourceLocation) are made relative when the flag is set - Dependency scanning resets the new option alongside the existing compilation dir options - Documentation updates for AddressSanitizer, UndefinedBehaviorSanitizer, UsersManual, and ReleaseNotes - Driver test, ASan codegen test, and UBSan codegen test added From f45ee969f011915705771298f185c45e6dd29d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= <[email protected]> Date: Mon, 23 Mar 2026 09:59:57 +0100 Subject: [PATCH] [Clang] Add -fsanitize-compilation-dir= for reproducible sanitizer builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add -fsanitize-compilation-dir=<dir> to set the compilation directory for sanitizer metadata. Absolute source paths that start with the given directory are made relative to it, affecting ASan module names and UBSan diagnostic source locations. This enables reproducible builds when using AddressSanitizer or UndefinedBehaviorSanitizer from different build directories. The flag follows the established -f*-compilation-dir pattern used by -fdebug-compilation-dir and -fcoverage-compilation-dir. It is also implied by -ffile-compilation-dir=, which sets the compilation directory for debug info, coverage, and now sanitizer metadata in a single flag. This addresses the issue where ASan and UBSan embed absolute source file paths in binary metadata (.rodata), causing non-reproducible builds when compiling from different directories. Signed-off-by: Björn Svensson <[email protected]> --- clang/docs/AddressSanitizer.rst | 29 +++++++++++++++++ clang/docs/ReleaseNotes.rst | 5 +++ clang/docs/UndefinedBehaviorSanitizer.rst | 6 ++++ clang/docs/UsersManual.rst | 8 +++++ clang/include/clang/Basic/CodeGenOptions.h | 3 ++ clang/include/clang/Options/Options.td | 6 +++- clang/lib/CodeGen/BackendUtil.cpp | 1 + clang/lib/CodeGen/CGExpr.cpp | 17 ++++++++++ .../DependencyScanning/ModuleDepCollector.cpp | 2 ++ clang/lib/Driver/SanitizerArgs.cpp | 7 ++++ clang/lib/Frontend/CompilerInvocation.cpp | 1 + .../CodeGen/asan-sanitize-compilation-dir.c | 20 ++++++++++++ .../ubsan-sanitize-compilation-dir.cpp | 27 ++++++++++++++++ clang/test/Driver/fsanitize-compilation-dir.c | 13 ++++++++ .../Instrumentation/AddressSanitizer.h | 2 ++ .../Instrumentation/AddressSanitizer.cpp | 32 ++++++++++++++++--- 16 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 clang/test/CodeGen/asan-sanitize-compilation-dir.c create mode 100644 clang/test/CodeGen/ubsan-sanitize-compilation-dir.cpp create mode 100644 clang/test/Driver/fsanitize-compilation-dir.c diff --git a/clang/docs/AddressSanitizer.rst b/clang/docs/AddressSanitizer.rst index 80b1cdd95d77a..80144206b2494 100644 --- a/clang/docs/AddressSanitizer.rst +++ b/clang/docs/AddressSanitizer.rst @@ -47,6 +47,11 @@ in error messages add ``-fno-omit-frame-pointer``. To get perfect stack traces you may need to disable inlining (just use ``-O1``) and tail call elimination (``-fno-optimize-sibling-calls``). +To produce reproducible builds, use ``-fsanitize-compilation-dir=<dir>`` (or +``-ffile-compilation-dir=<dir>`` which also sets it for debug info and +coverage) to make absolute paths in ASan metadata relative to the given +directory. See `Remapping source paths`_ for details. + .. code-block:: console % cat example_UseAfterFree.cc @@ -408,6 +413,30 @@ run-time performance, which leads to increased binary size. Using the flag forces all code instrumentation to be outlined, which reduces the size of the generated code, but also reduces the run-time performance. +Remapping source paths +---------------------- + +AddressSanitizer embeds the source file path in global metadata. For +reproducible builds, the option ``-fsanitize-compilation-dir=<dir>`` can be +used to set the compilation directory. Absolute source paths that start with +``<dir>`` are made relative to it. + +The option ``-ffile-compilation-dir=<dir>`` can also be used, which +additionally sets the compilation directory for debug info and coverage +mapping. When both ``-ffile-compilation-dir`` and ``-fsanitize-compilation-dir`` +are specified, the last one on the command line wins for sanitizer metadata. + +Example +^^^^^^^ + +.. code-block:: console + + # Make absolute paths relative to the build directory + $ clang -fsanitize=address -fsanitize-compilation-dir=/build/dir source.c + + # Using -ffile-compilation-dir to also cover debug info and coverage + $ clang -fsanitize=address -ffile-compilation-dir=/home/user/project source.c + Limitations =========== diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9e4a47a5b18fc..b6395c6c9058a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -929,6 +929,11 @@ Sanitizers ---------- - UndefinedBehaviorSanitizer now supports ``__ubsan_default_suppressions``. +- Added ``-fsanitize-compilation-dir=`` to set the compilation directory for + sanitizer metadata (UBSan diagnostics and ASan module names), making + absolute paths relative for reproducible builds. Also implied by + ``-ffile-compilation-dir=``. + Python Binding Changes ---------------------- - Add deprecation warnings to ``CompletionChunk.isKind...`` methods. diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index 3ff1a77e33a6c..4d5b760365a7d 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -522,6 +522,10 @@ information. If ``N`` is positive, file information emitted by UndefinedBehaviorSanitizer will drop the first ``N`` components from the file path. If ``N`` is negative, the last ``N`` components will be kept. +Alternatively, ``-fsanitize-compilation-dir=<dir>`` (or +``-ffile-compilation-dir=<dir>``) can be used to set the compilation directory, +making absolute paths relative to it. This is useful for reproducible builds. + Example ------- @@ -532,6 +536,8 @@ For a file called ``/code/library/file.cpp``, here is what would be emitted: * ``-fsanitize-undefined-strip-path-components=2``: ``library/file.cpp`` * ``-fsanitize-undefined-strip-path-components=-1``: ``file.cpp`` * ``-fsanitize-undefined-strip-path-components=-2``: ``library/file.cpp`` +* ``-fsanitize-compilation-dir=/code``: ``library/file.cpp`` +* ``-fsanitize-compilation-dir=/code/library``: ``file.cpp`` More Information ================ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 3392a210f0bb0..c6f25a34c06d7 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2277,6 +2277,14 @@ are listed below. See :doc: `AddressSanitizer` for more details. +.. option:: -fsanitize-compilation-dir=<dir> + + Set the compilation directory for sanitizer metadata. Absolute source paths + that start with the given directory are made relative to it, affecting + UBSan diagnostic source locations and ASan module names. This can be used + to achieve reproducible builds regardless of the build directory. Also + implied by ``-ffile-compilation-dir=``. + .. option:: -f[no-]sanitize-type-outline-instrumentation Controls how type sanitizer code is generated. If enabled will always use diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index e43112b4bb98b..aaacca4c5190c 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -260,6 +260,9 @@ class CodeGenOptions : public CodeGenOptionsBase { /// The string to embed in coverage mapping as the current working directory. std::string CoverageCompilationDir; + /// The compilation directory to use for sanitizer metadata. + std::string SanitizeCompilationDir; + /// The string to embed in the debug information for the compile unit, if /// non-empty. std::string DwarfDebugFlags; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 8451a3698ef17..989a86f84728a 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -1811,9 +1811,13 @@ def fcoverage_compilation_dir_EQ : Joined<["-"], "fcoverage-compilation-dir=">, Group<f_Group>, Visibility<[ClangOption, CC1Option, CC1AsOption, CLOption]>, HelpText<"The compilation directory to embed in the coverage mapping.">, MarshallingInfoString<CodeGenOpts<"CoverageCompilationDir">>; +def fsanitize_compilation_dir_EQ : Joined<["-"], "fsanitize-compilation-dir=">, + Group<f_Group>, Visibility<[ClangOption, CC1Option]>, + HelpText<"The compilation directory to use for sanitizer metadata.">, + MarshallingInfoString<CodeGenOpts<"SanitizeCompilationDir">>; def ffile_compilation_dir_EQ : Joined<["-"], "ffile-compilation-dir=">, Group<f_Group>, Visibility<[ClangOption, CLOption, DXCOption]>, - HelpText<"The compilation directory to embed in the debug info and coverage mapping.">; + HelpText<"The compilation directory to embed in the debug info, coverage mapping, and sanitizer metadata.">; defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling", CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index a46a25c4492f2..bb8218af31e92 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -750,6 +750,7 @@ static void addSanitizers(const Triple &TargetTriple, Opts.Recover = CodeGenOpts.SanitizeRecover.has(Mask); Opts.UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope; Opts.UseAfterReturn = CodeGenOpts.getSanitizeAddressUseAfterReturn(); + Opts.CompilationDir = CodeGenOpts.SanitizeCompilationDir; MPM.addPass(AddressSanitizerPass(Opts, UseGlobalGC, UseOdrIndicator, DestructorKind)); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 325902f2127bc..c3bea476732d7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -49,6 +49,7 @@ #include "llvm/IR/MatrixBuilder.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/xxhash.h" @@ -4050,6 +4051,22 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) { if (PLoc.isValid()) { StringRef FilenameString = PLoc.getFilename(); + // If a sanitize compilation dir is set, make absolute paths relative to it. + llvm::SmallString<256> FileBuf(FilenameString); + if (!CGM.getCodeGenOpts().SanitizeCompilationDir.empty() && + llvm::sys::path::is_absolute(FilenameString)) { + llvm::SmallString<256> CompDir( + CGM.getCodeGenOpts().SanitizeCompilationDir); + if (!llvm::sys::path::is_absolute(CompDir)) + llvm::sys::fs::make_absolute(CompDir); + llvm::sys::path::remove_dots(CompDir, /*remove_dot_dot=*/true); + // Ensure trailing separator so "/foo" doesn't match "/foobar/x.c". + if (!CompDir.empty() && !llvm::sys::path::is_separator(CompDir.back())) + CompDir += llvm::sys::path::get_separator(); + if (llvm::sys::path::replace_path_prefix(FileBuf, CompDir, "")) + FilenameString = FileBuf; + } + int PathComponentsToStrip = CGM.getCodeGenOpts().EmitCheckPathComponentsToStrip; if (PathComponentsToStrip < 0) { diff --git a/clang/lib/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/DependencyScanning/ModuleDepCollector.cpp index f9fe50564a5ae..24ce027a8004f 100644 --- a/clang/lib/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/DependencyScanning/ModuleDepCollector.cpp @@ -136,6 +136,7 @@ static void optimizeCWD(CowCompilerInvocation &BuildInvocation, StringRef CWD) { BuildInvocation.getMutFileSystemOpts().WorkingDir.clear(); BuildInvocation.getMutCodeGenOpts().DebugCompilationDir.clear(); BuildInvocation.getMutCodeGenOpts().CoverageCompilationDir.clear(); + BuildInvocation.getMutCodeGenOpts().SanitizeCompilationDir.clear(); } static std::vector<std::string> splitString(std::string S, char Separator) { @@ -185,6 +186,7 @@ void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) { CGOpts.DebugCompilationDir.clear(); CGOpts.CoverageCompilationDir.clear(); + CGOpts.SanitizeCompilationDir.clear(); CGOpts.CoverageDataFile.clear(); CGOpts.CoverageNotesFile.clear(); CGOpts.ProfileInstrumentUsePath.clear(); diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 31660dd29407c..b80f90b2909a0 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1697,6 +1697,13 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (Sanitizers.has(SanitizerKind::MemtagStack) && !hasTargetFeatureMTE(CmdArgs)) TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature); + + // Add sanitize compilation dir. + if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, + options::OPT_fsanitize_compilation_dir_EQ)) { + CmdArgs.push_back(Args.MakeArgString("-fsanitize-compilation-dir=" + + Twine(A->getValue()))); + } } SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 9fc695a74a3c7..384dc6482ae5c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -5396,6 +5396,7 @@ void CompilerInvocationBase::visitPathsImpl( auto &CodeGenOpts = *this->CodeGenOpts; RETURN_IF(CodeGenOpts.DebugCompilationDir); RETURN_IF(CodeGenOpts.CoverageCompilationDir); + RETURN_IF(CodeGenOpts.SanitizeCompilationDir); // Sanitizer options. RETURN_IF_MANY(LangOpts->NoSanitizeFiles); diff --git a/clang/test/CodeGen/asan-sanitize-compilation-dir.c b/clang/test/CodeGen/asan-sanitize-compilation-dir.c new file mode 100644 index 0000000000000..c173c74640fae --- /dev/null +++ b/clang/test/CodeGen/asan-sanitize-compilation-dir.c @@ -0,0 +1,20 @@ +// Verify that -fsanitize-compilation-dir makes absolute filenames relative +// in the ASan module name embedded in instrumented code. + +// RUN: mkdir -p %t.dir/sub +// RUN: cp %s %t.dir/sub/test.c +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-DEFAULT %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address -fsanitize-compilation-dir=%t.dir/ %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address -fsanitize-compilation-dir=%t.dir %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: cd %t.dir && %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address -fsanitize-compilation-dir=. %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: cd %t.dir/sub && %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address -fsanitize-compilation-dir=.. %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s + +// Verify that a partial prefix match does not strip (e.g. /tmp/dir vs /tmp/directory). +// RUN: mkdir -p %t.directory +// RUN: cp %s %t.directory/test.c +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=address -fsanitize-compilation-dir=%t.dir %t.directory/test.c -o - | FileCheck -check-prefix=CHECK-NO-FALSE-MATCH %s + +// CHECK-DEFAULT: @___asan_gen_module = private constant [{{.*}} x i8] c"{{.+}}test.c\00" +// CHECK-STRIPPED: @___asan_gen_module = private constant [{{.*}} x i8] c"sub{{.}}test.c\00" +// CHECK-NO-FALSE-MATCH: @___asan_gen_module = private constant [{{.*}} x i8] c"{{.+}}directory{{.}}test.c\00" +int x; diff --git a/clang/test/CodeGen/ubsan-sanitize-compilation-dir.cpp b/clang/test/CodeGen/ubsan-sanitize-compilation-dir.cpp new file mode 100644 index 0000000000000..0dcd65a8664aa --- /dev/null +++ b/clang/test/CodeGen/ubsan-sanitize-compilation-dir.cpp @@ -0,0 +1,27 @@ +// Verify that -fsanitize-compilation-dir makes absolute filenames relative +// in UBSan check metadata. +// +// We use -fsanitize=unreachable (one of the checks under -fsanitize=undefined) +// rather than -fsanitize=undefined because the latter is a driver-level umbrella +// flag not accepted by cc1. Any individual sanitizer check exercises the same +// EmitCheckSourceLocation path. + +// RUN: mkdir -p %t.dir/sub +// RUN: cp %s %t.dir/sub/test.c +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-DEFAULT %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -fsanitize-compilation-dir=%t.dir/ %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -fsanitize-compilation-dir=%t.dir %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: cd %t.dir && %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -fsanitize-compilation-dir=. %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s +// RUN: cd %t.dir/sub && %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -fsanitize-compilation-dir=.. %t.dir/sub/test.c -o - | FileCheck -check-prefix=CHECK-STRIPPED %s + +// Verify that a partial prefix match does not strip. +// RUN: mkdir -p %t.directory +// RUN: cp %s %t.directory/test.c +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -fsanitize-compilation-dir=%t.dir %t.directory/test.c -o - | FileCheck -check-prefix=CHECK-NO-FALSE-MATCH %s + +// CHECK-DEFAULT: @{{.*}} = private unnamed_addr constant [{{.*}} x i8] c"{{.+}}test.c\00" +// CHECK-STRIPPED: @{{.*}} = private unnamed_addr constant [{{.*}} x i8] c"sub{{.}}test.c\00" +// CHECK-NO-FALSE-MATCH: @{{.*}} = private unnamed_addr constant [{{.*}} x i8] c"{{.+}}directory{{.}}test.c\00" +void f(void) { + __builtin_unreachable(); +} diff --git a/clang/test/Driver/fsanitize-compilation-dir.c b/clang/test/Driver/fsanitize-compilation-dir.c new file mode 100644 index 0000000000000..6037f55e58d2f --- /dev/null +++ b/clang/test/Driver/fsanitize-compilation-dir.c @@ -0,0 +1,13 @@ +// RUN: %clang -### -fsanitize=address -fsanitize-compilation-dir=/foo %s 2>&1 | FileCheck %s --check-prefix=SANITIZE +// RUN: %clang -### -fsanitize=undefined -fsanitize-compilation-dir=/foo %s 2>&1 | FileCheck %s --check-prefix=SANITIZE +// RUN: %clang -### -fsanitize=address -ffile-compilation-dir=/foo %s 2>&1 | FileCheck %s --check-prefix=FILE +// RUN: %clang -### -fsanitize=undefined -ffile-compilation-dir=/foo %s 2>&1 | FileCheck %s --check-prefix=FILE + +// Verify that -fsanitize-compilation-dir wins over -ffile-compilation-dir when it comes last. +// RUN: %clang -### -fsanitize=address -ffile-compilation-dir=/bar -fsanitize-compilation-dir=/foo %s 2>&1 | FileCheck %s --check-prefix=OVERRIDE +// RUN: %clang -### -fsanitize=address -fsanitize-compilation-dir=/foo -ffile-compilation-dir=/bar %s 2>&1 | FileCheck %s --check-prefix=OVERRIDE-FILE + +// SANITIZE: "-fsanitize-compilation-dir=/foo" +// FILE: "-fsanitize-compilation-dir=/foo" +// OVERRIDE: "-fsanitize-compilation-dir=/foo" +// OVERRIDE-FILE: "-fsanitize-compilation-dir=/bar" diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h index 781b88175f562..aa75976a4c06f 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h @@ -16,6 +16,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/Support/Compiler.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" +#include <string> namespace llvm { class Module; @@ -30,6 +31,7 @@ struct AddressSanitizerOptions { int InstrumentationWithCallsThreshold = 7000; uint32_t MaxInlinePoisoningSize = 64; bool InsertVersionCheck = true; + std::string CompilationDir; }; /// Public interface to the address sanitizer module pass for instrumenting code diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index e75b5ccdf612c..6a985f8923074 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -70,8 +70,10 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/ModRef.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h" @@ -961,7 +963,8 @@ class ModuleAddressSanitizer { bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true, bool UseOdrIndicator = true, AsanDtorKind DestructorKind = AsanDtorKind::Global, - AsanCtorKind ConstructorKind = AsanCtorKind::Global) + AsanCtorKind ConstructorKind = AsanCtorKind::Global, + StringRef CompilationDir = "") : M(M), Inserter(M), CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel), @@ -988,7 +991,8 @@ class ModuleAddressSanitizer { DestructorKind(DestructorKind), ConstructorKind(ClConstructorKind.getNumOccurrences() > 0 ? ClConstructorKind - : ConstructorKind) { + : ConstructorKind), + CompilationDir(CompilationDir) { C = &(M.getContext()); int LongSize = M.getDataLayout().getPointerSizeInBits(); IntptrTy = Type::getIntNTy(*C, LongSize); @@ -1069,6 +1073,7 @@ class ModuleAddressSanitizer { Function *AsanCtorFunction = nullptr; Function *AsanDtorFunction = nullptr; GlobalVariable *ModuleName = nullptr; + std::string CompilationDir; }; // Stack poisoning does not play well with exception handling. @@ -1339,7 +1344,8 @@ PreservedAnalyses AddressSanitizerPass::run(Module &M, ModuleAddressSanitizer ModuleSanitizer( M, Options.InsertVersionCheck, Options.CompileKernel, Options.Recover, - UseGlobalGC, UseOdrIndicator, DestructorKind, ConstructorKind); + UseGlobalGC, UseOdrIndicator, DestructorKind, ConstructorKind, + Options.CompilationDir); bool Modified = false; auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); const StackSafetyGlobalInfo *const SSGI = @@ -2831,8 +2837,26 @@ GlobalVariable *ModuleAddressSanitizer::getOrCreateModuleName() { if (!ModuleName) { // We shouldn't merge same module names, as this string serves as unique // module ID in runtime. + std::string ModuleNameStr = M.getModuleIdentifier(); + + // If a compilation dir is set, make absolute paths relative to it. + if (!CompilationDir.empty()) { + SmallString<256> Path(ModuleNameStr); + if (sys::path::is_absolute(Path)) { + SmallString<256> CompDir(CompilationDir); + if (!sys::path::is_absolute(CompDir)) + sys::fs::make_absolute(CompDir); + sys::path::remove_dots(CompDir, /*remove_dot_dot=*/true); + // Ensure trailing separator so "/foo" doesn't match "/foobar/x.c". + if (!CompDir.empty() && !sys::path::is_separator(CompDir.back())) + CompDir += sys::path::get_separator(); + if (sys::path::replace_path_prefix(Path, CompDir, "")) + ModuleNameStr = std::string(Path); + } + } + ModuleName = - createPrivateGlobalForString(M, M.getModuleIdentifier(), + createPrivateGlobalForString(M, ModuleNameStr, /*AllowMerging*/ false, genName("module")); } return ModuleName; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
