[ubsan] Add -fsanitize-undefined-strip-path-components=N

Summary:
This option allows the user to control how much of the file name is
emitted by UBSan. Tuning this option allows one to save space in the
resulting binary, which is helpful for restricted execution
environments.

With a positive N, UBSan skips the first N path components.
With a negative N, UBSan only keeps the last N path components.

Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D19666

llvm-svn: 269309
This commit is contained in:
Filipe Cabecinhas 2016-05-12 16:51:36 +00:00
parent b61f01d0a5
commit ab731f7e86
8 changed files with 94 additions and 1 deletions

View File

@ -228,6 +228,26 @@ UndefinedBehaviorSanitizer is available on selected platforms starting from LLVM
3.3. The test suite is integrated into the CMake build and can be run with
``check-ubsan`` command.
Additional Configuration
========================
UndefinedBehaviorSanitizer adds static check data for each check unless it is
in trap mode. This check data includes the full file name. The option
``-fsanitize-undefined-strip-path-components=N`` can be used to trim this
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.
Example
-------
For a file called ``/code/library/file.cpp``, here is what would be emitted:
* Default (No flag, or ``-fsanitize-undefined-strip-path-components=0``): ``/code/library/file.cpp``
* ``-fsanitize-undefined-strip-path-components=1``: ``code/library/file.cpp``
* ``-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``
More Information
================

View File

@ -677,6 +677,10 @@ def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disable sanitizer statistics gathering.">;
def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-undefined-strip-path-components=">,
Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
HelpText<"Strip (or keep only, if negative) a given number of path components "
"when emitting check metadata.">;
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,

View File

@ -225,6 +225,10 @@ ENUM_CODEGENOPT(VecLib, VectorLibrary, 1, NoLibrary)
/// The default TLS model to use.
ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
/// Number of path components to strip when emitting checks. (0 == full
/// filename)
VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)
#undef CODEGENOPT
#undef ENUM_CODEGENOPT
#undef VALUE_CODEGENOPT

View File

@ -32,6 +32,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
using namespace clang;
@ -2367,7 +2368,33 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
if (PLoc.isValid()) {
auto FilenameGV = CGM.GetAddrOfConstantCString(PLoc.getFilename(), ".src");
StringRef FilenameString = PLoc.getFilename();
int PathComponentsToStrip =
CGM.getCodeGenOpts().EmitCheckPathComponentsToStrip;
if (PathComponentsToStrip < 0) {
assert(PathComponentsToStrip != INT_MIN);
int PathComponentsToKeep = -PathComponentsToStrip;
auto I = llvm::sys::path::rbegin(FilenameString);
auto E = llvm::sys::path::rend(FilenameString);
while (I != E && --PathComponentsToKeep)
++I;
FilenameString = FilenameString.substr(I - E);
} else if (PathComponentsToStrip > 0) {
auto I = llvm::sys::path::begin(FilenameString);
auto E = llvm::sys::path::end(FilenameString);
while (I != E && PathComponentsToStrip--)
++I;
if (I != E)
FilenameString =
FilenameString.substr(I - llvm::sys::path::begin(FilenameString));
else
FilenameString = llvm::sys::path::filename(FilenameString);
}
auto FilenameGV = CGM.GetAddrOfConstantCString(FilenameString, ".src");
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(
cast<llvm::GlobalVariable>(FilenameGV.getPointer()));
Filename = FilenameGV.getPointer();

View File

@ -5607,6 +5607,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
A->render(Args, CmdArgs);
if (Arg *A = Args.getLastArg(
options::OPT_fsanitize_undefined_strip_path_components_EQ))
A->render(Args, CmdArgs);
// -fdollars-in-identifiers default varies depending on platform and
// language; only pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,

View File

@ -823,6 +823,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.Backchain = Args.hasArg(OPT_mbackchain);
Opts.EmitCheckPathComponentsToStrip = getLastArgIntValue(
Args, OPT_fsanitize_undefined_strip_path_components_EQ, 0, Diags);
return Success;
}

View File

@ -0,0 +1,29 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - | FileCheck %s -check-prefix=REGULAR -check-prefix=CHECK
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=0 | FileCheck %s -check-prefix=REGULAR -check-prefix=CHECK
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=2 | FileCheck %s -check-prefix=REMOVE-FIRST-TWO -check-prefix=CHECK
// Try to strip too much:
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=-99999 | FileCheck %s -check-prefix=REGULAR
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=99999 | FileCheck %s -check-prefix=LAST-ONLY
// Check stripping from the file name
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=-2 | FileCheck %s -check-prefix=LAST-TWO
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fsanitize=unreachable -o - -fsanitize-undefined-strip-path-components=-1 | FileCheck %s -check-prefix=LAST-ONLY
// REGULAR: @[[SRC:[0-9.a-zA-Z_]+]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*test(.|\\5C)CodeGen(.|\\5C)ubsan-strip-path-components\.cpp}}\00", align 1
// First path component: "/" or "$drive_letter:", then a name, or '\5C' on Windows
// REMOVE-FIRST-TWO: @[[STR:[0-9.a-zA-Z_]+]] = private unnamed_addr constant [{{.*}} x i8] c"{{(.:|/)([^\\/]*(/|\\5C))}}[[REST:.*ubsan-strip-path-components\.cpp]]\00", align 1
// REMOVE-FIRST-TWO: @[[SRC:[0-9.a-zA-Z_]+]] = private unnamed_addr constant [{{.*}} x i8] c"[[REST]]\00", align 1
// LAST-TWO: @[[SRC:[0-9.a-zA-Z_]+]] = private unnamed_addr constant [{{.*}} x i8] c"CodeGen{{/|\\5C}}ubsan-strip-path-components.cpp\00", align 1
// LAST-ONLY: @[[SRC:[0-9.a-zA-Z_]+]] = private unnamed_addr constant [{{.*}} x i8] c"ubsan-strip-path-components.cpp\00", align 1
// CHECK: @[[STATIC_DATA:[0-9.a-zA-Z_]+]] = private unnamed_addr global { { [{{.*}} x i8]*, i32, i32 } } { { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+6]], i32 3 } }
void g(const char *);
void f() {
// CHECK-LABEL: @_Z1fv(
g(__FILE__);
// CHECK: call void @__ubsan_handle_builtin_unreachable(i8* bitcast ({ { [{{.*}} x i8]*, i32, i32 } }* @[[STATIC_DATA]] to i8*)) {{.*}}, !nosanitize
__builtin_unreachable();
}

View File

@ -0,0 +1,2 @@
// RUN: %clang %s -### -o %t.o -fsanitize-undefined-strip-path-components=42 2>&1 | FileCheck %s
// CHECK: "-fsanitize-undefined-strip-path-components=42"