forked from OSchip/llvm-project
Use-after-return sanitizer binary metadata
Currently per-function metadata consists of: (start-pc, size, features) This adds a new UAR feature and if it's set an additional element: (start-pc, size, features, stack-args-size) Reviewed By: melver Differential Revision: https://reviews.llvm.org/D136078
This commit is contained in:
parent
dca1a3f29e
commit
a1255dc467
|
@ -288,6 +288,8 @@ CODEGENOPT(SanitizeCoverageTraceLoads, 1, 0) ///< Enable tracing of loads.
|
|||
CODEGENOPT(SanitizeCoverageTraceStores, 1, 0) ///< Enable tracing of stores.
|
||||
CODEGENOPT(SanitizeBinaryMetadataCovered, 1, 0) ///< Emit PCs for covered functions.
|
||||
CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0) ///< Emit PCs for atomic operations.
|
||||
CODEGENOPT(SanitizeBinaryMetadataUAR, 1, 0) ///< Emit PCs for start of functions
|
||||
///< that are subject for use-after-return checking.
|
||||
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
|
||||
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
|
||||
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
|
||||
|
|
|
@ -497,7 +497,8 @@ public:
|
|||
|
||||
// Check if any one of SanitizeBinaryMetadata* is enabled.
|
||||
bool hasSanitizeBinaryMetadata() const {
|
||||
return SanitizeBinaryMetadataCovered || SanitizeBinaryMetadataAtomics;
|
||||
return SanitizeBinaryMetadataCovered || SanitizeBinaryMetadataAtomics ||
|
||||
SanitizeBinaryMetadataUAR;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5575,6 +5575,10 @@ def fexperimental_sanitize_metadata_EQ_atomics
|
|||
: Flag<["-"], "fexperimental-sanitize-metadata=atomics">,
|
||||
HelpText<"Emit PCs for atomic operations used by binary analysis sanitizers">,
|
||||
MarshallingInfoFlag<CodeGenOpts<"SanitizeBinaryMetadataAtomics">>;
|
||||
def fexperimental_sanitize_metadata_EQ_uar
|
||||
: Flag<["-"], "fexperimental-sanitize-metadata=uar">,
|
||||
HelpText<"Emit PCs for start of functions that are subject for use-after-return checking.">,
|
||||
MarshallingInfoFlag<CodeGenOpts<"SanitizeBinaryMetadataUAR">>;
|
||||
def fpatchable_function_entry_offset_EQ
|
||||
: Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"<M>">,
|
||||
HelpText<"Generate M NOPs before function entry">,
|
||||
|
|
|
@ -234,6 +234,7 @@ getSanitizerBinaryMetadataOptions(const CodeGenOptions &CGOpts) {
|
|||
SanitizerBinaryMetadataOptions Opts;
|
||||
Opts.Covered = CGOpts.SanitizeBinaryMetadataCovered;
|
||||
Opts.Atomics = CGOpts.SanitizeBinaryMetadataAtomics;
|
||||
Opts.UAR = CGOpts.SanitizeBinaryMetadataUAR;
|
||||
return Opts;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ enum CoverageFeature {
|
|||
enum BinaryMetadataFeature {
|
||||
BinaryMetadataCovered = 1 << 0,
|
||||
BinaryMetadataAtomics = 1 << 1,
|
||||
BinaryMetadataUAR = 1 << 2,
|
||||
};
|
||||
|
||||
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
|
||||
|
@ -1133,7 +1134,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
|||
// flags. Does not depend on any other sanitizers.
|
||||
const std::pair<int, std::string> BinaryMetadataFlags[] = {
|
||||
std::make_pair(BinaryMetadataCovered, "covered"),
|
||||
std::make_pair(BinaryMetadataAtomics, "atomics")};
|
||||
std::make_pair(BinaryMetadataAtomics, "atomics"),
|
||||
std::make_pair(BinaryMetadataUAR, "uar")};
|
||||
for (const auto &F : BinaryMetadataFlags) {
|
||||
if (BinaryMetadataFeatures & F.first)
|
||||
CmdArgs.push_back(
|
||||
|
@ -1399,6 +1401,7 @@ int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
|
|||
int F = llvm::StringSwitch<int>(Value)
|
||||
.Case("covered", BinaryMetadataCovered)
|
||||
.Case("atomics", BinaryMetadataAtomics)
|
||||
.Case("uar", BinaryMetadataUAR)
|
||||
.Case("all", ~0)
|
||||
.Default(0);
|
||||
if (F == 0 && DiagnoseErrors)
|
||||
|
|
|
@ -926,6 +926,7 @@ Error CodeGenPassBuilder<Derived>::addMachinePasses(
|
|||
|
||||
addPass(StackMapLivenessPass());
|
||||
addPass(LiveDebugValuesPass());
|
||||
addPass(MachineSanitizerBinaryMetadata());
|
||||
|
||||
if (TM.Options.EnableMachineOutliner && getOptLevel() != CodeGenOpt::None &&
|
||||
Opt.EnableMachineOutliner != RunOutliner::NeverOutline) {
|
||||
|
|
|
@ -202,4 +202,5 @@ DUMMY_MACHINE_FUNCTION_PASS("instruction-select", InstructionSelectPass, ())
|
|||
DUMMY_MACHINE_FUNCTION_PASS("reset-machine-function", ResetMachineFunctionPass, ())
|
||||
DUMMY_MACHINE_FUNCTION_PASS("machineverifier", MachineVerifierPass, ())
|
||||
DUMMY_MACHINE_FUNCTION_PASS("print-machine-cycles", MachineCycleInfoPrinterPass, ())
|
||||
DUMMY_MACHINE_FUNCTION_PASS("machine-sanmd", MachineSanitizerBinaryMetadata, ())
|
||||
#undef DUMMY_MACHINE_FUNCTION_PASS
|
||||
|
|
|
@ -409,6 +409,10 @@ namespace llvm {
|
|||
/// the intrinsic for later emission to the StackMap.
|
||||
extern char &StackMapLivenessID;
|
||||
|
||||
// MachineSanitizerBinaryMetadata - appends/finalizes sanitizer binary
|
||||
// metadata after llvm SanitizerBinaryMetadata pass.
|
||||
extern char &MachineSanitizerBinaryMetadataID;
|
||||
|
||||
/// RemoveRedundantDebugValues pass.
|
||||
extern char &RemoveRedundantDebugValuesID;
|
||||
|
||||
|
|
|
@ -285,6 +285,7 @@ void initializeMachineOutlinerPass(PassRegistry&);
|
|||
void initializeMachinePipelinerPass(PassRegistry&);
|
||||
void initializeMachinePostDominatorTreePass(PassRegistry&);
|
||||
void initializeMachineRegionInfoPassPass(PassRegistry&);
|
||||
void initializeMachineSanitizerBinaryMetadataPass(PassRegistry &);
|
||||
void initializeMachineSchedulerPass(PassRegistry&);
|
||||
void initializeMachineSinkingPass(PassRegistry&);
|
||||
void initializeMachineTraceMetricsPass(PassRegistry&);
|
||||
|
|
|
@ -150,13 +150,6 @@ struct SanitizerCoverageOptions {
|
|||
SanitizerCoverageOptions() = default;
|
||||
};
|
||||
|
||||
/// Options for SanitizerBinaryMetadata.
|
||||
struct SanitizerBinaryMetadataOptions {
|
||||
bool Covered = false;
|
||||
bool Atomics = false;
|
||||
SanitizerBinaryMetadataOptions() = default;
|
||||
};
|
||||
|
||||
/// Calculate what to divide by to scale counts.
|
||||
///
|
||||
/// Given the maximum count, calculate a divisor that will scale all the
|
||||
|
|
|
@ -19,6 +19,27 @@
|
|||
|
||||
namespace llvm {
|
||||
|
||||
struct SanitizerBinaryMetadataOptions {
|
||||
bool Covered = false;
|
||||
bool Atomics = false;
|
||||
bool UAR = false;
|
||||
SanitizerBinaryMetadataOptions() = default;
|
||||
};
|
||||
|
||||
inline constexpr int kSanitizerBinaryMetadataAtomicsBit = 0;
|
||||
inline constexpr int kSanitizerBinaryMetadataUARBit = 1;
|
||||
|
||||
inline constexpr uint32_t kSanitizerBinaryMetadataNone = 0;
|
||||
inline constexpr uint32_t kSanitizerBinaryMetadataAtomics =
|
||||
1 << kSanitizerBinaryMetadataAtomicsBit;
|
||||
inline constexpr uint32_t kSanitizerBinaryMetadataUAR =
|
||||
1 << kSanitizerBinaryMetadataUARBit;
|
||||
|
||||
inline constexpr char kSanitizerBinaryMetadataCoveredSection[] =
|
||||
"sanmd_covered";
|
||||
inline constexpr char kSanitizerBinaryMetadataAtomicsSection[] =
|
||||
"sanmd_atomics";
|
||||
|
||||
/// Public interface to the SanitizerBinaryMetadata module pass for emitting
|
||||
/// metadata for binary analysis sanitizers.
|
||||
//
|
||||
|
|
|
@ -196,6 +196,7 @@ add_llvm_component_library(LLVMCodeGen
|
|||
RegisterBankInfo.cpp
|
||||
SafeStack.cpp
|
||||
SafeStackLayout.cpp
|
||||
SanitizerBinaryMetadata.cpp
|
||||
ScheduleDAG.cpp
|
||||
ScheduleDAGInstrs.cpp
|
||||
ScheduleDAGPrinter.cpp
|
||||
|
|
|
@ -83,6 +83,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
|||
initializeMachineOptimizationRemarkEmitterPassPass(Registry);
|
||||
initializeMachineOutlinerPass(Registry);
|
||||
initializeMachinePipelinerPass(Registry);
|
||||
initializeMachineSanitizerBinaryMetadataPass(Registry);
|
||||
initializeModuloScheduleTestPass(Registry);
|
||||
initializeMachinePostDominatorTreePass(Registry);
|
||||
initializeMachineRegionInfoPassPass(Registry);
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
//===- SanitizerBinaryMetadata.cpp
|
||||
//----------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of SanitizerBinaryMetadata.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
class MachineSanitizerBinaryMetadata : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
MachineSanitizerBinaryMetadata();
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
};
|
||||
|
||||
INITIALIZE_PASS(MachineSanitizerBinaryMetadata, "machine-sanmd",
|
||||
"Machine Sanitizer Binary Metadata", false, false)
|
||||
|
||||
char MachineSanitizerBinaryMetadata::ID = 0;
|
||||
char &llvm::MachineSanitizerBinaryMetadataID =
|
||||
MachineSanitizerBinaryMetadata::ID;
|
||||
|
||||
MachineSanitizerBinaryMetadata::MachineSanitizerBinaryMetadata()
|
||||
: MachineFunctionPass(ID) {
|
||||
initializeMachineSanitizerBinaryMetadataPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool MachineSanitizerBinaryMetadata::runOnMachineFunction(MachineFunction &MF) {
|
||||
MDNode *MD = MF.getFunction().getMetadata(LLVMContext::MD_pcsections);
|
||||
if (!MD)
|
||||
return false;
|
||||
const auto &Section = *cast<MDString>(MD->getOperand(0));
|
||||
if (!Section.getString().equals(kSanitizerBinaryMetadataCoveredSection))
|
||||
return false;
|
||||
auto &AuxMDs = *cast<MDTuple>(MD->getOperand(1));
|
||||
// Assume it currently only has features.
|
||||
assert(AuxMDs.size() == 1);
|
||||
auto *Features = cast<ConstantAsMetadata>(AuxMDs.getOperand(0))->getValue();
|
||||
if (!Features->getUniqueInteger()[kSanitizerBinaryMetadataUARBit])
|
||||
return false;
|
||||
// Calculate size of stack args for the function.
|
||||
int64_t Size = 0;
|
||||
uint64_t Align = 0;
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
for (int i = -1; i >= (int)-MFI.getNumFixedObjects(); --i) {
|
||||
Size = std::max(Size, MFI.getObjectOffset(i) + MFI.getObjectSize(i));
|
||||
Align = std::max(Align, MFI.getObjectAlign(i).value());
|
||||
}
|
||||
Size = (Size + Align - 1) & ~(Align - 1);
|
||||
auto &F = MF.getFunction();
|
||||
IRBuilder<> IRB(F.getContext());
|
||||
MDBuilder MDB(F.getContext());
|
||||
// Keep the features and append size of stack args to the metadata.
|
||||
const auto *NewMD = MDB.createPCSections(
|
||||
{{Section.getString(), {Features, IRB.getInt32(Size)}}});
|
||||
MD->replaceOperandWith(1, NewMD->getOperand(1));
|
||||
return false;
|
||||
}
|
|
@ -1269,6 +1269,7 @@ void TargetPassConfig::addMachinePasses() {
|
|||
|
||||
addPass(&StackMapLivenessID);
|
||||
addPass(&LiveDebugValuesID);
|
||||
addPass(&MachineSanitizerBinaryMetadataID);
|
||||
|
||||
if (TM->Options.EnableMachineOutliner && getOptLevel() != CodeGenOpt::None &&
|
||||
EnableMachineOutliner != RunOutliner::NeverOutline) {
|
||||
|
|
|
@ -67,14 +67,16 @@ public:
|
|||
private:
|
||||
// Forbid construction elsewhere.
|
||||
explicit constexpr MetadataInfo(StringRef FunctionPrefix,
|
||||
StringRef SectionSuffix, int Feature)
|
||||
StringRef SectionSuffix, uint32_t Feature)
|
||||
: FunctionPrefix(FunctionPrefix), SectionSuffix(SectionSuffix),
|
||||
FeatureMask(Feature != -1 ? (1u << Feature) : 0) {}
|
||||
FeatureMask(Feature) {}
|
||||
};
|
||||
const MetadataInfo MetadataInfo::Covered{"__sanitizer_metadata_covered",
|
||||
"sanmd_covered", -1};
|
||||
kSanitizerBinaryMetadataCoveredSection,
|
||||
kSanitizerBinaryMetadataNone};
|
||||
const MetadataInfo MetadataInfo::Atomics{"__sanitizer_metadata_atomics",
|
||||
"sanmd_atomics", 0};
|
||||
kSanitizerBinaryMetadataAtomicsSection,
|
||||
kSanitizerBinaryMetadataAtomics};
|
||||
|
||||
// The only instances of MetadataInfo are the constants above, so a set of
|
||||
// them may simply store pointers to them. To deterministically generate code,
|
||||
|
@ -89,11 +91,16 @@ cl::opt<bool> ClEmitCovered("sanitizer-metadata-covered",
|
|||
cl::opt<bool> ClEmitAtomics("sanitizer-metadata-atomics",
|
||||
cl::desc("Emit PCs for atomic operations."),
|
||||
cl::Hidden, cl::init(false));
|
||||
cl::opt<bool> ClEmitUAR("sanitizer-metadata-uar",
|
||||
cl::desc("Emit PCs for start of functions that are "
|
||||
"subject for use-after-return checking"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
//===--- Statistics -------------------------------------------------------===//
|
||||
|
||||
STATISTIC(NumMetadataCovered, "Metadata attached to covered functions");
|
||||
STATISTIC(NumMetadataAtomics, "Metadata attached to atomics");
|
||||
STATISTIC(NumMetadataUAR, "Metadata attached to UAR functions");
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -102,6 +109,7 @@ SanitizerBinaryMetadataOptions &&
|
|||
transformOptionsFromCl(SanitizerBinaryMetadataOptions &&Opts) {
|
||||
Opts.Covered |= ClEmitCovered;
|
||||
Opts.Atomics |= ClEmitAtomics;
|
||||
Opts.UAR |= ClEmitUAR;
|
||||
return std::move(Opts);
|
||||
}
|
||||
|
||||
|
@ -142,7 +150,8 @@ private:
|
|||
// function with memory operations (atomic or not) requires covered metadata
|
||||
// to determine if a memory operation is atomic or not in modules compiled
|
||||
// with SanitizerBinaryMetadata.
|
||||
bool runOn(Instruction &I, MetadataInfoSet &MIS, MDBuilder &MDB);
|
||||
bool runOn(Instruction &I, MetadataInfoSet &MIS, MDBuilder &MDB,
|
||||
uint32_t &FeatureMask);
|
||||
|
||||
// Get start/end section marker pointer.
|
||||
GlobalVariable *getSectionMarker(const Twine &MarkerName, Type *Ty);
|
||||
|
@ -232,36 +241,58 @@ void SanitizerBinaryMetadata::runOn(Function &F, MetadataInfoSet &MIS) {
|
|||
|
||||
// The metadata features enabled for this function, stored along covered
|
||||
// metadata (if enabled).
|
||||
uint32_t PerInstrFeatureMask = getEnabledPerInstructionFeature();
|
||||
uint32_t FeatureMask = getEnabledPerInstructionFeature();
|
||||
// Don't emit unnecessary covered metadata for all functions to save space.
|
||||
bool RequiresCovered = false;
|
||||
if (PerInstrFeatureMask) {
|
||||
// We can only understand if we need to set UAR feature after looking
|
||||
// at the instructions. So we need to check instructions even if FeatureMask
|
||||
// is empty.
|
||||
if (FeatureMask || Options.UAR) {
|
||||
for (BasicBlock &BB : F)
|
||||
for (Instruction &I : BB)
|
||||
RequiresCovered |= runOn(I, MIS, MDB);
|
||||
RequiresCovered |= runOn(I, MIS, MDB, FeatureMask);
|
||||
}
|
||||
|
||||
if (F.isVarArg())
|
||||
FeatureMask &= ~kSanitizerBinaryMetadataUAR;
|
||||
if (FeatureMask & kSanitizerBinaryMetadataUAR)
|
||||
NumMetadataUAR++;
|
||||
|
||||
// Covered metadata is always emitted if explicitly requested, otherwise only
|
||||
// if some other metadata requires it to unambiguously interpret it for
|
||||
// modules compiled with SanitizerBinaryMetadata.
|
||||
if (Options.Covered || RequiresCovered) {
|
||||
if (Options.Covered || (FeatureMask && RequiresCovered)) {
|
||||
NumMetadataCovered++;
|
||||
const auto *MI = &MetadataInfo::Covered;
|
||||
MIS.insert(MI);
|
||||
const StringRef Section = getSectionName(MI->SectionSuffix);
|
||||
// The feature mask will be placed after the size (32 bit) of the function,
|
||||
// so in total one covered entry will use `sizeof(void*) + 4 + 4`.
|
||||
Constant *CFM = IRB.getInt32(PerInstrFeatureMask);
|
||||
Constant *CFM = IRB.getInt32(FeatureMask);
|
||||
F.setMetadata(LLVMContext::MD_pcsections,
|
||||
MDB.createPCSections({{Section, {CFM}}}));
|
||||
}
|
||||
}
|
||||
|
||||
bool SanitizerBinaryMetadata::runOn(Instruction &I, MetadataInfoSet &MIS,
|
||||
MDBuilder &MDB) {
|
||||
MDBuilder &MDB, uint32_t &FeatureMask) {
|
||||
SmallVector<const MetadataInfo *, 1> InstMetadata;
|
||||
bool RequiresCovered = false;
|
||||
|
||||
if (Options.UAR) {
|
||||
for (unsigned i = 0; i < I.getNumOperands(); ++i) {
|
||||
const Value *V = I.getOperand(i);
|
||||
// TODO(dvyukov): check if V is an address of alloca/function arg.
|
||||
// See isSafeAndProfitableToSinkLoad for addr-taken allocas
|
||||
// and DeadArgumentEliminationPass::removeDeadStuffFromFunction
|
||||
// for iteration over function args.
|
||||
if (V) {
|
||||
RequiresCovered = true;
|
||||
FeatureMask |= kSanitizerBinaryMetadataUAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.Atomics && I.mayReadOrWriteMemory()) {
|
||||
auto SSID = getAtomicSyncScopeID(&I);
|
||||
if (SSID.has_value() && SSID.value() != SyncScope::SingleThread) {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
printf("main\n");
|
||||
}
|
||||
|
||||
typedef unsigned long uptr;
|
||||
|
||||
#define FN(X) if (pc == reinterpret_cast<uptr>(X)) return #X
|
||||
|
||||
const char* symbolize(uptr pc) {
|
||||
FUNCTIONS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T consume(const char*& pos, const char* end) {
|
||||
T v = *reinterpret_cast<const T*>(pos);
|
||||
pos += sizeof(T);
|
||||
assert(pos <= end);
|
||||
return v;
|
||||
}
|
||||
|
||||
uint32_t meta_version;
|
||||
const char* meta_start;
|
||||
const char* meta_end;
|
||||
|
||||
extern "C" {
|
||||
void __sanitizer_metadata_covered_add(uint32_t version, const char* start, const char* end) {
|
||||
printf("metadata add version %u\n", version);
|
||||
for (const char* pos = start; pos < end;) {
|
||||
const uptr base = reinterpret_cast<uptr>(pos);
|
||||
const long offset = (version & (1 << 16)) ?
|
||||
consume<long>(pos, end) : consume<int>(pos, end);
|
||||
const uint32_t size = consume<uint32_t>(pos, end);
|
||||
const uint32_t features = consume<uint32_t>(pos, end);
|
||||
uint32_t stack_args = 0;
|
||||
if (features & (1 << 1))
|
||||
stack_args = consume<uint32_t>(pos, end);
|
||||
if (const char* name = symbolize(base + offset))
|
||||
printf("%s: features=%x stack_args=%u\n", name, features, stack_args);
|
||||
}
|
||||
meta_version = version;
|
||||
meta_start = start;
|
||||
meta_end = end;
|
||||
}
|
||||
|
||||
void __sanitizer_metadata_covered_del(uint32_t version, const char* start, const char* end) {
|
||||
assert(version == meta_version);
|
||||
assert(start == meta_start);
|
||||
assert(end == meta_end);
|
||||
}
|
||||
|
||||
const char* atomics_start;
|
||||
const char* atomics_end;
|
||||
|
||||
void __sanitizer_metadata_atomics_add(uint32_t version, const char* start, const char* end) {
|
||||
assert(version == meta_version);
|
||||
assert(start);
|
||||
assert(end >= end);
|
||||
atomics_start = start;
|
||||
atomics_end = end;
|
||||
}
|
||||
|
||||
void __sanitizer_metadata_atomics_del(uint32_t version, const char* start, const char* end) {
|
||||
assert(version == meta_version);
|
||||
assert(atomics_start == start);
|
||||
assert(atomics_end == end);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// REQUIRES: native && target-x86_64
|
||||
// RUN: clang++ %s -o %t && %t | FileCheck %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=covered && %t | FileCheck -check-prefix=CHECK-C %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=atomics && %t | FileCheck -check-prefix=CHECK-A %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=uar && %t | FileCheck -check-prefix=CHECK-U %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=covered,atomics && %t | FileCheck -check-prefix=CHECK-CA %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck -check-prefix=CHECK-CU %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=atomics,uar && %t | FileCheck -check-prefix=CHECK-AU %s
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=covered,atomics,uar && %t | FileCheck -check-prefix=CHECK-CAU %s
|
||||
|
||||
// CHECK-NOT: metadata add
|
||||
// CHECK: main
|
||||
// CHECK-NOT: metadata del
|
||||
|
||||
// CHECK-C: empty: features=0
|
||||
// CHECK-A-NOT: empty:
|
||||
// CHECK-U-NOT: empty:
|
||||
// CHECK-CA: empty: features=1
|
||||
// CHECK-CU: empty: features=0
|
||||
// CHECK-AU-NOT: empty:
|
||||
// CHECK-CAU: empty: features=1
|
||||
void empty() {
|
||||
}
|
||||
|
||||
// CHECK-C: normal: features=0
|
||||
// CHECK-A: normal: features=1
|
||||
// CHECK-U: normal: features=2
|
||||
// CHECK-CA: normal: features=1
|
||||
// CHECK-CU: normal: features=2
|
||||
// CHECK-AU: normal: features=3
|
||||
// CHECK-CAU:normal: features=3
|
||||
void normal() {
|
||||
volatile int x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
// CHECK-C: with_atomic: features=0
|
||||
// CHECK-A: with_atomic: features=1
|
||||
// CHECK-U: with_atomic: features=2
|
||||
// CHECK-CA: with_atomic: features=1
|
||||
// CHECK-CU: with_atomic: features=2
|
||||
// CHECK-AU: with_atomic: features=3
|
||||
// CHECK-CAU: with_atomic: features=3
|
||||
int with_atomic(int* p) {
|
||||
return __atomic_load_n(p, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
// CHECK-C: ellipsis: features=0
|
||||
// CHECK-A: ellipsis: features=1
|
||||
// CHECK-U-NOT: ellipsis:
|
||||
// CHECK-CA: ellipsis: features=1
|
||||
// CHECK-CU: ellipsis: features=0
|
||||
// CHECK-AU: ellipsis: features=1
|
||||
// CHECK-CAU: ellipsis: features=1
|
||||
void ellipsis(int* p, ...) {
|
||||
volatile int x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
// CHECK-C: ellipsis_with_atomic: features=0
|
||||
// CHECK-A: ellipsis_with_atomic: features=1
|
||||
// CHECK-U-NOT: ellipsis_with_atomic:
|
||||
// CHECK-CA: ellipsis_with_atomic: features=1
|
||||
// CHECK-CU: ellipsis_with_atomic: features=0
|
||||
// CHECK-AU: ellipsis_with_atomic: features=1
|
||||
// CHECK-CAU: ellipsis_with_atomic: features=1
|
||||
int ellipsis_with_atomic(int* p, ...) {
|
||||
return __atomic_load_n(p, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
#define FUNCTIONS \
|
||||
FN(empty); \
|
||||
FN(normal); \
|
||||
FN(with_atomic); \
|
||||
FN(ellipsis); \
|
||||
FN(ellipsis_with_atomic); \
|
||||
/**/
|
||||
|
||||
#include "common.h"
|
|
@ -0,0 +1 @@
|
|||
config.suffixes = ['.ll', '.cpp']
|
|
@ -0,0 +1,59 @@
|
|||
// We run the compiled binary + sizes of stack arguments depend on the arch.
|
||||
// REQUIRES: native && target-x86_64
|
||||
// RUN: clang++ %s -o %t -fexperimental-sanitize-metadata=covered,uar && %t | tee /dev/stderr | FileCheck %s
|
||||
|
||||
// CHECK: metadata add version 1
|
||||
|
||||
// CHECK: empty: features=0 stack_args=0
|
||||
void empty() {
|
||||
}
|
||||
|
||||
// CHECK: ellipsis: features=0 stack_args=0
|
||||
void ellipsis(const char* fmt, ...) {
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
// CHECK: non_empty_function: features=2 stack_args=0
|
||||
void non_empty_function() {
|
||||
// Completely empty functions don't get uar metadata.
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
// CHECK: no_stack_args: features=2 stack_args=0
|
||||
void no_stack_args(long a0, long a1, long a2, long a3, long a4, long a5) {
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
// CHECK: stack_args: features=2 stack_args=16
|
||||
void stack_args(long a0, long a1, long a2, long a3, long a4, long a5, long a6) {
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
// CHECK: more_stack_args: features=2 stack_args=32
|
||||
void more_stack_args(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) {
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
// CHECK: struct_stack_args: features=2 stack_args=144
|
||||
struct large { char x[131]; };
|
||||
void struct_stack_args(large a) {
|
||||
volatile int x;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
#define FUNCTIONS \
|
||||
FN(empty); \
|
||||
FN(ellipsis); \
|
||||
FN(non_empty_function); \
|
||||
FN(no_stack_args); \
|
||||
FN(stack_args); \
|
||||
FN(more_stack_args); \
|
||||
FN(struct_stack_args); \
|
||||
/**/
|
||||
|
||||
#include "common.h"
|
Loading…
Reference in New Issue