Introduce -fsanitize-stats flag.

This is part of a new statistics gathering feature for the sanitizers.
See clang/docs/SanitizerStats.rst for further info and docs.

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

llvm-svn: 257971
This commit is contained in:
Peter Collingbourne 2016-01-16 00:31:22 +00:00
parent f0f5e87083
commit dc13453128
28 changed files with 304 additions and 22 deletions

View File

@ -0,0 +1,62 @@
==============
SanitizerStats
==============
.. contents::
:local:
Introduction
============
The sanitizers support a simple mechanism for gathering profiling statistics
to help understand the overhead associated with sanitizers.
How to build and run
====================
SanitizerStats can currently only be used with :doc:`ControlFlowIntegrity`.
In addition to ``-fsanitize=cfi*``, pass the ``-fsanitize-stats`` flag.
This will cause the program to count the number of times that each control
flow integrity check in the program fires.
At run time, set the ``SANITIZER_STATS_PATH`` environment variable to direct
statistics output to a file. The file will be written on process exit.
The following substitutions will be applied to the environment variable:
- ``%b`` -- The executable basename.
- ``%p`` -- The process ID.
You can also send the ``SIGUSR2`` signal to a process to make it write
sanitizer statistics immediately.
The ``sanstats`` program can be used to dump statistics. It takes as a
command line argument the path to a statistics file produced by a program
compiled with ``-fsanitize-stats``.
The output of ``sanstats`` is in four columns, separated by spaces. The first
column is the file and line number of the call site. The second column is
the function name. The third column is the type of statistic gathered (in
this case, the type of control flow integrity check). The fourth column is
the call count.
Example:
.. code-block:: console
$ cat -n vcall.cc
1 struct A {
2 virtual void f() {}
3 };
4
5 __attribute__((noinline)) void g(A *a) {
6 a->f();
7 }
8
9 int main() {
10 A a;
11 g(&a);
12 }
$ clang++ -fsanitize=cfi -flto -fuse-ld=gold vcall.cc -fsanitize-stats -g
$ SANITIZER_STATS_PATH=a.stats ./a.out
$ sanstats a.stats
vcall.cc:6 _Z1gP1A cfi-vcall 1

View File

@ -1038,6 +1038,11 @@ are listed below.
Enable simple code coverage in addition to certain sanitizers.
See :doc:`SanitizerCoverage` for more details.
**-f[no-]sanitize-stats**
Enable simple statistics gathering for the enabled sanitizers.
See :doc:`SanitizerStats` for more details.
.. option:: -fsanitize-undefined-trap-on-error
Deprecated alias for ``-fsanitize-trap=undefined``.

View File

@ -28,6 +28,7 @@ Using Clang as a Compiler
DataFlowSanitizer
LeakSanitizer
SanitizerCoverage
SanitizerStats
SanitizerSpecialCaseList
ControlFlowIntegrity
SafeStack

View File

@ -94,9 +94,10 @@ public:
/// The default implementation passes it to HandleTopLevelDecl.
virtual void HandleImplicitImportDecl(ImportDecl *D);
/// \brief Handle a pragma that appends to Linker Options. Currently this
/// only exists to support Microsoft's #pragma comment(linker, "/foo").
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
/// \brief Handle a pragma or command line flag that appends to Linker
/// Options. This exists to support Microsoft's
/// #pragma comment(linker, "/foo") and the frontend flag --linker-option=.
virtual void HandleLinkerOption(llvm::StringRef Opts) {}
/// \brief Handle a pragma that emits a mismatch identifier and value to the
/// object file for the linker to work with. Currently, this only exists to

View File

@ -252,6 +252,8 @@ def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">,
HelpText<"Run the BB vectorization passes">;
def dependent_lib : Joined<["--"], "dependent-lib=">,
HelpText<"Add dependent library">;
def linker_option : Joined<["--"], "linker-option=">,
HelpText<"Add linker option">;
def fsanitize_coverage_type : Joined<["-"], "fsanitize-coverage-type=">,
HelpText<"Sanitizer coverage type">;
def fsanitize_coverage_indirect_calls

View File

@ -644,6 +644,12 @@ def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Enable sanitizer statistics gathering.">;
def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disable sanitizer statistics gathering.">;
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,

View File

@ -36,6 +36,7 @@ class SanitizerArgs {
bool AsanSharedRuntime = false;
bool LinkCXXRuntimes = false;
bool NeedPIE = false;
bool Stats = false;
public:
/// Parses the sanitizer arguments from an argument list.
@ -56,6 +57,7 @@ class SanitizerArgs {
}
bool needsCfiRt() const;
bool needsCfiDiagRt() const;
bool needsStatsRt() const { return Stats; }
bool requiresPIE() const;
bool needsUnwindTables() const;

View File

@ -134,6 +134,7 @@ CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
///< in sanitizer coverage.
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.

View File

@ -164,6 +164,9 @@ public:
/// A list of dependent libraries.
std::vector<std::string> DependentLibraries;
/// A list of linker options to embed in the object file.
std::vector<std::string> LinkerOptions;
/// Name of the profile file to use as output for -fprofile-instr-generate
/// and -fprofile-generate.
std::string InstrProfileOutput;

View File

@ -44,7 +44,7 @@ public:
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
void HandleImplicitImportDecl(ImportDecl *D) override;
void HandleLinkerOptionPragma(llvm::StringRef Opts) override;
void HandleLinkerOption(llvm::StringRef Opts) override;
void HandleDetectMismatch(llvm::StringRef Name,
llvm::StringRef Value) override;
void HandleDependentLibrary(llvm::StringRef Lib) override;

View File

@ -26,6 +26,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
using namespace clang;
using namespace CodeGen;
@ -2551,6 +2552,22 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
return;
SanitizerScope SanScope(this);
llvm::SanitizerStatKind SSK;
switch (TCK) {
case CFITCK_VCall:
SSK = llvm::SanStat_CFI_VCall;
break;
case CFITCK_NVCall:
SSK = llvm::SanStat_CFI_NVCall;
break;
case CFITCK_DerivedCast:
SSK = llvm::SanStat_CFI_DerivedCast;
break;
case CFITCK_UnrelatedCast:
SSK = llvm::SanStat_CFI_UnrelatedCast;
break;
}
EmitSanitizerStatReport(SSK);
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));

View File

@ -32,6 +32,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
using namespace clang;
using namespace CodeGen;
@ -3852,6 +3853,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
if (SanOpts.has(SanitizerKind::CFIICall) &&
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
SanitizerScope SanScope(this);
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);

View File

@ -214,8 +214,8 @@ namespace clang {
Gen->HandleVTable(RD);
}
void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
Gen->HandleLinkerOptionPragma(Opts);
void HandleLinkerOption(llvm::StringRef Opts) override {
Gen->HandleLinkerOption(Opts);
}
void HandleDetectMismatch(llvm::StringRef Name,

View File

@ -1956,3 +1956,12 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
<< FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
}
}
void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
if (!CGM.getCodeGenOpts().SanitizeStats)
return;
llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());
CGM.getSanStats().create(IRB, SSK);
}

View File

@ -36,6 +36,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
namespace llvm {
class BasicBlock;
@ -3187,6 +3188,8 @@ public:
Address EmitPointerWithAlignment(const Expr *Addr,
AlignmentSource *Source = nullptr);
void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
private:
QualType getVarArgType(const Expr *Arg);

View File

@ -392,6 +392,8 @@ void CodeGenModule::Release() {
if (CoverageMapping)
CoverageMapping->emit();
emitLLVMUsed();
if (SanStats)
SanStats->finish();
if (CodeGenOpts.Autolink &&
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
@ -4066,3 +4068,10 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Target.getTargetOpts().Features);
}
}
llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
if (!SanStats)
SanStats = llvm::make_unique<llvm::SanitizerStatReport>(&getModule());
return *SanStats;
}

View File

@ -33,6 +33,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
namespace llvm {
class Module;
@ -289,6 +290,7 @@ private:
llvm::MDNode *NoObjCARCExceptionsMetadata;
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
InstrProfStats PGOStats;
std::unique_ptr<llvm::SanitizerStatReport> SanStats;
// A set of references that have only been seen via a weakref so far. This is
// used to remove the weak of the reference if we ever see a direct reference
@ -1129,6 +1131,8 @@ public:
/// \breif Get the declaration of std::terminate for the platform.
llvm::Constant *getTerminateFn();
llvm::SanitizerStatReport &getSanStats();
private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,

View File

@ -103,8 +103,10 @@ namespace {
PreprocessorOpts, CodeGenOpts,
*M, Diags, CoverageInfo));
for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; ++i)
HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
for (auto &&Lib : CodeGenOpts.DependentLibraries)
HandleDependentLibrary(Lib);
for (auto &&Opt : CodeGenOpts.LinkerOptions)
HandleLinkerOption(Opt);
}
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
@ -222,7 +224,7 @@ namespace {
Builder->EmitVTable(RD);
}
void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
void HandleLinkerOption(llvm::StringRef Opts) override {
Builder->AppendLinkerOptions(Opts);
}

View File

@ -431,6 +431,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
NeedPIE |= CfiCrossDso;
}
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
options::OPT_fno_sanitize_stats, false);
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
// enabled sanitizers.
if (AllAddedKinds & SupportsCoverage) {
@ -548,6 +551,20 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
return Res;
}
static void addIncludeLinkerOption(const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
StringRef SymbolName) {
SmallString<64> LinkerOptionFlag;
LinkerOptionFlag = "--linker-option=/include:";
if (TC.getTriple().getArch() == llvm::Triple::x86) {
// Win32 mangles C function names with a '_' prefix.
LinkerOptionFlag += '_';
}
LinkerOptionFlag += SymbolName;
CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
}
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
types::ID InputType) const {
@ -584,6 +601,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (CfiCrossDso)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
if (Stats)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats"));
if (AsanFieldPadding)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
llvm::utostr(AsanFieldPadding)));
@ -619,6 +639,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
}
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
TC.getCompilerRT(Args, "stats_client")));
// The main executable must export the stats runtime.
// FIXME: Only exporting from the main executable (e.g. based on whether the
// translation unit defines main()) would save a little space, but having
// multiple copies of the runtime shouldn't hurt.
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
TC.getCompilerRT(Args, "stats")));
addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
}
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,

View File

@ -413,6 +413,13 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
if (Sanitize.needsTsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
if (Sanitize.needsStatsRt()) {
StringRef OS = isTargetMacOS() ? "osx" : "iossim";
AddLinkRuntimeLib(Args, CmdArgs,
(Twine("libclang_rt.stats_client_") + OS + ".a").str(),
/*AlwaysLink=*/true);
AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
}
// Otherwise link libSystem, then the dynamic runtime library, and finally any
// target specific static runtime library.

View File

@ -2773,12 +2773,12 @@ static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, StringRef Sanitizer,
bool IsShared) {
// Static runtimes must be forced into executable, so we wrap them in
bool IsShared, bool IsWhole) {
// Wrap any static runtimes that must be forced into executable in
// whole-archive.
if (!IsShared) CmdArgs.push_back("-whole-archive");
if (IsWhole) CmdArgs.push_back("-whole-archive");
CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared));
if (!IsShared) CmdArgs.push_back("-no-whole-archive");
if (IsWhole) CmdArgs.push_back("-no-whole-archive");
}
// Tries to use a file with the list of dynamic symbols that need to be exported
@ -2811,12 +2811,17 @@ static void
collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
SmallVectorImpl<StringRef> &SharedRuntimes,
SmallVectorImpl<StringRef> &StaticRuntimes,
SmallVectorImpl<StringRef> &HelperStaticRuntimes) {
SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
SmallVectorImpl<StringRef> &HelperStaticRuntimes,
SmallVectorImpl<StringRef> &RequiredSymbols) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
// Collect shared runtimes.
if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
SharedRuntimes.push_back("asan");
}
// The stats_client library is also statically linked into DSOs.
if (SanArgs.needsStatsRt())
StaticRuntimes.push_back("stats_client");
// Collect static runtimes.
if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) {
@ -2857,6 +2862,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("cfi");
if (SanArgs.needsCfiDiagRt())
StaticRuntimes.push_back("cfi_diag");
if (SanArgs.needsStatsRt()) {
NonWholeStaticRuntimes.push_back("stats");
RequiredSymbols.push_back("__sanitizer_stats_register");
}
}
// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
@ -2864,18 +2873,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
HelperStaticRuntimes;
NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
HelperStaticRuntimes);
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
for (auto RT : SharedRuntimes)
addSanitizerRuntime(TC, Args, CmdArgs, RT, true);
addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
for (auto RT : HelperStaticRuntimes)
addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
bool AddExportDynamic = false;
for (auto RT : StaticRuntimes) {
addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
}
for (auto RT : NonWholeStaticRuntimes) {
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
}
for (auto S : RequiredSymbols) {
CmdArgs.push_back("-u");
CmdArgs.push_back(Args.MakeArgString(S));
}
// If there is a static runtime with no dynamic list, force all the symbols
// to be dynamic to be sure we export sanitizer interface functions.
if (AddExportDynamic)

View File

@ -623,6 +623,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeMemoryUseAfterDtor =
Args.hasArg(OPT_fsanitize_memory_use_after_dtor);
Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@ -697,6 +698,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
Opts.LinkerOptions = Args.getAllArgValues(OPT_linker_option);
bool NeedLocTracking = false;
if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {

View File

@ -317,9 +317,9 @@ void MultiplexConsumer::HandleImplicitImportDecl(ImportDecl *D) {
Consumer->HandleImplicitImportDecl(D);
}
void MultiplexConsumer::HandleLinkerOptionPragma(llvm::StringRef Opts) {
void MultiplexConsumer::HandleLinkerOption(llvm::StringRef Opts) {
for (auto &Consumer : Consumers)
Consumer->HandleLinkerOptionPragma(Opts);
Consumer->HandleLinkerOption(Opts);
}
void MultiplexConsumer::HandleDetectMismatch(llvm::StringRef Name, llvm::StringRef Value) {

View File

@ -275,7 +275,7 @@ void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg) {
case PCK_Unknown:
llvm_unreachable("unexpected pragma comment kind");
case PCK_Linker:
Consumer.HandleLinkerOptionPragma(Arg);
Consumer.HandleLinkerOption(Arg);
return;
case PCK_Lib:
Consumer.HandleDependentLibrary(Arg);

View File

@ -0,0 +1,8 @@
// RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
// CHECK: !llvm.module.flags = !{{{.*}}}
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
// CHECK: ![[msvcrt]] = !{!"/include:foo"}
int f();

View File

@ -0,0 +1,50 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck --check-prefix=CHECK %s
// CHECK: [[STATS:@[^ ]*]] = internal global { i8*, i32, [5 x [2 x i8*]] } { i8* null, i32 5, [5 x [2 x i8*]]
// CHECK: {{\[\[}}2 x i8*] zeroinitializer,
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 2305843009213693952 to i8*)],
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 4611686018427387904 to i8*)],
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 6917529027641081856 to i8*)],
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 -9223372036854775808 to i8*)]] }
// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* [[CTOR:@[^ ]*]], i8* null }]
struct A {
virtual void vf();
void nvf();
};
struct B : A {};
// CHECK: @vcall
extern "C" void vcall(A *a) {
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 0
a->vf();
}
// CHECK: @nvcall
extern "C" void nvcall(A *a) {
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 1
a->nvf();
}
// CHECK: @dcast
extern "C" void dcast(A *a) {
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 2
static_cast<B *>(a);
}
// CHECK: @ucast
extern "C" void ucast(void *a) {
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 3
reinterpret_cast<A *>(a);
}
// CHECK: @icall
extern "C" void icall(void (*p)()) {
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 4
p();
}
// CHECK: define internal void [[CTOR]]()
// CHECK-NEXT: call void @__sanitizer_stat_init(i8* bitcast ({ i8*, i32, [5 x [2 x i8*]] }* [[STATS]] to i8*))
// CHECK-NEXT: ret void

View File

@ -272,6 +272,9 @@
// CHECK-CFI-NO-CROSS-DSO: -emit-llvm-bc
// CHECK-CFI-NO-CROSS-DSO-NOT: -fsanitize-cfi-cross-dso
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-stats -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-STATS
// CHECK-CFI-STATS: -fsanitize-stats
// RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
// RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
// RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL

View File

@ -345,6 +345,39 @@
// CHECK-SAFESTACK-LINUX: "-lpthread"
// CHECK-SAFESTACK-LINUX: "-ldl"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-LINUX %s
// CHECK-CFI-STATS-LINUX: "{{.*}}ld{{(.exe)?}}"
// CHECK-CFI-STATS-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.stats_client-x86_64.a" "-no-whole-archive"
// CHECK-CFI-STATS-LINUX-NOT: "-whole-archive"
// CHECK-CFI-STATS-LINUX: "{{[^"]*}}libclang_rt.stats-x86_64.a"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-apple-darwin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-DARWIN %s
// CHECK-CFI-STATS-DARWIN: "{{.*}}ld{{(.exe)?}}"
// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_client_osx.a"
// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_osx_dynamic.dylib"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-pc-windows \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN64 %s
// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats_client-x86_64.lib"
// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats-x86_64.lib"
// CHECK-CFI-STATS-WIN64: "--linker-option=/include:__sanitizer_stats_register"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
// RUN: -target i686-pc-windows \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN32 %s
// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats_client-i386.lib"
// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats-i386.lib"
// CHECK-CFI-STATS-WIN32: "--linker-option=/include:___sanitizer_stats_register"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_android_tree \