diff --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp --- a/compiler-rt/lib/dfsan/dfsan.cpp +++ b/compiler-rt/lib/dfsan/dfsan.cpp @@ -41,8 +41,15 @@ Flags __dfsan::flags_data; -SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; -SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; +// The size of TLS variables. These constants must be kept in sync with the ones +// in DataFlowSanitizer.cpp. +static const int kDFsanArgTlsSize = 800; +static const int kDFsanRetvalTlsSize = 800; + +SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 + __dfsan_retval_tls[kDFsanRetvalTlsSize / sizeof(u64)]; +SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 + __dfsan_arg_tls[kDFsanArgTlsSize / sizeof(u64)]; SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask; diff --git a/compiler-rt/test/dfsan/pair.cpp b/compiler-rt/test/dfsan/pair.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/pair.cpp @@ -0,0 +1,169 @@ +// RUN: %clangxx_dfsan %s -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-select-control-flow=false -mllvm -dfsan-combine-pointer-labels-on-load=false -O0 -DO0 -o %t && %run %t +// RUN: %clangxx_dfsan %s -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-select-control-flow=false -mllvm -dfsan-combine-pointer-labels-on-load=false -O1 -o %t && %run %t + +#include +#include +#include +#include + +__attribute__((noinline)) +std::pair +make_pair(int *p, int i) { return {p, i}; } + +__attribute__((noinline)) +std::pair +copy_pair1(const std::pair &pair) { + return pair; +} + +__attribute__((noinline)) +std::pair +copy_pair2(std::pair *pair) { + return *pair; +} + +__attribute__((noinline)) +std::pair +copy_pair3(std::pair &&pair) { + return std::move(pair); +} + +__attribute__((noinline)) +std::pair +return_ptr_and_i32(const char *p, uint32_t res) { + for (uint32_t i = 2; i < 5; i++) { + uint32_t byte = static_cast(p[i]); + res += (byte - 1) << (7 * i); + if (byte < 128) { + return {p + i + 1, res}; + } + } + return {nullptr, 0}; +} + +__attribute__((noinline)) +std::pair +return_ptr_and_i64(const char *p, uint32_t res32) { + uint64_t res = res32; + for (uint32_t i = 2; i < 10; i++) { + uint64_t byte = static_cast(p[i]); + res += (byte - 1) << (7 * i); + if (byte < 128) { + return {p + i + 1, res}; + } + } + return {nullptr, 0}; +} + +void test_simple_constructors() { + int i = 1; + int *ptr = NULL; + dfsan_set_label(8, &i, sizeof(i)); + dfsan_set_label(2, &ptr, sizeof(ptr)); + + std::pair pair1 = make_pair(ptr, i); + int i1 = pair1.second; + int *ptr1 = pair1.first; + +#ifdef O0 + assert(dfsan_read_label(&i1, sizeof(i1)) == 10); + assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 10); +#else + assert(dfsan_read_label(&i1, sizeof(i1)) == 8); + assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 2); +#endif + + std::pair pair2 = copy_pair1(pair1); + int i2 = pair2.second; + int *ptr2 = pair2.first; + +#ifdef O0 + assert(dfsan_read_label(&i2, sizeof(i2)) == 10); + assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 10); +#else + assert(dfsan_read_label(&i2, sizeof(i2)) == 8); + assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 2); +#endif + + std::pair pair3 = copy_pair2(&pair1); + int i3 = pair3.second; + int *ptr3 = pair3.first; + +#ifdef O0 + assert(dfsan_read_label(&i3, sizeof(i3)) == 10); + assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 10); +#else + assert(dfsan_read_label(&i3, sizeof(i3)) == 8); + assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 2); +#endif + + std::pair pair4 = copy_pair3(std::move(pair1)); + int i4 = pair4.second; + int *ptr4 = pair4.first; + +#ifdef O0 + assert(dfsan_read_label(&i4, sizeof(i4)) == 10); + assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 10); +#else + assert(dfsan_read_label(&i4, sizeof(i4)) == 8); + assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 2); +#endif +} + +void test_branches() { + uint32_t res = 4; + dfsan_set_label(8, &res, sizeof(res)); + + char p[100]; + const char *q = p; + dfsan_set_label(2, &q, sizeof(q)); + + { + std::fill_n(p, 100, static_cast(128)); + + { + std::pair r = return_ptr_and_i32(q, res); + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 0); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 0); + } + + { + std::pair r = return_ptr_and_i64(q, res); + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 0); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 0); + } + } + + { + std::fill_n(p, 100, 0); + + { + std::pair r = return_ptr_and_i32(q, res); +#ifdef O0 + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10); +#else + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8); +#endif + } + + { + std::pair r = return_ptr_and_i64(q, res); +#ifdef O0 + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10); +#else + assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2); + assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8); +#endif + } + } +} + +int main(void) { + test_simple_constructors(); + test_branches(); + + return 0; +} diff --git a/compiler-rt/test/dfsan/struct.c b/compiler-rt/test/dfsan/struct.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/struct.c @@ -0,0 +1,93 @@ +// RUN: %clang_dfsan %s -O1 -o %t && %run %t +// RUN: %clang_dfsan %s -O0 -DO0 -o %t && %run %t + +#include +#include + +typedef struct Pair { + int i; + char *ptr; +} Pair; + +__attribute__((noinline)) +Pair make_pair(int i, char *ptr) { + Pair pair; + pair.i = i; + pair.ptr = ptr; + return pair; +} + +__attribute__((noinline)) +Pair copy_pair1(const Pair *pair0) { + Pair pair; + pair.i = pair0->i; + pair.ptr = pair0->ptr; + return pair; +} + +__attribute__((noinline)) +Pair copy_pair2(const Pair pair0) { + Pair pair; + pair.i = pair0.i; + pair.ptr = pair0.ptr; + return pair; +} + +int main(void) { + int i = 1; + char *ptr = NULL; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + dfsan_label ptr_label = dfsan_create_label("ptr", 0); + dfsan_set_label(ptr_label, &ptr, sizeof(ptr)); + + Pair pair1 = make_pair(i, ptr); + int i1 = pair1.i; + char *ptr1 = pair1.ptr; + + dfsan_label i1_label = dfsan_read_label(&i1, sizeof(i1)); + dfsan_label ptr1_label = dfsan_read_label(&ptr1, sizeof(ptr1)); +#ifdef O0 + assert(dfsan_has_label(i1_label, i_label)); + assert(dfsan_has_label(i1_label, ptr_label)); + assert(dfsan_has_label(ptr1_label, i_label)); + assert(dfsan_has_label(ptr1_label, ptr_label)); +#else + assert(i1_label == i_label); + assert(ptr1_label == ptr_label); +#endif + + Pair pair2 = copy_pair1(&pair1); + int i2 = pair2.i; + char *ptr2 = pair2.ptr; + + dfsan_label i2_label = dfsan_read_label(&i2, sizeof(i2)); + dfsan_label ptr2_label = dfsan_read_label(&ptr2, sizeof(ptr2)); +#ifdef O0 + assert(dfsan_has_label(i2_label, i_label)); + assert(dfsan_has_label(i2_label, ptr_label)); + assert(dfsan_has_label(ptr2_label, i_label)); + assert(dfsan_has_label(ptr2_label, ptr_label)); +#else + assert(i2_label == i_label); + assert(ptr2_label == ptr_label); +#endif + + Pair pair3 = copy_pair2(pair1); + int i3 = pair3.i; + char *ptr3 = pair3.ptr; + + dfsan_label i3_label = dfsan_read_label(&i3, sizeof(i3)); + dfsan_label ptr3_label = dfsan_read_label(&ptr3, sizeof(ptr3)); +#ifdef O0 + assert(dfsan_has_label(i3_label, i_label)); + assert(dfsan_has_label(i3_label, ptr_label)); + assert(dfsan_has_label(ptr3_label, i_label)); + assert(dfsan_has_label(ptr3_label, ptr_label)); +#else + assert(i3_label == i_label); + assert(ptr3_label == ptr_label); +#endif + + return 0; +} diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -106,6 +106,13 @@ using namespace llvm; +static const Align kShadowTLSAlignment = Align(8); + +// The size of TLS variables. These constants must be kept in sync with the ones +// in dfsan.cpp. +static const unsigned kArgTLSSize = 800; +static const unsigned kRetvalTLSSize = 800; + // External symbol to be used when generating the shadow address for // architectures with multiple VMAs. Instead of using a constant integer // the runtime will set the external mask based on the VMA range. @@ -354,10 +361,13 @@ Module *Mod; LLVMContext *Ctx; Type *Int8Ptr; - IntegerType *ShadowTy; - PointerType *ShadowPtrTy; + /// The shadow type for primary types in TLS mode, and all types in Args mode. + IntegerType *PrimaryShadowTy; + PointerType *PrimaryShadowPtrTy; IntegerType *IntptrTy; - ConstantInt *ZeroShadow; + /// The zero shadow constant for values with primary types in TLS mode, and + /// all types in Args mode. + ConstantInt *ZeroPrimaryShadow; ConstantInt *ShadowPtrMask; ConstantInt *ShadowPtrMul; Constant *ArgTLS; @@ -408,6 +418,31 @@ bool init(Module &M); + /// Returns a zero constant with the shadow type of OrigTy. + /// + /// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T1),...} + /// getZeroShadow([n x T]) = [n x getZeroShadow(T)] + /// getZeroShadow(other type) = i16(0) + /// + /// Note that in Args mode a zero shadow is always i16(0). + Constant *getZeroShadow(Type *OrigTy); + /// Returns a zero constant with the shadow type of V's type. + Constant *getZeroShadow(Value *V); + + /// Checks if V is a zero shadow. + bool isZeroShadow(Value *V); + + /// Returns the shadow type of OrigTy. + /// + /// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T1),...} + /// getShadowTy([n x T]) = [n x getShadowTy(T)] + /// getShadowTy(other type) = i16 + /// + /// Note that in Args mode a shadow type is always i16. + Type *getShadowTy(Type *OrigTy); + /// Returns the shadow type of of V's type. + Type *getShadowTy(Value *V); + public: DataFlowSanitizer(const std::vector &ABIListFiles); @@ -428,12 +463,16 @@ std::vector NonZeroChecks; bool AvoidNewBlocks; - struct CachedCombinedShadow { + struct CachedShadow { + // The block where Shadow is defined. BasicBlock *Block; Value *Shadow; }; - DenseMap, CachedCombinedShadow> - CachedCombinedShadows; + /// Maps a value to its latest shadow value in terms of domination tree. + DenseMap, CachedShadow> CachedShadows; + /// Maps a value to its latest primary shadow value it was converted to in + /// terms of domination tree. + DenseMap CachedShadow2PrimaryShadow; DenseMap> ShadowElements; DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI) @@ -444,15 +483,66 @@ AvoidNewBlocks = F->size() > 1000; } - Value *getArgTLS(unsigned Index, Instruction *Pos); + /// Computes the shadow address for a given function argument. + /// + /// Shadow = ArgTLS+ArgOffset. + Value *getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB); + + /// Computes the shadow address for a retval. + Value *getRetvalTLS(Type *T, IRBuilder<> &IRB); + Value *getShadow(Value *V); void setShadow(Instruction *I, Value *Shadow); + /// Generates IR to compute the union of the two given shadows, inserting it + /// before Pos. The combined value is with primary type. Value *combineShadows(Value *V1, Value *V2, Instruction *Pos); + /// Combines the shadow values of V1 and V2, then converts the combined value + /// with primary type into a shadow value with the original type T. + Value *combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos); Value *combineOperandShadows(Instruction *Inst); Value *loadShadow(Value *ShadowAddr, uint64_t Size, uint64_t Align, Instruction *Pos); void storeShadow(Value *Addr, uint64_t Size, Align Alignment, Value *Shadow, Instruction *Pos); + /// Returns a shadow value with the original type T. All its primary sub + /// values are assigne to PrimaryShadow. + /// + /// CFP({T1,T2, ...}, PS) = {CFP(T1,PS),CFP(T2,PS),...} + /// CFP([n x T], PS) = [n x CFP(T,PS)] + /// CFP(other types, PS) = PS + Value *convertFromPrimaryShadow(Type *T, Value *PrimaryShadow, + Instruction *Pos); + /// Returns a primary shadow value by combining all primary values of Shadow. + /// + /// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP(other types, PS) = PS + Value *convertToPrimaryShadow(Value *Shadow, Instruction *Pos); + +private: + Value *convertFromPrimaryShadowByShadowType(Value *Shadow, + SmallVector &Indices, + Type *SubShadowTy, + Value *PrimaryShadow, + IRBuilder<> &IRB); + Value *convertFromPrimaryShadowByShadowType(Type *ShadowTy, + Value *PrimaryShadow, + Instruction *Pos); + /// Returns a primary shadow value by combining all primary values of a Shadow + /// value with type Struct. This is an auxilary method of + /// convertToPrimaryShadow. + Value *collapseStructShadow(StructType *Struct, Value *Shadow, + IRBuilder<> &IRB); + /// Returns a primary shadow value by combining all primary values of a Shadow + /// value with type Array. This is an auxilary method of + /// convertToPrimaryShadow. + Value *collapseArrayShadow(ArrayType *Array, Value *Shadow, IRBuilder<> &IRB); + + Value *convertToPrimaryShadow(Value *Shadow, IRBuilder<> &IRB); + + /// Returns the shadow value of an argument A. + Value *getShadowForTLSArgument(Argument *A); }; class DFSanVisitor : public InstVisitor { @@ -504,12 +594,12 @@ FunctionType *DataFlowSanitizer::getArgsFunctionType(FunctionType *T) { SmallVector ArgTypes(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), ShadowTy); + ArgTypes.append(T->getNumParams(), PrimaryShadowTy); if (T->isVarArg()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimaryShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - RetType = StructType::get(RetType, ShadowTy); + RetType = StructType::get(RetType, PrimaryShadowTy); return FunctionType::get(RetType, ArgTypes, T->isVarArg()); } @@ -518,10 +608,10 @@ SmallVector ArgTypes; ArgTypes.push_back(T->getPointerTo()); ArgTypes.append(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), ShadowTy); + ArgTypes.append(T->getNumParams(), PrimaryShadowTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimaryShadowPtrTy); return FunctionType::get(T->getReturnType(), ArgTypes, false); } @@ -547,17 +637,226 @@ } } for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) - ArgTypes.push_back(ShadowTy); + ArgTypes.push_back(PrimaryShadowTy); if (T->isVarArg()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimaryShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimaryShadowPtrTy); return TransformedFunction( T, FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()), ArgumentIndexMapping); } +// Checks if V is a zero shadow. +bool DataFlowSanitizer::isZeroShadow(Value *V) { + if (getInstrumentedABI() == DataFlowSanitizer::IA_Args) { + return ZeroPrimaryShadow == V; + } + + Type *T = V->getType(); + if (!isa(T) && !isa(T)) { + if (const ConstantInt *CI = dyn_cast(V)) + return CI->isZero(); + else + return false; + } + + return isa(V); +} + +// Returns a zero constant with the shadow type of OrigTy. +// +// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T1),...} +// getZeroShadow([n x T]) = [n x getZeroShadow(T)] +// getZeroShadow(other type) = i16(0) +// +// Note that in Args mode a zero shadow is always i16(0). +Constant *DataFlowSanitizer::getZeroShadow(Type *OrigTy) { + if (getInstrumentedABI() == DataFlowSanitizer::IA_Args) { + return ZeroPrimaryShadow; + } + + if (!isa(OrigTy) && !isa(OrigTy)) { + return ZeroPrimaryShadow; + } + Type *ShadowTy = getShadowTy(OrigTy); + return ConstantAggregateZero::get(ShadowTy); +} + +Constant *DataFlowSanitizer::getZeroShadow(Value *V) { + return getZeroShadow(V->getType()); +} + +Value *DFSanFunction::convertFromPrimaryShadowByShadowType( + Value *Shadow, SmallVector &Indices, Type *SubShadowTy, + Value *PrimaryShadow, IRBuilder<> &IRB) { + if (!isa(SubShadowTy) && !isa(SubShadowTy)) + return IRB.CreateInsertValue(Shadow, PrimaryShadow, Indices); + + if (ArrayType *AT = dyn_cast(SubShadowTy)) { + for (unsigned Idx = 0; Idx < AT->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = convertFromPrimaryShadowByShadowType( + Shadow, Indices, AT->getElementType(), PrimaryShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + + if (StructType *ST = dyn_cast(SubShadowTy)) { + for (unsigned Idx = 0; Idx < ST->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = convertFromPrimaryShadowByShadowType( + Shadow, Indices, ST->getElementType(Idx), PrimaryShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + llvm_unreachable("Unexpected shadow type"); +} + +Value *DFSanFunction::convertFromPrimaryShadowByShadowType(Type *ShadowTy, + Value *PrimaryShadow, + Instruction *Pos) { + if (!isa(ShadowTy) && !isa(ShadowTy)) + return PrimaryShadow; + + if (DFS.isZeroShadow(PrimaryShadow)) { + return DFS.getZeroShadow(ShadowTy); + } + + IRBuilder<> IRB(Pos); + SmallVector Indices; + Value *ZeroShadow = DFS.getZeroShadow(ShadowTy); + Value *Shadow = convertFromPrimaryShadowByShadowType( + ZeroShadow, Indices, ShadowTy, PrimaryShadow, IRB); + // Caches the primary shadow value that built the shadow value. + CachedShadow &CS = CachedShadow2PrimaryShadow[Shadow]; + CS.Shadow = PrimaryShadow; + CS.Block = Pos->getParent(); + return Shadow; +} + +// Returns a shadow value with the original type T. All its primary sub +// values are assigne to PrimaryShadow. +// +// CFP({T1,T2, ...}, PS) = {CFP(T1,PS),CFP(T2,PS),...} +// CFP([n x T], PS) = [n x CFP(T,PS)] +// CFP(other types, PS) = PS +Value *DFSanFunction::convertFromPrimaryShadow(Type *T, Value *PrimaryShadow, + Instruction *Pos) { + Type *ShadowTy = DFS.getShadowTy(T); + return convertFromPrimaryShadowByShadowType(ShadowTy, PrimaryShadow, Pos); +} + +Value *DFSanFunction::collapseStructShadow(StructType *Struct, Value *Shadow, + IRBuilder<> &IRB) { + if (!Struct->getNumElements()) + return DFS.ZeroPrimaryShadow; + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = convertToPrimaryShadow(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < Struct->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertToPrimaryShadow(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; +} + +Value *DFSanFunction::collapseArrayShadow(ArrayType *Array, Value *Shadow, + IRBuilder<> &IRB) { + if (!Array->getNumElements()) + return DFS.ZeroPrimaryShadow; + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = convertToPrimaryShadow(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < Array->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertToPrimaryShadow(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; +} + +Value *DFSanFunction::convertToPrimaryShadow(Value *Shadow, IRBuilder<> &IRB) { + Type *ShadowTy = Shadow->getType(); + if (!isa(ShadowTy) && !isa(ShadowTy)) + return Shadow; + if (ArrayType *AT = dyn_cast(ShadowTy)) { + return collapseArrayShadow(AT, Shadow, IRB); + } + if (StructType *ST = dyn_cast(ShadowTy)) { + return collapseStructShadow(ST, Shadow, IRB); + } + llvm_unreachable("Unexpected shadow type"); +} + +// Returns a primary shadow value by combining all primary values of Shadow. +// +// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...) +// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...) +// CTP(other types, PS) = PS +Value *DFSanFunction::convertToPrimaryShadow(Value *Shadow, Instruction *Pos) { + Type *ShadowTy = Shadow->getType(); + if (!isa(ShadowTy) && !isa(ShadowTy)) + return Shadow; + + // Checks if the cached converted shadow value dominates Pos. + CachedShadow &CS = CachedShadow2PrimaryShadow[Shadow]; + if (CS.Block && DT.dominates(CS.Block, Pos->getParent()) && + DT.dominates(CS.Shadow, Pos)) + return CS.Shadow; + + IRBuilder<> IRB(Pos); + Value *PrimaryShadow = convertToPrimaryShadow(Shadow, IRB); + // Caches the converted primary shadow value. + CS.Block = Pos->getParent(); + CS.Shadow = PrimaryShadow; + return PrimaryShadow; +} + +// Returns the shadow type of OrigTy. +// +// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T1),...} +// getShadowTy([n x T]) = [n x getShadowTy(T)] +// getShadowTy(other type) = i16 +// +// Note that in Args mode a shadow type is always i16. +Type *DataFlowSanitizer::getShadowTy(Type *OrigTy) { + if (getInstrumentedABI() == DataFlowSanitizer::IA_Args) { + return PrimaryShadowTy; + } + + if (!OrigTy->isSized()) { + return PrimaryShadowTy; + } + if (isa(OrigTy)) + return PrimaryShadowTy; + if (isa(OrigTy)) { + return PrimaryShadowTy; + } + if (ArrayType *AT = dyn_cast(OrigTy)) { + return ArrayType::get(getShadowTy(AT->getElementType()), + AT->getNumElements()); + } + if (StructType *ST = dyn_cast(OrigTy)) { + SmallVector Elements; + for (unsigned i = 0, n = ST->getNumElements(); i < n; i++) + Elements.push_back(getShadowTy(ST->getElementType(i))); + StructType *Res = StructType::get(*Ctx, Elements); + return Res; + } + return PrimaryShadowTy; +} + +Type *DataFlowSanitizer::getShadowTy(Value *V) { + return getShadowTy(V->getType()); +} + bool DataFlowSanitizer::init(Module &M) { Triple TargetTriple(M.getTargetTriple()); bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; @@ -570,10 +869,10 @@ Mod = &M; Ctx = &M.getContext(); Int8Ptr = Type::getInt8PtrTy(*Ctx); - ShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); - ShadowPtrTy = PointerType::getUnqual(ShadowTy); + PrimaryShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); + PrimaryShadowPtrTy = PointerType::getUnqual(PrimaryShadowTy); IntptrTy = DL.getIntPtrType(*Ctx); - ZeroShadow = ConstantInt::getSigned(ShadowTy, 0); + ZeroPrimaryShadow = ConstantInt::getSigned(PrimaryShadowTy, 0); ShadowPtrMul = ConstantInt::getSigned(IntptrTy, ShadowWidthBytes); if (IsX86_64) ShadowPtrMask = ConstantInt::getSigned(IntptrTy, ~0x700000000000LL); @@ -585,28 +884,30 @@ else report_fatal_error("unsupported triple"); - Type *DFSanUnionArgs[2] = { ShadowTy, ShadowTy }; + Type *DFSanUnionArgs[2] = {PrimaryShadowTy, PrimaryShadowTy}; DFSanUnionFnTy = - FunctionType::get(ShadowTy, DFSanUnionArgs, /*isVarArg=*/ false); - Type *DFSanUnionLoadArgs[2] = { ShadowPtrTy, IntptrTy }; - DFSanUnionLoadFnTy = - FunctionType::get(ShadowTy, DFSanUnionLoadArgs, /*isVarArg=*/ false); + FunctionType::get(PrimaryShadowTy, DFSanUnionArgs, /*isVarArg=*/false); + Type *DFSanUnionLoadArgs[2] = {PrimaryShadowPtrTy, IntptrTy}; + DFSanUnionLoadFnTy = FunctionType::get(PrimaryShadowTy, DFSanUnionLoadArgs, + /*isVarArg=*/false); DFSanUnimplementedFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - Type *DFSanSetLabelArgs[3] = { ShadowTy, Type::getInt8PtrTy(*Ctx), IntptrTy }; + Type *DFSanSetLabelArgs[3] = {PrimaryShadowTy, Type::getInt8PtrTy(*Ctx), + IntptrTy}; DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanSetLabelArgs, /*isVarArg=*/false); - DFSanNonzeroLabelFnTy = FunctionType::get( - Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); + DFSanNonzeroLabelFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); DFSanVarargWrapperFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - DFSanCmpCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, - /*isVarArg=*/false); - Type *DFSanLoadStoreCallbackArgs[2] = {ShadowTy, Int8Ptr}; + DFSanCmpCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), PrimaryShadowTy, + /*isVarArg=*/false); + Type *DFSanLoadStoreCallbackArgs[2] = {PrimaryShadowTy, Int8Ptr}; DFSanLoadStoreCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs, /*isVarArg=*/false); - Type *DFSanMemTransferCallbackArgs[2] = {ShadowPtrTy, IntptrTy}; + Type *DFSanMemTransferCallbackArgs[2] = {PrimaryShadowPtrTy, IntptrTy}; DFSanMemTransferCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs, /*isVarArg=*/false); @@ -711,14 +1012,22 @@ else RI = ReturnInst::Create(*Ctx, CI, BB); + // F is called by a wrapped custom function with primary shadows. So + // its arguments and return value need convertion. DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true); - Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI; ++ValAI; - for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) - DFSF.ValShadowMap[&*ValAI] = &*ShadowAI; + Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI; + ++ValAI; + for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) { + Value *Shadow = + DFSF.convertFromPrimaryShadow(ValAI->getType(), &*ShadowAI, CI); + DFSF.ValShadowMap[&*ValAI] = Shadow; + } DFSanVisitor(DFSF).visitCallInst(*CI); - if (!FT->getReturnType()->isVoidTy()) - new StoreInst(DFSF.getShadow(RI->getReturnValue()), - &*std::prev(F->arg_end()), RI); + if (!FT->getReturnType()->isVoidTy()) { + Value *PrimaryShadow = + DFSF.convertToPrimaryShadow(DFSF.getShadow(RI->getReturnValue()), RI); + new StoreInst(PrimaryShadow, &*std::prev(F->arg_end()), RI); + } } return cast(C.getCallee()); @@ -811,13 +1120,15 @@ bool Changed = false; - Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); + Type *ArgTLSTy = ArrayType::get(Type::getInt64Ty(*Ctx), kArgTLSSize / 8); ArgTLS = Mod->getOrInsertGlobal("__dfsan_arg_tls", ArgTLSTy); if (GlobalVariable *G = dyn_cast(ArgTLS)) { Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); } - RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", ShadowTy); + Type *RetvalTLSTy = + ArrayType::get(Type::getInt64Ty(*Ctx), kRetvalTLSSize / 8); + RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", RetvalTLSTy); if (GlobalVariable *G = dyn_cast(RetvalTLS)) { Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); @@ -1036,7 +1347,8 @@ while (isa(Pos) || isa(Pos)) Pos = Pos->getNextNode(); IRBuilder<> IRB(Pos); - Value *Ne = IRB.CreateICmpNE(V, DFSF.DFS.ZeroShadow); + Value *PrimaryShadow = DFSF.convertToPrimaryShadow(V, Pos); + Value *Ne = IRB.CreateICmpNE(PrimaryShadow, DFSF.DFS.ZeroPrimaryShadow); BranchInst *BI = cast(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, ColdCallWeights)); IRBuilder<> ThenIRB(BI); @@ -1049,29 +1361,71 @@ M.global_size() != InitialGlobalSize || M.size() != InitialModuleSize; } -Value *DFSanFunction::getArgTLS(unsigned Idx, Instruction *Pos) { - IRBuilder<> IRB(Pos); - return IRB.CreateConstGEP2_64(ArrayType::get(DFS.ShadowTy, 64), DFS.ArgTLS, 0, - Idx); +// Computes the shadow address for a given function argument. +// +// Shadow = ArgTLS+ArgOffset. +Value *DFSanFunction::getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB) { + Value *Base = IRB.CreatePointerCast(DFS.ArgTLS, DFS.IntptrTy); + if (ArgOffset) + Base = IRB.CreateAdd(Base, ConstantInt::get(DFS.IntptrTy, ArgOffset)); + return IRB.CreateIntToPtr(Base, PointerType::get(DFS.getShadowTy(T), 0), + "_dfsarg"); +} + +// Computes the shadow address for a retval. +Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) { + return IRB.CreatePointerCast( + DFS.RetvalTLS, PointerType::get(DFS.getShadowTy(T), 0), "_dfsret"); +} + +// Returns the shadow value of an argument A. +Value *DFSanFunction::getShadowForTLSArgument(Argument *A) { + unsigned ArgOffset = 0; + const DataLayout &DL = F->getParent()->getDataLayout(); + for (auto &FArg : F->args()) { + if (!FArg.getType()->isSized()) { + if (A == &FArg) { + break; + } + continue; + } + + unsigned Size = DL.getTypeAllocSize(DFS.getShadowTy(&FArg)); + if (A != &FArg) { + ArgOffset += alignTo(Size, kShadowTLSAlignment); + if (ArgOffset > kArgTLSSize) { + // ArgTLS overflows, uses a zero shadow. + break; + } + continue; + } + + if (ArgOffset + Size > kArgTLSSize) { + // ArgTLS overflows, uses a zero shadow. + break; + } + + Instruction *ArgTLSPos = &*F->getEntryBlock().begin(); + IRBuilder<> IRB(ArgTLSPos); + Value *Base = getArgTLS(FArg.getType(), ArgOffset, IRB); + return IRB.CreateAlignedLoad(DFS.getShadowTy(&FArg), Base, + kShadowTLSAlignment); + } + + return DFS.getZeroShadow(A); } Value *DFSanFunction::getShadow(Value *V) { if (!isa(V) && !isa(V)) - return DFS.ZeroShadow; + return DFS.getZeroShadow(V); Value *&Shadow = ValShadowMap[V]; if (!Shadow) { if (Argument *A = dyn_cast(V)) { if (IsNativeABI) - return DFS.ZeroShadow; + return DFS.getZeroShadow(V); switch (IA) { case DataFlowSanitizer::IA_TLS: { - Value *ArgTLSPtr = DFS.ArgTLS; - Instruction *ArgTLSPos = - DFS.ArgTLS ? &*F->getEntryBlock().begin() - : cast(ArgTLSPtr)->getNextNode(); - IRBuilder<> IRB(ArgTLSPos); - Shadow = - IRB.CreateLoad(DFS.ShadowTy, getArgTLS(A->getArgNo(), ArgTLSPos)); + Shadow = getShadowForTLSArgument(A); break; } case DataFlowSanitizer::IA_Args: { @@ -1080,13 +1434,13 @@ while (ArgIdx--) ++i; Shadow = &*i; - assert(Shadow->getType() == DFS.ShadowTy); + assert(Shadow->getType() == DFS.PrimaryShadowTy); break; } } NonZeroChecks.push_back(Shadow); } else { - Shadow = DFS.ZeroShadow; + Shadow = DFS.getZeroShadow(V); } } return Shadow; @@ -1094,7 +1448,8 @@ void DFSanFunction::setShadow(Instruction *I, Value *Shadow) { assert(!ValShadowMap.count(I)); - assert(Shadow->getType() == DFS.ShadowTy); + assert(DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS || + Shadow->getType() == DFS.PrimaryShadowTy); ValShadowMap[I] = Shadow; } @@ -1111,50 +1466,60 @@ IRB.CreateAnd(IRB.CreatePtrToInt(Addr, IntptrTy), IRB.CreatePtrToInt(ShadowPtrMaskValue, IntptrTy)), ShadowPtrMul), - ShadowPtrTy); + PrimaryShadowPtrTy); +} + +Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos) { + Value *PrimaryValue = combineShadows(V1, V2, Pos); + return convertFromPrimaryShadow(T, PrimaryValue, Pos); } // Generates IR to compute the union of the two given shadows, inserting it -// before Pos. Returns the computed union Value. +// before Pos. The combined value is with primary type. Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { - if (V1 == DFS.ZeroShadow) - return V2; - if (V2 == DFS.ZeroShadow) - return V1; + if (DFS.isZeroShadow(V1)) + return convertToPrimaryShadow(V2, Pos); + if (DFS.isZeroShadow(V2)) + return convertToPrimaryShadow(V1, Pos); if (V1 == V2) - return V1; + return convertToPrimaryShadow(V1, Pos); auto V1Elems = ShadowElements.find(V1); auto V2Elems = ShadowElements.find(V2); if (V1Elems != ShadowElements.end() && V2Elems != ShadowElements.end()) { if (std::includes(V1Elems->second.begin(), V1Elems->second.end(), V2Elems->second.begin(), V2Elems->second.end())) { - return V1; + return convertToPrimaryShadow(V1, Pos); } else if (std::includes(V2Elems->second.begin(), V2Elems->second.end(), V1Elems->second.begin(), V1Elems->second.end())) { - return V2; + return convertToPrimaryShadow(V2, Pos); } } else if (V1Elems != ShadowElements.end()) { if (V1Elems->second.count(V2)) - return V1; + return convertToPrimaryShadow(V1, Pos); } else if (V2Elems != ShadowElements.end()) { if (V2Elems->second.count(V1)) - return V2; + return convertToPrimaryShadow(V2, Pos); } auto Key = std::make_pair(V1, V2); if (V1 > V2) std::swap(Key.first, Key.second); - CachedCombinedShadow &CCS = CachedCombinedShadows[Key]; + CachedShadow &CCS = CachedShadows[Key]; if (CCS.Block && DT.dominates(CCS.Block, Pos->getParent())) return CCS.Shadow; + // Converts inputs shadows to shadows with primary types. + Value *PV1 = convertToPrimaryShadow(V1, Pos); + Value *PV2 = convertToPrimaryShadow(V2, Pos); + IRBuilder<> IRB(Pos); if (ClFast16Labels) { CCS.Block = Pos->getParent(); - CCS.Shadow = IRB.CreateOr(V1, V2); + CCS.Shadow = IRB.CreateOr(PV1, PV2); } else if (AvoidNewBlocks) { - CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {V1, V2}); + CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); @@ -1163,19 +1528,19 @@ CCS.Shadow = Call; } else { BasicBlock *Head = Pos->getParent(); - Value *Ne = IRB.CreateICmpNE(V1, V2); + Value *Ne = IRB.CreateICmpNE(PV1, PV2); BranchInst *BI = cast(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, DFS.ColdCallWeights, &DT)); IRBuilder<> ThenIRB(BI); - CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {V1, V2}); + CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); BasicBlock *Tail = BI->getSuccessor(0); - PHINode *Phi = PHINode::Create(DFS.ShadowTy, 2, "", &Tail->front()); + PHINode *Phi = PHINode::Create(DFS.PrimaryShadowTy, 2, "", &Tail->front()); Phi->addIncoming(Call, Call->getParent()); - Phi->addIncoming(V1, Head); + Phi->addIncoming(PV1, Head); CCS.Block = Tail; CCS.Shadow = Phi; @@ -1202,13 +1567,13 @@ // the computed union Value. Value *DFSanFunction::combineOperandShadows(Instruction *Inst) { if (Inst->getNumOperands() == 0) - return DFS.ZeroShadow; + return DFS.getZeroShadow(Inst); Value *Shadow = getShadow(Inst->getOperand(0)); for (unsigned i = 1, n = Inst->getNumOperands(); i != n; ++i) { Shadow = combineShadows(Shadow, getShadow(Inst->getOperand(i)), Inst); } - return Shadow; + return convertFromPrimaryShadow(Inst->getType(), Shadow, Inst); } Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) { @@ -1218,14 +1583,15 @@ } // Generates IR to load shadow corresponding to bytes [Addr, Addr+Size), where -// Addr has alignment Align, and take the union of each of those shadows. +// Addr has alignment Align, and take the union of each of those shadows. The +// returned shadow is always with primary types. Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, Instruction *Pos) { if (AllocaInst *AI = dyn_cast(Addr)) { const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - return IRB.CreateLoad(DFS.ShadowTy, i->second); + return IRB.CreateLoad(DFS.PrimaryShadowTy, i->second); } } @@ -1243,24 +1609,25 @@ break; } if (AllConstants) - return DFS.ZeroShadow; + return DFS.ZeroPrimaryShadow; Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); switch (Size) { case 0: - return DFS.ZeroShadow; + return DFS.ZeroPrimaryShadow; case 1: { - LoadInst *LI = new LoadInst(DFS.ShadowTy, ShadowAddr, "", Pos); + LoadInst *LI = new LoadInst(DFS.PrimaryShadowTy, ShadowAddr, "", Pos); LI->setAlignment(ShadowAlign); return LI; } case 2: { IRBuilder<> IRB(Pos); - Value *ShadowAddr1 = IRB.CreateGEP(DFS.ShadowTy, ShadowAddr, + Value *ShadowAddr1 = IRB.CreateGEP(DFS.PrimaryShadowTy, ShadowAddr, ConstantInt::get(DFS.IntptrTy, 1)); return combineShadows( - IRB.CreateAlignedLoad(DFS.ShadowTy, ShadowAddr, ShadowAlign), - IRB.CreateAlignedLoad(DFS.ShadowTy, ShadowAddr1, ShadowAlign), Pos); + IRB.CreateAlignedLoad(DFS.PrimaryShadowTy, ShadowAddr, ShadowAlign), + IRB.CreateAlignedLoad(DFS.PrimaryShadowTy, ShadowAddr1, ShadowAlign), + Pos); } } @@ -1285,7 +1652,7 @@ Value *ShrShadow = IRB.CreateLShr(CombinedWideShadow, Width); CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, ShrShadow); } - return IRB.CreateTrunc(CombinedWideShadow, DFS.ShadowTy); + return IRB.CreateTrunc(CombinedWideShadow, DFS.PrimaryShadowTy); } if (!AvoidNewBlocks && Size % (64 / DFS.ShadowWidthBits) == 0) { // Fast path for the common case where each byte has identical shadow: load @@ -1305,7 +1672,7 @@ IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); Value *WideShadow = IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); - Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.ShadowTy); + Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.PrimaryShadowTy); Value *ShlShadow = IRB.CreateShl(WideShadow, DFS.ShadowWidthBits); Value *ShrShadow = IRB.CreateLShr(WideShadow, 64 - DFS.ShadowWidthBits); Value *RotShadow = IRB.CreateOr(ShlShadow, ShrShadow); @@ -1346,7 +1713,8 @@ LastBr->setSuccessor(0, Tail); FallbackIRB.CreateBr(Tail); - PHINode *Shadow = PHINode::Create(DFS.ShadowTy, 2, "", &Tail->front()); + PHINode *Shadow = + PHINode::Create(DFS.PrimaryShadowTy, 2, "", &Tail->front()); Shadow->addIncoming(FallbackCall, FallbackBB); Shadow->addIncoming(TruncShadow, LastBr->getParent()); return Shadow; @@ -1365,25 +1733,27 @@ auto &DL = LI.getModule()->getDataLayout(); uint64_t Size = DL.getTypeStoreSize(LI.getType()); if (Size == 0) { - DFSF.setShadow(&LI, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&LI, DFSF.DFS.getZeroShadow(&LI)); return; } Align Alignment = ClPreserveAlignment ? LI.getAlign() : Align(1); - Value *Shadow = + Value *PrimaryShadow = DFSF.loadShadow(LI.getPointerOperand(), Size, Alignment.value(), &LI); if (ClCombinePointerLabelsOnLoad) { Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand()); - Shadow = DFSF.combineShadows(Shadow, PtrShadow, &LI); + PrimaryShadow = DFSF.combineShadows(PrimaryShadow, PtrShadow, &LI); } - if (Shadow != DFSF.DFS.ZeroShadow) - DFSF.NonZeroChecks.push_back(Shadow); + if (!DFSF.DFS.isZeroShadow(PrimaryShadow)) + DFSF.NonZeroChecks.push_back(PrimaryShadow); + Value *Shadow = + DFSF.convertFromPrimaryShadow(LI.getType(), PrimaryShadow, &LI); DFSF.setShadow(&LI, Shadow); if (ClEventCallbacks) { IRBuilder<> IRB(&LI); Value *Addr8 = IRB.CreateBitCast(LI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {Shadow, Addr8}); + IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimaryShadow, Addr8}); } } @@ -1393,7 +1763,8 @@ const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - IRB.CreateStore(Shadow, i->second); + Value *PrimaryShadow = convertToPrimaryShadow(Shadow, Pos); + IRB.CreateStore(PrimaryShadow, i->second); return; } } @@ -1401,24 +1772,27 @@ const Align ShadowAlign(Alignment.value() * DFS.ShadowWidthBytes); IRBuilder<> IRB(Pos); Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); - if (Shadow == DFS.ZeroShadow) { - IntegerType *ShadowTy = + if (DFS.isZeroShadow(Shadow)) { + IntegerType *PrimaryShadowTy = IntegerType::get(*DFS.Ctx, Size * DFS.ShadowWidthBits); - Value *ExtZeroShadow = ConstantInt::get(ShadowTy, 0); + Value *ExtZeroShadow = ConstantInt::get(PrimaryShadowTy, 0); Value *ExtShadowAddr = - IRB.CreateBitCast(ShadowAddr, PointerType::getUnqual(ShadowTy)); + IRB.CreateBitCast(ShadowAddr, PointerType::getUnqual(PrimaryShadowTy)); IRB.CreateAlignedStore(ExtZeroShadow, ExtShadowAddr, ShadowAlign); return; } const unsigned ShadowVecSize = 128 / DFS.ShadowWidthBits; uint64_t Offset = 0; + Value *PrimaryShadow = convertToPrimaryShadow(Shadow, Pos); if (Size >= ShadowVecSize) { - auto *ShadowVecTy = FixedVectorType::get(DFS.ShadowTy, ShadowVecSize); + auto *ShadowVecTy = + FixedVectorType::get(DFS.PrimaryShadowTy, ShadowVecSize); Value *ShadowVec = UndefValue::get(ShadowVecTy); for (unsigned i = 0; i != ShadowVecSize; ++i) { ShadowVec = IRB.CreateInsertElement( - ShadowVec, Shadow, ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); + ShadowVec, PrimaryShadow, + ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); } Value *ShadowVecAddr = IRB.CreateBitCast(ShadowAddr, PointerType::getUnqual(ShadowVecTy)); @@ -1433,8 +1807,8 @@ } while (Size > 0) { Value *CurShadowAddr = - IRB.CreateConstGEP1_32(DFS.ShadowTy, ShadowAddr, Offset); - IRB.CreateAlignedStore(Shadow, CurShadowAddr, ShadowAlign); + IRB.CreateConstGEP1_32(DFS.PrimaryShadowTy, ShadowAddr, Offset); + IRB.CreateAlignedStore(PrimaryShadow, CurShadowAddr, ShadowAlign); --Size; ++Offset; } @@ -1448,16 +1822,18 @@ const Align Alignment = ClPreserveAlignment ? SI.getAlign() : Align(1); - Value* Shadow = DFSF.getShadow(SI.getValueOperand()); + Value *Shadow = DFSF.getShadow(SI.getValueOperand()); if (ClCombinePointerLabelsOnStore) { Value *PtrShadow = DFSF.getShadow(SI.getPointerOperand()); - Shadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); + Shadow = DFSF.combineShadowsThenConvert(SI.getValueOperand()->getType(), + Shadow, PtrShadow, &SI); } DFSF.storeShadow(SI.getPointerOperand(), Size, Alignment, Shadow, &SI); if (ClEventCallbacks) { IRBuilder<> IRB(&SI); Value *Addr8 = IRB.CreateBitCast(SI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {Shadow, Addr8}); + Value *PrimaryShadow = DFSF.convertToPrimaryShadow(Shadow, &SI); + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimaryShadow, Addr8}); } } @@ -1496,11 +1872,29 @@ } void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) { - visitOperandShadowInst(I); + if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_Args) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *Agg = I.getAggregateOperand(); + Value *AggShadow = DFSF.getShadow(Agg); + Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices()); + DFSF.setShadow(&I, ResShadow); } void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) { - visitOperandShadowInst(I); + if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_Args) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *AggShadow = DFSF.getShadow(I.getAggregateOperand()); + Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand()); + Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices()); + DFSF.setShadow(&I, Res); } void DFSanVisitor::visitAllocaInst(AllocaInst &I) { @@ -1519,9 +1913,9 @@ } if (AllLoadsStores) { IRBuilder<> IRB(&I); - DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.ShadowTy); + DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.PrimaryShadowTy); } - DFSF.setShadow(&I, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&I, DFSF.DFS.ZeroPrimaryShadow); } void DFSanVisitor::visitSelectInst(SelectInst &I) { @@ -1531,7 +1925,8 @@ Value *ShadowSel = nullptr; if (isa(I.getCondition()->getType())) { - ShadowSel = DFSF.combineShadows(TrueShadow, FalseShadow, &I); + ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow, + FalseShadow, &I); } else { if (TrueShadow == FalseShadow) { ShadowSel = TrueShadow; @@ -1541,7 +1936,8 @@ } } DFSF.setShadow(&I, ClTrackSelectControlFlow - ? DFSF.combineShadows(CondShadow, ShadowSel, &I) + ? DFSF.combineShadowsThenConvert( + I.getType(), CondShadow, ShadowSel, &I) : ShadowSel); } @@ -1586,7 +1982,15 @@ case DataFlowSanitizer::IA_TLS: { Value *S = DFSF.getShadow(RI.getReturnValue()); IRBuilder<> IRB(&RI); - IRB.CreateStore(S, DFSF.DFS.RetvalTLS); + Type *RT = DFSF.F->getFunctionType()->getReturnType(); + unsigned Size = + getDataLayout().getTypeAllocSize(DFSF.DFS.getShadowTy(RT)); + if (Size <= kRetvalTLSSize) { + // If the size overflows, stores nothing. At callsite, oversized return + // shadows are set to zero. + IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB), + kShadowTLSAlignment); + } break; } case DataFlowSanitizer::IA_Args: { @@ -1626,11 +2030,11 @@ CB.setCalledFunction(F); IRB.CreateCall(DFSF.DFS.DFSanUnimplementedFn, IRB.CreateGlobalStringPtr(F->getName())); - DFSF.setShadow(&CB, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Discard: CB.setCalledFunction(F); - DFSF.setShadow(&CB, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Functional: CB.setCalledFunction(F); @@ -1682,10 +2086,10 @@ i = CB.arg_begin(); const unsigned ShadowArgStart = Args.size(); for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) - Args.push_back(DFSF.getShadow(*i)); + Args.push_back(DFSF.convertToPrimaryShadow(DFSF.getShadow(*i), &CB)); if (FT->isVarArg()) { - auto *LabelVATy = ArrayType::get(DFSF.DFS.ShadowTy, + auto *LabelVATy = ArrayType::get(DFSF.DFS.PrimaryShadowTy, CB.arg_size() - FT->getNumParams()); auto *LabelVAAlloca = new AllocaInst( LabelVATy, getDataLayout().getAllocaAddrSpace(), @@ -1693,7 +2097,9 @@ for (unsigned n = 0; i != CB.arg_end(); ++i, ++n) { auto LabelVAPtr = IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, n); - IRB.CreateStore(DFSF.getShadow(*i), LabelVAPtr); + IRB.CreateStore( + DFSF.convertToPrimaryShadow(DFSF.getShadow(*i), &CB), + LabelVAPtr); } Args.push_back(IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, 0)); @@ -1701,10 +2107,9 @@ if (!FT->getReturnType()->isVoidTy()) { if (!DFSF.LabelReturnAlloca) { - DFSF.LabelReturnAlloca = - new AllocaInst(DFSF.DFS.ShadowTy, - getDataLayout().getAllocaAddrSpace(), - "labelreturn", &DFSF.F->getEntryBlock().front()); + DFSF.LabelReturnAlloca = new AllocaInst( + DFSF.DFS.PrimaryShadowTy, getDataLayout().getAllocaAddrSpace(), + "labelreturn", &DFSF.F->getEntryBlock().front()); } Args.push_back(DFSF.LabelReturnAlloca); } @@ -1719,17 +2124,19 @@ // Update the parameter attributes of the custom call instruction to // zero extend the shadow parameters. This is required for targets - // which consider ShadowTy an illegal type. + // which consider PrimaryShadowTy an illegal type. for (unsigned n = 0; n < FT->getNumParams(); n++) { const unsigned ArgNo = ShadowArgStart + n; - if (CustomCI->getArgOperand(ArgNo)->getType() == DFSF.DFS.ShadowTy) + if (CustomCI->getArgOperand(ArgNo)->getType() == + DFSF.DFS.PrimaryShadowTy) CustomCI->addParamAttr(ArgNo, Attribute::ZExt); } if (!FT->getReturnType()->isVoidTy()) { LoadInst *LabelLoad = - IRB.CreateLoad(DFSF.DFS.ShadowTy, DFSF.LabelReturnAlloca); - DFSF.setShadow(CustomCI, LabelLoad); + IRB.CreateLoad(DFSF.DFS.PrimaryShadowTy, DFSF.LabelReturnAlloca); + DFSF.setShadow(CustomCI, DFSF.convertFromPrimaryShadow( + FT->getReturnType(), LabelLoad, &CB)); } CI->replaceAllUsesWith(CustomCI); @@ -1742,9 +2149,20 @@ FunctionType *FT = CB.getFunctionType(); if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { + unsigned ArgOffset = 0; + const DataLayout &DL = getDataLayout(); for (unsigned i = 0, n = FT->getNumParams(); i != n; ++i) { - IRB.CreateStore(DFSF.getShadow(CB.getArgOperand(i)), - DFSF.getArgTLS(i, &CB)); + unsigned Size = + DL.getTypeAllocSize(DFSF.DFS.getShadowTy(FT->getParamType(i))); + // Stop storing if arguments' size overflows. Inside a function, arguments + // after overflow have zero shadow values. + if (ArgOffset + Size > kArgTLSSize) + break; + IRB.CreateAlignedStore( + DFSF.getShadow(CB.getArgOperand(i)), + DFSF.getArgTLS(FT->getParamType(i), ArgOffset, IRB), + kShadowTLSAlignment); + ArgOffset += alignTo(Size, kShadowTLSAlignment); } } @@ -1765,10 +2183,19 @@ if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { IRBuilder<> NextIRB(Next); - LoadInst *LI = NextIRB.CreateLoad(DFSF.DFS.ShadowTy, DFSF.DFS.RetvalTLS); - DFSF.SkipInsts.insert(LI); - DFSF.setShadow(&CB, LI); - DFSF.NonZeroChecks.push_back(LI); + const DataLayout &DL = getDataLayout(); + unsigned Size = DL.getTypeAllocSize(DFSF.DFS.getShadowTy(&CB)); + if (Size > kRetvalTLSSize) { + // Set overflowed return shadow to be zero. + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); + } else { + LoadInst *LI = NextIRB.CreateAlignedLoad( + DFSF.DFS.getShadowTy(&CB), DFSF.getRetvalTLS(CB.getType(), NextIRB), + kShadowTLSAlignment, "_dfsret"); + DFSF.SkipInsts.insert(LI); + DFSF.setShadow(&CB, LI); + DFSF.NonZeroChecks.push_back(LI); + } } } @@ -1790,7 +2217,8 @@ if (FT->isVarArg()) { unsigned VarArgSize = CB.arg_size() - FT->getNumParams(); - ArrayType *VarArgArrayTy = ArrayType::get(DFSF.DFS.ShadowTy, VarArgSize); + ArrayType *VarArgArrayTy = + ArrayType::get(DFSF.DFS.PrimaryShadowTy, VarArgSize); AllocaInst *VarArgShadow = new AllocaInst(VarArgArrayTy, getDataLayout().getAllocaAddrSpace(), "", &DFSF.F->getEntryBlock().front()); @@ -1831,11 +2259,12 @@ } void DFSanVisitor::visitPHINode(PHINode &PN) { + Type *ShadowTy = DFSF.DFS.getShadowTy(PN.getType()); PHINode *ShadowPN = - PHINode::Create(DFSF.DFS.ShadowTy, PN.getNumIncomingValues(), "", &PN); + PHINode::Create(ShadowTy, PN.getNumIncomingValues(), "", &PN); // Give the shadow phi node valid predecessors to fool SplitEdge into working. - Value *UndefShadow = UndefValue::get(DFSF.DFS.ShadowTy); + Value *UndefShadow = UndefValue::get(ShadowTy); for (PHINode::block_iterator i = PN.block_begin(), e = PN.block_end(); i != e; ++i) { ShadowPN->addIncoming(UndefShadow, *i); diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/abilist_aggregate.ll b/llvm/test/Instrumentation/DataFlowSanitizer/abilist_aggregate.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/abilist_aggregate.ll @@ -0,0 +1,284 @@ +; RUN: opt < %s -dfsan -dfsan-abilist=%S/Inputs/abilist.txt -S | FileCheck %s --check-prefix=TLS_ABI +; RUN: opt < %s -dfsan -dfsan-args-abi -dfsan-abilist=%S/Inputs/abilist.txt -S | FileCheck %s --check-prefix=ARGS_ABI +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; TLS_ABI: define { i1, i7 } @functional({ i32, i1 } %a, [2 x i7] %b) +; ARGS_ABI: define { i1, i7 } @functional({ i32, i1 } %a, [2 x i7] %b) +define {i1, i7} @functional({i32, i1} %a, [2 x i7] %b) { + %a1 = extractvalue {i32, i1} %a, 1 + %b0 = extractvalue [2 x i7] %b, 0 + %r0 = insertvalue {i1, i7} undef, i1 %a1, 0 + %r1 = insertvalue {i1, i7} %r0, i7 %b0, 1 + ret {i1, i7} %r1 +} + +define {i1, i7} @call_functional({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_functional" + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[A01]], i16 zeroext [[B01]]) + ; TLS_ABI: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[A01]], {{.*}} ] + ; TLS_ABI: [[R0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[PH]], 0 + ; TLS_ABI: [[R1:%.*]] = insertvalue { i16, i16 } [[R0]], i16 [[PH]], 1 + ; TLS_ABI: store { i16, i16 } [[R1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + ; ARGS_ABI: @"dfs$call_functional" + ; ARGS_ABI: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext %2, i16 zeroext %3) + ; ARGS_ABI: [[PH:%.*]] = phi i16 [ %7, {{.*}} ], [ %2, {{.*}} ] + ; ARGS_ABI: [[R0:%.*]] = insertvalue { { i1, i7 }, i16 } undef, { i1, i7 } %r, 0 + ; ARGS_ABI: [[R1:%.*]] = insertvalue { { i1, i7 }, i16 } [[R0]], i16 [[PH]], 1 + ; ARGS_ABI: ret { { i1, i7 }, i16 } [[R1]] + + %r = call {i1, i7} @functional({i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +; TLS_ABI: define { i1, i7 } @discard({ i32, i1 } %a, [2 x i7] %b) +define {i1, i7} @discard({i32, i1} %a, [2 x i7] %b) { + %a1 = extractvalue {i32, i1} %a, 1 + %b0 = extractvalue [2 x i7] %b, 0 + %r0 = insertvalue {i1, i7} undef, i1 %a1, 0 + %r1 = insertvalue {i1, i7} %r0, i7 %b0, 1 + ret {i1, i7} %r1 +} + +define {i1, i7} @call_discard({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_discard" + ; TLS_ABI: store { i16, i16 } zeroinitializer, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + ; ARGS_ABI: @"dfs$call_discard" + ; ARGS_ABI: %r = call { i1, i7 } @discard({ i32, i1 } %0, [2 x i7] %1) + ; ARGS_ABI: [[R0:%.*]] = insertvalue { { i1, i7 }, i16 } undef, { i1, i7 } %r, 0 + ; ARGS_ABI: [[R1:%.*]] = insertvalue { { i1, i7 }, i16 } [[R0]], i16 0, 1 + ; ARGS_ABI: ret { { i1, i7 }, i16 } [[R1]] + + %r = call {i1, i7} @discard({i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +; TLS_ABI: define { i1, i7 } @uninstrumented({ i32, i1 } %a, [2 x i7] %b) +define {i1, i7} @uninstrumented({i32, i1} %a, [2 x i7] %b) { + %a1 = extractvalue {i32, i1} %a, 1 + %b0 = extractvalue [2 x i7] %b, 0 + %r0 = insertvalue {i1, i7} undef, i1 %a1, 0 + %r1 = insertvalue {i1, i7} %r0, i7 %b0, 1 + ret {i1, i7} %r1 +} + +define {i1, i7} @call_uninstrumented({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_uninstrumented" + ; TLS_ABI: call void @__dfsan_unimplemented + ; TLS_ABI: store { i16, i16 } zeroinitializer, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + ; ARGS_ABI: @"dfs$call_uninstrumented" + ; ARGS_ABI: call void @__dfsan_unimplemented + ; ARGS_ABI: %r = call { i1, i7 } @uninstrumented({ i32, i1 } %0, [2 x i7] %1) + ; ARGS_ABI: [[R0:%.*]] = insertvalue { { i1, i7 }, i16 } undef, { i1, i7 } %r, 0 + ; ARGS_ABI: [[R1:%.*]] = insertvalue { { i1, i7 }, i16 } [[R0]], i16 0, 1 + ; ARGS_ABI: ret { { i1, i7 }, i16 } [[R1]] + + %r = call {i1, i7} @uninstrumented({i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +define {i1, i7} @call_custom_with_ret({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_custom_with_ret" + ; TLS_ABI: %labelreturn = alloca i16, align 2 + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: [[R:%.*]] = call { i1, i7 } @__dfsw_custom_with_ret({ i32, i1 } %a, [2 x i7] %b, i16 zeroext [[A01]], i16 zeroext [[B01]], i16* %labelreturn) + ; TLS_ABI: [[RE:%.*]] = load i16, i16* %labelreturn, align 2 + ; TLS_ABI: [[RS0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[RE]], 0 + ; TLS_ABI: [[RS1:%.*]] = insertvalue { i16, i16 } [[RS0]], i16 [[RE]], 1 + ; TLS_ABI: store { i16, i16 } [[RS1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + ; TLS_ABI: ret { i1, i7 } [[R]] + + %r = call {i1, i7} @custom_with_ret({i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +define void @call_custom_without_ret({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_custom_without_ret" + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: call void @__dfsw_custom_without_ret({ i32, i1 } %a, [2 x i7] %b, i16 zeroext [[A01]], i16 zeroext [[B01]]) + + call void @custom_without_ret({i32, i1} %a, [2 x i7] %b) + ret void +} + +define void @call_custom_varg({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: @"dfs$call_custom_varg" + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: %labelva = alloca [1 x i16], align 2 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[V0:%.*]] = getelementptr inbounds [1 x i16], [1 x i16]* %labelva, i32 0, i32 0 + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: store i16 [[B01]], i16* [[V0]], align 2 + ; TLS_ABI: [[V:%.*]] = getelementptr inbounds [1 x i16], [1 x i16]* %labelva, i32 0, i32 0 + ; TLS_ABI: call void ({ i32, i1 }, i16, i16*, ...) @__dfsw_custom_varg({ i32, i1 } %a, i16 zeroext [[A01]], i16* [[V]], [2 x i7] %b) + + call void ({i32, i1}, ...) @custom_varg({i32, i1} %a, [2 x i7] %b) + ret void +} + +define {i1, i7} @call_custom_cb({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: define { i1, i7 } @"dfs$call_custom_cb"({ i32, i1 } %a, [2 x i7] %b) { + ; TLS_ABI: %labelreturn = alloca i16, align 2 + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: [[R:%.*]] = call { i1, i7 } @__dfsw_custom_cb({ i1, i7 } ({ i1, i7 } ({ i32, i1 }, [2 x i7])*, { i32, i1 }, [2 x i7], i16, i16, i16*)* @"dfst0$custom_cb", i8* bitcast ({ i1, i7 } ({ i32, i1 }, [2 x i7])* @"dfs$cb" to i8*), { i32, i1 } %a, [2 x i7] %b, i16 zeroext 0, i16 zeroext [[A01]], i16 zeroext [[B01]], i16* %labelreturn) + ; TLS_ABI: [[RE:%.*]] = load i16, i16* %labelreturn, align 2 + ; TLS_ABI: [[RS0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[RE]], 0 + ; TLS_ABI: [[RS1:%.*]] = insertvalue { i16, i16 } [[RS0]], i16 [[RE]], 1 + ; TLS_ABI: store { i16, i16 } [[RS1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %r = call {i1, i7} @custom_cb({i1, i7} ({i32, i1}, [2 x i7])* @cb, {i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +define {i1, i7} @custom_cb({i1, i7} ({i32, i1}, [2 x i7])* %cb, {i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: define { i1, i7 } @custom_cb({ i1, i7 } ({ i32, i1 }, [2 x i7])* %cb, { i32, i1 } %a, [2 x i7] %b) + ; TLS_ABI: store { i16, i16 } zeroinitializer, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: store [2 x i16] zeroinitializer, [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: %_dfsret = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %r = call {i1, i7} %cb({i32, i1} %a, [2 x i7] %b) + ret {i1, i7} %r +} + +define {i1, i7} @cb({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: define { i1, i7 } @"dfs$cb"({ i32, i1 } %a, [2 x i7] %b) + ; TLS_ABI: {{.*}} = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: {{.*}} = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: store { i16, i16 } {{.*}}, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %a1 = extractvalue {i32, i1} %a, 1 + %b0 = extractvalue [2 x i7] %b, 0 + %r0 = insertvalue {i1, i7} undef, i1 %a1, 0 + %r1 = insertvalue {i1, i7} %r0, i7 %b0, 1 + ret {i1, i7} %r1 +} + +define {i1, i7} ({i32, i1}, [2 x i7])* @ret_custom() { + ; TLS_ABI: @"dfs$ret_custom" + ; TLS_ABI: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + ; TLS_ABI: ret {{.*}} @"dfsw$custom_with_ret" + ret {i1, i7} ({i32, i1}, [2 x i7])* @custom_with_ret +} + +; TLS_ABI: define linkonce_odr { i1, i7 } @"dfsw$custom_cb"({ i1, i7 } ({ i32, i1 }, [2 x i7])* %0, { i32, i1 } %1, [2 x i7] %2) { +; TLS_ABI: %labelreturn = alloca i16, align 2 +; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 16) to [2 x i16]*), align 8 +; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to { i16, i16 }*), align 8 +; TLS_ABI: [[CB:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 +; TLS_ABI: [[CAST:%.*]] = bitcast { i1, i7 } ({ i32, i1 }, [2 x i7])* %0 to i8* +; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 +; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 +; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] +; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 +; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 +; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] +; TLS_ABI: [[R:%.*]] = call { i1, i7 } @__dfsw_custom_cb({ i1, i7 } ({ i1, i7 } ({ i32, i1 }, [2 x i7])*, { i32, i1 }, [2 x i7], i16, i16, i16*)* @"dfst0$custom_cb", i8* [[CAST]], { i32, i1 } %1, [2 x i7] %2, i16 zeroext [[CB]], i16 zeroext [[A01]], i16 zeroext [[B01]], i16* %labelreturn) +; TLS_ABI: [[RE:%.*]] = load i16, i16* %labelreturn, align 2 +; TLS_ABI: [[RS0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[RE]], 0 +; TLS_ABI: [[RS1:%.*]] = insertvalue { i16, i16 } [[RS0]], i16 [[RE]], 1 +; TLS_ABI: store { i16, i16 } [[RS1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + +define {i1, i7} @custom_with_ret({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: define linkonce_odr { i1, i7 } @"dfsw$custom_with_ret"({ i32, i1 } %0, [2 x i7] %1) + ; TLS_ABI: %labelreturn = alloca i16, align 2 + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: [[R:%.*]] = call { i1, i7 } @__dfsw_custom_with_ret({ i32, i1 } %0, [2 x i7] %1, i16 zeroext [[A01]], i16 zeroext [[B01]], i16* %labelreturn) + ; TLS_ABI: [[RE:%.*]] = load i16, i16* %labelreturn, align 2 + ; TLS_ABI: [[RS0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[RE]], 0 + ; TLS_ABI: [[RS1:%.*]] = insertvalue { i16, i16 } [[RS0]], i16 [[RE]], 1 + ; TLS_ABI: store { i16, i16 } [[RS1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + ; TLS_ABI: ret { i1, i7 } [[R]] + %a1 = extractvalue {i32, i1} %a, 1 + %b0 = extractvalue [2 x i7] %b, 0 + %r0 = insertvalue {i1, i7} undef, i1 %a1, 0 + %r1 = insertvalue {i1, i7} %r0, i7 %b0, 1 + ret {i1, i7} %r1 +} + +define void @custom_without_ret({i32, i1} %a, [2 x i7] %b) { + ; TLS_ABI: define linkonce_odr void @"dfsw$custom_without_ret"({ i32, i1 } %0, [2 x i7] %1) + ; TLS_ABI: [[B:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; TLS_ABI: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; TLS_ABI: [[A0:%.*]] = extractvalue { i16, i16 } [[A]], 0 + ; TLS_ABI: [[A1:%.*]] = extractvalue { i16, i16 } [[A]], 1 + ; TLS_ABI: [[A01:%.*]] = or i16 [[A0]], [[A1]] + ; TLS_ABI: [[B0:%.*]] = extractvalue [2 x i16] [[B]], 0 + ; TLS_ABI: [[B1:%.*]] = extractvalue [2 x i16] [[B]], 1 + ; TLS_ABI: [[B01:%.*]] = or i16 [[B0]], [[B1]] + ; TLS_ABI: call void @__dfsw_custom_without_ret({ i32, i1 } %0, [2 x i7] %1, i16 zeroext [[A01]], i16 zeroext [[B01]]) + ; TLS_ABI: ret + ret void +} + +define void @custom_varg({i32, i1} %a, ...) { + ; TLS_ABI: define linkonce_odr void @"dfsw$custom_varg"({ i32, i1 } %0, ...) + ; TLS_ABI: call void @__dfsan_vararg_wrapper + ; TLS_ABI: unreachable + ret void +} + +; TLS_ABI: declare { i1, i7 } @__dfsw_custom_with_ret({ i32, i1 }, [2 x i7], i16, i16, i16*) +; TLS_ABI: declare void @__dfsw_custom_without_ret({ i32, i1 }, [2 x i7], i16, i16) +; TLS_ABI: declare void @__dfsw_custom_varg({ i32, i1 }, i16, i16*, ...) + +; TLS_ABI: declare { i1, i7 } @__dfsw_custom_cb({ i1, i7 } ({ i1, i7 } ({ i32, i1 }, [2 x i7])*, { i32, i1 }, [2 x i7], i16, i16, i16*)*, i8*, { i32, i1 }, [2 x i7], i16, i16, i16, i16*) + +; TLS_ABI: define linkonce_odr { i1, i7 } @"dfst0$custom_cb"({ i1, i7 } ({ i32, i1 }, [2 x i7])* %0, { i32, i1 } %1, [2 x i7] %2, i16 %3, i16 %4, i16* %5) { +; TLS_ABI: [[A0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 %3, 0 +; TLS_ABI: [[A1:%.*]] = insertvalue { i16, i16 } [[A0]], i16 %3, 1 +; TLS_ABI: [[B0:%.*]] = insertvalue [2 x i16] zeroinitializer, i16 %4, 0 +; TLS_ABI: [[B1:%.*]] = insertvalue [2 x i16] [[B0]], i16 %4, 1 +; TLS_ABI: store { i16, i16 } [[A1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 +; TLS_ABI: store [2 x i16] [[B1]], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 +; TLS_ABI: [[R:%.*]] = call { i1, i7 } %0({ i32, i1 } %1, [2 x i7] %2) +; TLS_ABI: %_dfsret = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 +; TLS_ABI: [[RE0:%.*]] = extractvalue { i16, i16 } %_dfsret, 0 +; TLS_ABI: [[RE1:%.*]] = extractvalue { i16, i16 } %_dfsret, 1 +; TLS_ABI: [[RE01:%.*]] = or i16 [[RE0]], [[RE1]] +; TLS_ABI: store i16 [[RE01]], i16* %5, align 2 +; TLS_ABI: ret { i1, i7 } [[R]] diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/arith.ll b/llvm/test/Instrumentation/DataFlowSanitizer/arith.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/arith.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/arith.ll @@ -4,12 +4,12 @@ define i8 @add(i8 %a, i8 %b) { ; CHECK: @"dfs$add" - ; CHECK-DAG: %[[ALABEL:.*]] = load{{.*}}__dfsan_arg_tls, i64 0, i64 0 - ; CHECK-DAG: %[[BLABEL:.*]] = load{{.*}}__dfsan_arg_tls, i64 0, i64 1 - ; CHECK: %[[UNION:.*]] = call{{.*}}__dfsan_union(i16 zeroext %[[ALABEL]], i16 zeroext %[[BLABEL]]) - ; CHECK: %[[ADDLABEL:.*]] = phi i16 [ %[[UNION]], {{.*}} ], [ %[[ALABEL]], {{.*}} ] + ; CHECK-DAG: %[[ALABEL:.*]] = load [[ST:.*]], [[ST]]* bitcast ([[VT:\[.*\]]]* @__dfsan_arg_tls to [[ST]]*), align [[ALIGN:.*]] + ; CHECK-DAG: %[[BLABEL:.*]] = load [[ST]], [[ST]]* inttoptr (i64 add (i64 ptrtoint ([[VT]]* @__dfsan_arg_tls to i64), i64 8) to [[ST]]*), align [[ALIGN]] + ; CHECK: %[[UNION:.*]] = call zeroext [[ST]] @__dfsan_union([[ST]] zeroext %[[ALABEL]], [[ST]] zeroext %[[BLABEL]]) + ; CHECK: %[[ADDLABEL:.*]] = phi [[ST]] [ %[[UNION]], {{.*}} ], [ %[[ALABEL]], {{.*}} ] ; CHECK: add i8 - ; CHECK: store i16 %[[ADDLABEL]], i16* @__dfsan_retval_tls + ; CHECK: store [[ST]] %[[ADDLABEL]], [[ST]]* bitcast ([[VT]]* @__dfsan_retval_tls to [[ST]]*), align [[ALIGN]] ; CHECK: ret i8 %c = add i8 %a, %b ret i8 %c diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/array.ll b/llvm/test/Instrumentation/DataFlowSanitizer/array.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/array.ll @@ -0,0 +1,315 @@ +; RUN: opt < %s -dfsan -S | FileCheck %s --check-prefix=LEGACY +; RUN: opt < %s -dfsan -dfsan-event-callbacks=true -S | FileCheck %s --check-prefix=EVENT_CALLBACKS +; RUN: opt < %s -dfsan -dfsan-args-abi -S | FileCheck %s --check-prefix=ARGS_ABI +; RUN: opt < %s -dfsan -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=FAST16 +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-load=false -S | FileCheck %s --check-prefix=NO_COMBINE_LOAD_PTR +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-store=true -S | FileCheck %s --check-prefix=COMBINE_STORE_PTR +; RUN: opt < %s -dfsan -dfsan-debug-nonzero-labels -S | FileCheck %s --check-prefix=DEBUG_NONZERO_LABELS +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define [4 x i8] @pass_array([4 x i8] %a) { + ; NO_COMBINE_LOAD_PTR: @"dfs$pass_array" + ; NO_COMBINE_LOAD_PTR: %1 = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; NO_COMBINE_LOAD_PTR: store [4 x i16] %1, [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + + ; ARGS_ABI: @"dfs$pass_array" + ; ARGS_ABI: ret { [4 x i8], i16 } + + ; DEBUG_NONZERO_LABELS: @"dfs$pass_array" + ; DEBUG_NONZERO_LABELS: [[L:%.*]] = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; DEBUG_NONZERO_LABELS: [[L0:%.*]] = extractvalue [4 x i16] [[L]], 0 + ; DEBUG_NONZERO_LABELS: [[L1:%.*]] = extractvalue [4 x i16] [[L]], 1 + ; DEBUG_NONZERO_LABELS: [[L01:%.*]] = or i16 [[L0]], [[L1]] + ; DEBUG_NONZERO_LABELS: [[L2:%.*]] = extractvalue [4 x i16] [[L]], 2 + ; DEBUG_NONZERO_LABELS: [[L012:%.*]] = or i16 [[L01]], [[L2]] + ; DEBUG_NONZERO_LABELS: [[L3:%.*]] = extractvalue [4 x i16] [[L]], 3 + ; DEBUG_NONZERO_LABELS: [[L0123:%.*]] = or i16 [[L012]], [[L3]] + ; DEBUG_NONZERO_LABELS: {{.*}} = icmp ne i16 [[L0123]], 0 + ; DEBUG_NONZERO_LABELS: call void @__dfsan_nonzero_label() + + ret [4 x i8] %a +} + +%ArrayOfStruct = type [4 x {i8*, i32}] + +define %ArrayOfStruct @pass_array_of_struct(%ArrayOfStruct %as) { + ; NO_COMBINE_LOAD_PTR: @"dfs$pass_array_of_struct" + ; NO_COMBINE_LOAD_PTR: %1 = load [4 x { i16, i16 }], [4 x { i16, i16 }]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x { i16, i16 }]*), align 8 + ; NO_COMBINE_LOAD_PTR: store [4 x { i16, i16 }] %1, [4 x { i16, i16 }]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x { i16, i16 }]*), align 8 + + ; ARGS_ABI: @"dfs$pass_array_of_struct" + ; ARGS_ABI: ret { [4 x { i8*, i32 }], i16 } + ret %ArrayOfStruct %as +} + +define [4 x i1]* @alloca_ret_array() { + ; NO_COMBINE_LOAD_PTR: @"dfs$alloca_ret_array" + ; NO_COMBINE_LOAD_PTR: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %p = alloca [4 x i1] + ret [4 x i1]* %p +} + +define [4 x i1] @load_alloca_array() { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_alloca_array" + ; NO_COMBINE_LOAD_PTR: [[A:%.*]] = alloca i16, align 2 + ; NO_COMBINE_LOAD_PTR: [[M:%.*]] = load i16, i16* [[A]], align 2 + ; NO_COMBINE_LOAD_PTR: [[S0:%.*]] = insertvalue [4 x i16] zeroinitializer, i16 [[M]], 0 + ; NO_COMBINE_LOAD_PTR: [[S1:%.*]] = insertvalue [4 x i16] [[S0]], i16 [[M]], 1 + ; NO_COMBINE_LOAD_PTR: [[S2:%.*]] = insertvalue [4 x i16] [[S1]], i16 [[M]], 2 + ; NO_COMBINE_LOAD_PTR: [[S3:%.*]] = insertvalue [4 x i16] [[S2]], i16 [[M]], 3 + ; NO_COMBINE_LOAD_PTR: store [4 x i16] [[S3]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + %p = alloca [4 x i1] + %a = load [4 x i1], [4 x i1]* %p + ret [4 x i1] %a +} + +define [0 x i1] @load_array0([0 x i1]* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_array0" + ; NO_COMBINE_LOAD_PTR: store [0 x i16] zeroinitializer, [0 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [0 x i16]*), align 8 + %a = load [0 x i1], [0 x i1]* %p + ret [0 x i1] %a +} + +define [1 x i1] @load_array1([1 x i1]* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_array1" + ; NO_COMBINE_LOAD_PTR: [[L:%.*]] = load i16, + ; NO_COMBINE_LOAD_PTR: [[S:%.*]] = insertvalue [1 x i16] zeroinitializer, i16 [[L]], 0 + ; NO_COMBINE_LOAD_PTR: store [1 x i16] [[S]], [1 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [1 x i16]*), align 8 + + ; EVENT_CALLBACKS: @"dfs$load_array1" + ; EVENT_CALLBACKS: [[PH:%.*]] = phi i16 + ; EVENT_CALLBACKS: call void @__dfsan_load_callback(i16 [[PH]], i8* {{.*}}) + + ; LEGACY: @"dfs$load_array1" + ; LEGACY: [[P:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: [[L:%.*]] = load i16, i16* {{.*}}, align 2 + ; LEGACY: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[L]], i16 zeroext [[P]]) + ; LEGACY: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[L]], {{.*}} ] + ; LEGACY: [[S1:%.*]] = insertvalue [1 x i16] zeroinitializer, i16 [[PH]], 0 + ; LEGACY: store [1 x i16] [[S1]], [1 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [1 x i16]*), align 8 + %a = load [1 x i1], [1 x i1]* %p + ret [1 x i1] %a +} + +define [2 x i1] @load_array2([2 x i1]* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_array2" + ; NO_COMBINE_LOAD_PTR: [[P1:%.*]] = getelementptr i16, i16* [[P0:%.*]], i64 1 + ; NO_COMBINE_LOAD_PTR-DAG: [[E1:%.*]] = load i16, i16* [[P1]], align 2 + ; NO_COMBINE_LOAD_PTR-DAG: [[E0:%.*]] = load i16, i16* [[P0]], align 2 + ; NO_COMBINE_LOAD_PTR: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[E0]], i16 zeroext [[E1]]) + ; NO_COMBINE_LOAD_PTR: [[P:%.*]] = phi i16 [ [[U]] + ; NO_COMBINE_LOAD_PTR: [[S1:%.*]] = insertvalue [2 x i16] zeroinitializer, i16 [[P]], 0 + ; NO_COMBINE_LOAD_PTR: [[S2:%.*]] = insertvalue [2 x i16] [[S1]], i16 [[P]], 1 + ; NO_COMBINE_LOAD_PTR: store [2 x i16] [[S2]], [2 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [2 x i16]*), align 8 + + ; EVENT_CALLBACKS: @"dfs$load_array2" + ; EVENT_CALLBACKS: [[PH1:%.*]] = phi i16 + ; EVENT_CALLBACKS: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[PH1]] + ; EVENT_CALLBACKS: [[PH2:%.*]] = phi i16 [ [[U]] + ; EVENT_CALLBACKS: call void @__dfsan_load_callback(i16 [[PH2]], i8* {{.*}}) + + ; LEGACY: @"dfs$load_array2" + ; LEGACY: [[P:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: [[PH1:%.*]] = phi i16 + ; LEGACY: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[PH1]], i16 zeroext [[P]]) + ; LEGACY: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[PH1]], {{.*}} ] + ; LEGACY: [[S:%.*]] = insertvalue [2 x i16] zeroinitializer, i16 [[PH]], 0 + ; LEGACY: [[S1:%.*]] = insertvalue [2 x i16] [[S]], i16 [[PH]], 1 + ; LEGACY: store [2 x i16] [[S1]], [2 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [2 x i16]*), align 8 + %a = load [2 x i1], [2 x i1]* %p + ret [2 x i1] %a +} + +define [4 x i1] @load_array4([4 x i1]* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_array4" + ; NO_COMBINE_LOAD_PTR: [[P:%.*]] = phi i16 + ; NO_COMBINE_LOAD_PTR: [[S1:%.*]] = insertvalue [4 x i16] zeroinitializer, i16 [[P]], 0 + ; NO_COMBINE_LOAD_PTR: [[S2:%.*]] = insertvalue [4 x i16] [[S1]], i16 [[P]], 1 + ; NO_COMBINE_LOAD_PTR: [[S3:%.*]] = insertvalue [4 x i16] [[S2]], i16 [[P]], 2 + ; NO_COMBINE_LOAD_PTR: [[S4:%.*]] = insertvalue [4 x i16] [[S3]], i16 [[P]], 3 + ; NO_COMBINE_LOAD_PTR: store [4 x i16] [[S4]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + + ; EVENT_CALLBACKS: @"dfs$load_array4" + ; EVENT_CALLBACKS: [[PH1:%.*]] = phi i16 + ; EVENT_CALLBACKS: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[PH1]] + ; EVENT_CALLBACKS: [[PH2:%.*]] = phi i16 [ [[U]] + ; EVENT_CALLBACKS: call void @__dfsan_load_callback(i16 [[PH2]], i8* {{.*}}) + + ; FAST16: @"dfs$load_array4" + ; FAST16: [[T:%.*]] = trunc i64 {{.*}} to i16 + ; FAST16: [[O:%.*]] = or i16 [[T]] + ; FAST16: [[S1:%.*]] = insertvalue [4 x i16] zeroinitializer, i16 [[O]], 0 + ; FAST16: [[S2:%.*]] = insertvalue [4 x i16] [[S1]], i16 [[O]], 1 + ; FAST16: [[S3:%.*]] = insertvalue [4 x i16] [[S2]], i16 [[O]], 2 + ; FAST16: [[S4:%.*]] = insertvalue [4 x i16] [[S3]], i16 [[O]], 3 + ; FAST16: store [4 x i16] [[S4]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + + ; LEGACY: @"dfs$load_array4" + ; LEGACY: [[P:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: [[PH1:%.*]] = phi i16 + ; LEGACY: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[PH1]], i16 zeroext [[P]]) + ; LEGACY: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[PH1]], {{.*}} ] + ; LEGACY: [[S1:%.*]] = insertvalue [4 x i16] zeroinitializer, i16 [[PH]], 0 + ; LEGACY: [[S2:%.*]] = insertvalue [4 x i16] [[S1]], i16 [[PH]], 1 + ; LEGACY: [[S3:%.*]] = insertvalue [4 x i16] [[S2]], i16 [[PH]], 2 + ; LEGACY: [[S4:%.*]] = insertvalue [4 x i16] [[S3]], i16 [[PH]], 3 + ; LEGACY: store [4 x i16] [[S4]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + + %a = load [4 x i1], [4 x i1]* %p + ret [4 x i1] %a +} + +define i1 @extract_array([4 x i1] %a) { + ; NO_COMBINE_LOAD_PTR: @"dfs$extract_array" + ; NO_COMBINE_LOAD_PTR: [[AM:%.*]] = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; NO_COMBINE_LOAD_PTR: [[EM:%.*]] = extractvalue [4 x i16] [[AM]], 2 + ; NO_COMBINE_LOAD_PTR: store i16 [[EM]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %e2 = extractvalue [4 x i1] %a, 2 + ret i1 %e2 +} + +define [4 x i1] @insert_array([4 x i1] %a, i1 %e2) { + ; NO_COMBINE_LOAD_PTR: @"dfs$insert_array" + ; NO_COMBINE_LOAD_PTR: [[EM:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to i16*), align 8 + ; NO_COMBINE_LOAD_PTR: [[AM:%.*]] = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; NO_COMBINE_LOAD_PTR: [[AM1:%.*]] = insertvalue [4 x i16] [[AM]], i16 [[EM]], 0 + ; NO_COMBINE_LOAD_PTR: store [4 x i16] [[AM1]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + %a1 = insertvalue [4 x i1] %a, i1 %e2, 0 + ret [4 x i1] %a1 +} + +define void @store_alloca_array([4 x i1] %a) { + ; LEGACY: @"dfs$store_alloca_array" + ; LEGACY: [[S:%.*]] = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; LEGACY: [[SP:%.*]] = alloca i16, align 2 + ; LEGACY: [[E0:%.*]] = extractvalue [4 x i16] [[S]], 0 + ; LEGACY: [[E1:%.*]] = extractvalue [4 x i16] [[S]], 1 + ; LEGACY: [[E01:%.*]] = or i16 [[E0]], [[E1]] + ; LEGACY: [[E2:%.*]] = extractvalue [4 x i16] [[S]], 2 + ; LEGACY: [[E012:%.*]] = or i16 [[E01]], [[E2]] + ; LEGACY: [[E3:%.*]] = extractvalue [4 x i16] [[S]], 3 + ; LEGACY: [[E0123:%.*]] = or i16 [[E012]], [[E3]] + ; LEGACY: store i16 [[E0123]], i16* [[SP]], align 2 + %p = alloca [4 x i1] + store [4 x i1] %a, [4 x i1]* %p + ret void +} + +define void @store_zero_array([4 x i1]* %p) { + ; LEGACY: @"dfs$store_zero_array" + ; LEGACY: store i64 0, i64* {{.*}}, align 2 + store [4 x i1] zeroinitializer, [4 x i1]* %p + ret void +} + +define void @store_array2([2 x i1] %a, [2 x i1]* %p) { + ; LEGACY: @"dfs$store_array2" + ; LEGACY: [[S:%.*]] = load [2 x i16], [2 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [2 x i16]*), align 8 + ; LEGACY: [[E1:%.*]] = extractvalue [2 x i16] [[S]], 0 + ; LEGACY: [[E2:%.*]] = extractvalue [2 x i16] [[S]], 1 + ; LEGACY: [[E12:%.*]] = or i16 [[E1]], [[E2]] + ; LEGACY: [[SP0:%.*]] = getelementptr i16, i16* [[SP:%.*]], i32 0 + ; LEGACY: store i16 [[E12]], i16* [[SP0]], align 2 + ; LEGACY: [[SP1:%.*]] = getelementptr i16, i16* [[SP]], i32 1 + ; LEGACY: store i16 [[E12]], i16* [[SP1]], align 2 + + ; EVENT_CALLBACKS: @"dfs$store_array2" + ; EVENT_CALLBACKS: [[E12:%.*]] = or i16 + ; EVENT_CALLBACKS: [[P:%.*]] = bitcast [2 x i1]* %p to i8* + ; EVENT_CALLBACKS: call void @__dfsan_store_callback(i16 [[E12]], i8* [[P]]) + + ; FAST16: @"dfs$store_array2" + ; FAST16: [[S:%.*]] = load [2 x i16], [2 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [2 x i16]*), align 8 + ; FAST16: [[E1:%.*]] = extractvalue [2 x i16] [[S]], 0 + ; FAST16: [[E2:%.*]] = extractvalue [2 x i16] [[S]], 1 + ; FAST16: [[E12:%.*]] = or i16 [[E1]], [[E2]] + ; FAST16: [[SP0:%.*]] = getelementptr i16, i16* [[SP:%.*]], i32 0 + ; FAST16: store i16 [[E12]], i16* [[SP0]], align 2 + ; FAST16: [[SP1:%.*]] = getelementptr i16, i16* [[SP]], i32 1 + ; FAST16: store i16 [[E12]], i16* [[SP1]], align 2 + + ; COMBINE_STORE_PTR: @"dfs$store_array2" + ; COMBINE_STORE_PTR: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[E:%.*]], i16 zeroext {{.*}}) + ; COMBINE_STORE_PTR: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[E]], {{.*}} ] + ; COMBINE_STORE_PTR: [[P1:%.*]] = getelementptr i16, i16* [[P:%.*]], i32 0 + ; COMBINE_STORE_PTR: store i16 [[PH]], i16* [[P1]], align 2 + ; COMBINE_STORE_PTR: [[P2:%.*]] = getelementptr i16, i16* [[P]], i32 1 + ; COMBINE_STORE_PTR: store i16 [[PH]], i16* [[P2]], align 2 + + store [2 x i1] %a, [2 x i1]* %p + ret void +} + +define void @store_array17([17 x i1] %a, [17 x i1]* %p) { + ; LEGACY: @"dfs$store_array17" + ; LEGACY: [[E:%.*]] = extractvalue [17 x i16] {{.*}}, 16 + ; LEGACY: [[S:%.*]] = or i16 {{.*}}, [[E]] + ; LEGACY: [[V1:%.*]] = insertelement <8 x i16> undef, i16 [[S]], i32 0 + ; LEGACY: [[V2:%.*]] = insertelement <8 x i16> [[V1]], i16 [[S]], i32 1 + ; LEGACY: [[V3:%.*]] = insertelement <8 x i16> [[V2]], i16 [[S]], i32 2 + ; LEGACY: [[V4:%.*]] = insertelement <8 x i16> [[V3]], i16 [[S]], i32 3 + ; LEGACY: [[V5:%.*]] = insertelement <8 x i16> [[V4]], i16 [[S]], i32 4 + ; LEGACY: [[V6:%.*]] = insertelement <8 x i16> [[V5]], i16 [[S]], i32 5 + ; LEGACY: [[V7:%.*]] = insertelement <8 x i16> [[V6]], i16 [[S]], i32 6 + ; LEGACY: [[V8:%.*]] = insertelement <8 x i16> [[V7]], i16 [[S]], i32 7 + ; LEGACY: [[VP:%.*]] = bitcast i16* [[P:%.*]] to <8 x i16>* + ; LEGACY: [[VP1:%.*]] = getelementptr <8 x i16>, <8 x i16>* [[VP]], i32 0 + ; LEGACY: store <8 x i16> [[V8]], <8 x i16>* [[VP1]], align 2 + ; LEGACY: [[VP2:%.*]] = getelementptr <8 x i16>, <8 x i16>* [[VP]], i32 1 + ; LEGACY: store <8 x i16> [[V8]], <8 x i16>* [[VP2]], align 2 + ; LEGACY: [[P3:%.*]] = getelementptr i16, i16* [[P]], i32 16 + ; LEGACY: store i16 [[S]], i16* [[P3]], align 2 + store [17 x i1] %a, [17 x i1]* %p + ret void +} + +define [2 x i32] @const_array() { + ; LEGACY: @"dfs$const_array" + ; LEGACY: store [2 x i16] zeroinitializer, [2 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [2 x i16]*), align 8 + ret [2 x i32] [ i32 42, i32 11 ] +} + +define [4 x i8] @call_array([4 x i8] %a) { + ; LEGACY: @"dfs$call_array" + ; LEGACY: [[A:%.*]] = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; LEGACY: store [4 x i16] [[A]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_arg_tls to [4 x i16]*), align 8 + ; LEGACY: %_dfsret = load [4 x i16], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + ; LEGACY: store [4 x i16] %_dfsret, [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + + %r = call [4 x i8] @pass_array([4 x i8] %a) + ret [4 x i8] %r +} + +%LargeArr = type [1000 x i8] + +define i8 @fun_with_large_args(i1 %i, %LargeArr %a) { + ; LEGACY: @"dfs$fun_with_large_args" + ; LEGACY: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %r = extractvalue %LargeArr %a, 0 + ret i8 %r +} + +define %LargeArr @fun_with_large_ret() { + ; LEGACY: @"dfs$fun_with_large_ret" + ; LEGACY-NEXT: ret [1000 x i8] zeroinitializer + ret %LargeArr zeroinitializer +} + +define i8 @call_fun_with_large_ret() { + ; LEGACY: @"dfs$call_fun_with_large_ret" + ; LEGACY: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %r = call %LargeArr @fun_with_large_ret() + %e = extractvalue %LargeArr %r, 0 + ret i8 %e +} + +define i8 @call_fun_with_large_args(i1 %i, %LargeArr %a) { + ; LEGACY: @"dfs$call_fun_with_large_args" + ; LEGACY: [[I:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: store i16 [[I]], i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: %r = call i8 @"dfs$fun_with_large_args"(i1 %i, [1000 x i8] %a) + + %r = call i8 @fun_with_large_args(i1 %i, %LargeArr %a) + ret i8 %r +} diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/call.ll b/llvm/test/Instrumentation/DataFlowSanitizer/call.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/call.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/call.ll @@ -4,10 +4,10 @@ target triple = "x86_64-unknown-linux-gnu" ; CHECK-LABEL: @__dfsan_arg_tls -; CHECK: = external thread_local(initialexec) global [64 x i16] +; CHECK: = external thread_local(initialexec) global [100 x i64] ; CHECK-LABEL: @__dfsan_retval_tls -; CHECK: = external thread_local(initialexec) global i16 +; CHECK: = external thread_local(initialexec) global [100 x i64] declare i32 @f(i32) declare float @llvm.sqrt.f32(float) diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/callback.ll b/llvm/test/Instrumentation/DataFlowSanitizer/callback.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/callback.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/callback.ll @@ -22,8 +22,8 @@ define i1 @cmp(i8 %a, i8 %b) { ; CHECK: call void @__dfsan_cmp_callback(i16 %[[l:.*]]) ; CHECK: %c = icmp ne i8 %a, %b - ; CHECK: store i16 %[[l]], i16* @__dfsan_retval_tls + ; CHECK: store i16 %[[l]], i16* bitcast ({{.*}}* @__dfsan_retval_tls to i16*) %c = icmp ne i8 %a, %b ret i1 %c } \ No newline at end of file diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/fast16labels.ll b/llvm/test/Instrumentation/DataFlowSanitizer/fast16labels.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/fast16labels.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/fast16labels.ll @@ -6,11 +6,11 @@ define i8 @add(i8 %a, i8 %b) { ; CHECK-LABEL: define i8 @"dfs$add" - ; CHECK-DAG: %[[ALABEL:.*]] = load{{.*}}__dfsan_arg_tls, i64 0, i64 0 - ; CHECK-DAG: %[[BLABEL:.*]] = load{{.*}}__dfsan_arg_tls, i64 0, i64 1 + ; CHECK-DAG: %[[ALABEL:.*]] = load [[ST:.*]], [[ST]]* bitcast ([[VT:\[.*\]]]* @__dfsan_arg_tls to [[ST]]*), align [[ALIGN:.*]] + ; CHECK-DAG: %[[BLABEL:.*]] = load [[ST]], [[ST]]* inttoptr (i64 add (i64 ptrtoint ([[VT]]* @__dfsan_arg_tls to i64), i64 8) to [[ST]]*), align [[ALIGN]] ; CHECK: %[[ADDLABEL:.*]] = or i16 %[[ALABEL]], %[[BLABEL]] ; CHECK: add i8 - ; CHECK: store i16 %[[ADDLABEL]], i16* @__dfsan_retval_tls + ; CHECK: store [[ST]] %[[ADDLABEL]], [[ST]]* bitcast ([[VT]]* @__dfsan_retval_tls to [[ST]]*), align [[ALIGN]] ; CHECK: ret i8 %c = add i8 %a, %b ret i8 %c diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/load.ll b/llvm/test/Instrumentation/DataFlowSanitizer/load.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/load.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/load.ll @@ -166,3 +166,12 @@ %a = load i64, i64* %p ret i64 %a } + +@X = constant i1 1 +define i1 @load_global() { + ; NO_COMBINE_PTR_LABEL: @"dfs$load_global" + ; NO_COMBINE_PTR_LABEL: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + + %a = load i1, i1* @X + ret i1 %a +} \ No newline at end of file diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/phi.ll b/llvm/test/Instrumentation/DataFlowSanitizer/phi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/phi.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -dfsan -S | FileCheck %s +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define {i32, i32} @test({i32, i32} %a, i1 %c) { + ; CHECK: [[E0:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; CHECK: [[E1:%.*]] = insertvalue { i16, i16 } [[E0]], i16 0, 0 + ; CHECK: [[E2:%.*]] = insertvalue { i16, i16 } [[E0]], i16 0, 1 + ; CHECK: [[E3:%.*]] = phi { i16, i16 } [ [[E1]], %T ], [ [[E2]], %F ] + ; CHECK: store { i16, i16 } [[E3]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + +entry: + br i1 %c, label %T, label %F + +T: + %at = insertvalue {i32, i32} %a, i32 1, 0 + br label %done + +F: + %af = insertvalue {i32, i32} %a, i32 1, 1 + br label %done + +done: + %b = phi {i32, i32} [%at, %T], [%af, %F] + ret {i32, i32} %b +} diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/select.ll b/llvm/test/Instrumentation/DataFlowSanitizer/select.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/select.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/select.ll @@ -4,23 +4,23 @@ target triple = "x86_64-unknown-linux-gnu" define i8 @select8(i1 %c, i8 %t, i8 %f) { - ; TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 2) - ; TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; TRACK_CONTROL_FLOW: %3 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; TRACK_CONTROL_FLOW: %3 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; TRACK_CONTROL_FLOW: %4 = select i1 %c, i16 %2, i16 %1 ; TRACK_CONTROL_FLOW: %5 = icmp ne i16 %3, %4 ; TRACK_CONTROL_FLOW: %7 = call {{.*}} i16 @__dfsan_union(i16 {{.*}} %3, i16 {{.*}} %4) ; TRACK_CONTROL_FLOW: %9 = phi i16 [ %7, {{.*}} ], [ %3, {{.*}} ] ; TRACK_CONTROL_FLOW: %a = select i1 %c, i8 %t, i8 %f - ; TRACK_CONTROL_FLOW: store i16 %9, i16* @__dfsan_retval_tls + ; TRACK_CONTROL_FLOW: store i16 %9, {{.*}}@__dfsan_retval_tls{{.*}} ; TRACK_CONTROL_FLOW: ret i8 %a - ; NO_TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 2) - ; NO_TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; NO_TRACK_CONTROL_FLOW: %3 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; NO_TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; NO_TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; NO_TRACK_CONTROL_FLOW: %3 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: %4 = select i1 %c, i16 %2, i16 %1 ; NO_TRACK_CONTROL_FLOW: %a = select i1 %c, i8 %t, i8 %f - ; NO_TRACK_CONTROL_FLOW: store i16 %4, i16* @__dfsan_retval_tls + ; NO_TRACK_CONTROL_FLOW: store i16 %4, {{.*}}@__dfsan_retval_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: ret i8 %a %a = select i1 %c, i8 %t, i8 %f @@ -28,19 +28,19 @@ } define i8 @select8e(i1 %c, i8 %tf) { - ; TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; TRACK_CONTROL_FLOW: %3 = icmp ne i16 %2, %1 ; TRACK_CONTROL_FLOW: %5 = call {{.*}} i16 @__dfsan_union(i16 {{.*}} %2, i16 {{.*}} %1) ; TRACK_CONTROL_FLOW: %7 = phi i16 [ %5, {{.*}} ], [ %2, {{.*}} ] ; TRACK_CONTROL_FLOW: %a = select i1 %c, i8 %tf, i8 %tf - ; TRACK_CONTROL_FLOW: store i16 %7, i16* @__dfsan_retval_tls + ; TRACK_CONTROL_FLOW: store i16 %7, {{.*}}@__dfsan_retval_tls{{.*}} ; TRACK_CONTROL_FLOW: ret i8 %a - ; NO_TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; NO_TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; NO_TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; NO_TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: %a = select i1 %c, i8 %tf, i8 %tf - ; NO_TRACK_CONTROL_FLOW: store i16 %1, i16* @__dfsan_retval_tls + ; NO_TRACK_CONTROL_FLOW: store i16 %1, {{.*}}@__dfsan_retval_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: ret i8 %a %a = select i1 %c, i8 %tf, i8 %tf @@ -48,9 +48,9 @@ } define <4 x i8> @select8v(<4 x i1> %c, <4 x i8> %t, <4 x i8> %f) { - ; TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 2) - ; TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; TRACK_CONTROL_FLOW: %3 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; TRACK_CONTROL_FLOW: %3 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; TRACK_CONTROL_FLOW: %4 = icmp ne i16 %2, %1 ; TRACK_CONTROL_FLOW: %6 = call {{.*}} i16 @__dfsan_union(i16 {{.*}} %2, i16 zeroext %1) ; TRACK_CONTROL_FLOW: %8 = phi i16 [ %6, {{.*}} ], [ %2, {{.*}} ] @@ -58,19 +58,19 @@ ; TRACK_CONTROL_FLOW: %11 = call {{.*}} i16 @__dfsan_union(i16 {{.*}} %3, i16 zeroext %8) ; TRACK_CONTROL_FLOW: %13 = phi i16 [ %11, {{.*}} ], [ %3, {{.*}} ] ; TRACK_CONTROL_FLOW: %a = select <4 x i1> %c, <4 x i8> %t, <4 x i8> %f - ; TRACK_CONTROL_FLOW: store i16 %13, i16* @__dfsan_retval_tls + ; TRACK_CONTROL_FLOW: store i16 %13, {{.*}}@__dfsan_retval_tls{{.*}} ; TRACK_CONTROL_FLOW: ret <4 x i8> %a - ; NO_TRACK_CONTROL_FLOW: %1 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 2) - ; NO_TRACK_CONTROL_FLOW: %2 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 1) - ; NO_TRACK_CONTROL_FLOW: %3 = load i16, i16* getelementptr inbounds ([64 x i16], [64 x i16]* @__dfsan_arg_tls, i64 0, i64 0) + ; NO_TRACK_CONTROL_FLOW: %1 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; NO_TRACK_CONTROL_FLOW: %2 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} + ; NO_TRACK_CONTROL_FLOW: %3 = load i16, {{.*}}@__dfsan_arg_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: %4 = icmp ne i16 %2, %1 ; NO_TRACK_CONTROL_FLOW: %6 = call {{.*}} i16 @__dfsan_union(i16 {{.*}} %2, i16 {{.*}} %1) ; NO_TRACK_CONTROL_FLOW: %8 = phi i16 [ %6, {{.*}} ], [ %2, {{.*}} ] ; NO_TRACK_CONTROL_FLOW: %a = select <4 x i1> %c, <4 x i8> %t, <4 x i8> %f - ; NO_TRACK_CONTROL_FLOW: store i16 %8, i16* @__dfsan_retval_tls + ; NO_TRACK_CONTROL_FLOW: store i16 %8, {{.*}}@__dfsan_retval_tls{{.*}} ; NO_TRACK_CONTROL_FLOW: ret <4 x i8> %a %a = select <4 x i1> %c, <4 x i8> %t, <4 x i8> %f ret <4 x i8> %a } \ No newline at end of file diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/struct.ll b/llvm/test/Instrumentation/DataFlowSanitizer/struct.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/struct.ll @@ -0,0 +1,226 @@ +; RUN: opt < %s -dfsan -S | FileCheck %s --check-prefix=LEGACY +; RUN: opt < %s -dfsan -dfsan-event-callbacks=true -S | FileCheck %s --check-prefix=EVENT_CALLBACKS +; RUN: opt < %s -dfsan -dfsan-args-abi -S | FileCheck %s --check-prefix=ARGS_ABI +; RUN: opt < %s -dfsan -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=FAST16 +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-load=false -S | FileCheck %s --check-prefix=NO_COMBINE_LOAD_PTR +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-store=true -S | FileCheck %s --check-prefix=COMBINE_STORE_PTR +; RUN: opt < %s -dfsan -dfsan-track-select-control-flow=false -S | FileCheck %s --check-prefix=NO_SELECT_CONTROL +; RUN: opt < %s -dfsan -dfsan-debug-nonzero-labels -S | FileCheck %s --check-prefix=DEBUG_NONZERO_LABELS +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define {i8*, i32} @pass_struct({i8*, i32} %s) { + ; NO_COMBINE_LOAD_PTR: @"dfs$pass_struct" + ; NO_COMBINE_LOAD_PTR: %1 = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; NO_COMBINE_LOAD_PTR: store { i16, i16 } %1, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + ; ARGS_ABI: @"dfs$pass_struct" + ; ARGS_ABI: ret { { i8*, i32 }, i16 } + + ; DEBUG_NONZERO_LABELS: @"dfs$pass_struct" + ret {i8*, i32} %s +} + +%StructOfAggr = type {i8*, [4 x i2], <4 x i3>, {i1, i1}} + +define %StructOfAggr @pass_struct_of_aggregate(%StructOfAggr %s) { + ; NO_COMBINE_LOAD_PTR: @"dfs$pass_struct_of_aggregate" + ; NO_COMBINE_LOAD_PTR: %1 = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; NO_COMBINE_LOAD_PTR: store { i16, [4 x i16], i16, { i16, i16 } } %1, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + + ; ARGS_ABI: @"dfs$pass_struct_of_aggregate" + ; ARGS_ABI: ret { %StructOfAggr, i16 } + ret %StructOfAggr %s +} + +define {} @load_empty_struct({}* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_empty_struct" + ; NO_COMBINE_LOAD_PTR: store {} zeroinitializer, {}* bitcast ([100 x i64]* @__dfsan_retval_tls to {}*), align 8 + + ; EVENT_CALLBACKS: @"dfs$load_empty_struct" + ; FAST16: @"dfs$load_empty_struct" + ; COMBINE_STORE_PTR: @"dfs$load_empty_struct" + + %a = load {}, {}* %p + ret {} %a +} + +@Y = constant {i1, i32} {i1 1, i32 1} + +define {i1, i32} @load_global_struct() { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_global_struct" + ; NO_COMBINE_LOAD_PTR: store { i16, i16 } zeroinitializer, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %a = load {i1, i32}, {i1, i32}* @Y + ret {i1, i32} %a +} + +define {i1, i32} @select_struct(i1 %c, {i1, i32} %a, {i1, i32} %b) { + ; NO_SELECT_CONTROL: @"dfs$select_struct" + ; NO_SELECT_CONTROL: [[B:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 16) to { i16, i16 }*), align 8 + ; NO_SELECT_CONTROL: [[A:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to { i16, i16 }*), align 8 + ; NO_SELECT_CONTROL: [[C:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; NO_SELECT_CONTROL: [[S:%.*]] = select i1 %c, { i16, i16 } [[A]], { i16, i16 } [[B]] + ; NO_SELECT_CONTROL: store { i16, i16 } [[S]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + ; LEGACY: @"dfs$select_struct" + ; LEGACY: [[U:%.*]] = call zeroext i16 @__dfsan_union + ; LEGACY: [[P:%.*]] = phi i16 [ [[U]], + ; LEGACY: [[S1:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[P]], 0 + ; LEGACY: [[S2:%.*]] = insertvalue { i16, i16 } [[S1]], i16 [[P]], 1 + ; LEGACY: store { i16, i16 } [[S2]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %s = select i1 %c, {i1, i32} %a, {i1, i32} %b + ret {i1, i32} %s +} + +define { i32, i32 } @asm_struct(i32 %0, i32 %1) { + ; LEGACY: @"dfs$asm_struct" + ; LEGACY: [[E1:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to i16*), align 8 + ; LEGACY: [[E0:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: [[E01:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[E0]], i16 zeroext [[E1]]) + ; LEGACY: [[P:%.*]] = phi i16 [ [[E01]], {{.*}} ], [ [[E0]], {{.*}} ] + ; LEGACY: [[S0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[P]], 0 + ; LEGACY: [[S1:%.*]] = insertvalue { i16, i16 } [[S0]], i16 [[P]], 1 + ; LEGACY: store { i16, i16 } [[S1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + +entry: + %a = call { i32, i32 } asm "", "=r,=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1) + ret { i32, i32 } %a +} + +define {i32, i32} @const_struct() { + ; LEGACY: @"dfs$const_struct" + ; LEGACY: store { i16, i16 } zeroinitializer, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + ret {i32, i32} { i32 42, i32 11 } +} + +define i1 @extract_struct({i1, i5} %s) { + ; LEGACY: @"dfs$extract_struct" + ; LEGACY: [[SM:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; LEGACY: [[EM:%.*]] = extractvalue { i16, i16 } [[SM]], 0 + ; LEGACY: store i16 [[EM]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %e2 = extractvalue {i1, i5} %s, 0 + ret i1 %e2 +} + +define {i1, i5} @insert_struct({i1, i5} %s, i5 %e1) { + ; LEGACY: @"dfs$insert_struct" + ; LEGACY: [[EM:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to i16*), align 8 + ; LEGACY: [[SM:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; LEGACY: [[SM1:%.*]] = insertvalue { i16, i16 } [[SM]], i16 [[EM]], 1 + ; LEGACY: store { i16, i16 } [[SM1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + %s1 = insertvalue {i1, i5} %s, i5 %e1, 1 + ret {i1, i5} %s1 +} + +define {i1, i1} @load_struct({i1, i1}* %p) { + ; NO_COMBINE_LOAD_PTR: @"dfs$load_struct" + ; NO_COMBINE_LOAD_PTR: [[PH:%.*]] = phi i16 + ; NO_COMBINE_LOAD_PTR: [[S0:%.*]] = insertvalue { i16, i16 } zeroinitializer, i16 [[PH]], 0 + ; NO_COMBINE_LOAD_PTR: [[S1:%.*]] = insertvalue { i16, i16 } [[S0]], i16 [[PH]], 1 + ; NO_COMBINE_LOAD_PTR: store { i16, i16 } [[S1]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %s = load {i1, i1}, {i1, i1}* %p + ret {i1, i1} %s +} + +define void @store_struct({i1, i1}* %p, {i1, i1} %s) { + ; LEGACY: @"dfs$store_struct" + ; LEGACY: [[S:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to { i16, i16 }*), align 8 + ; LEGACY: [[E0:%.*]] = extractvalue { i16, i16 } [[S]], 0 + ; LEGACY: [[E1:%.*]] = extractvalue { i16, i16 } [[S]], 1 + ; LEGACY: [[E:%.*]] = or i16 [[E0]], [[E1]] + ; LEGACY-NEXT: [[P0:%.*]] = getelementptr i16, i16* [[P:%.*]], i32 0 + ; LEGACY: store i16 [[E]], i16* [[P0]], align 2 + ; LEGACY: [[P1:%.*]] = getelementptr i16, i16* [[P]], i32 1 + ; LEGACY: store i16 [[E]], i16* [[P1]], align 2 + + store {i1, i1} %s, {i1, i1}* %p + ret void +} + +define i2 @extract_struct_of_aggregate11(%StructOfAggr %s) { + ; LEGACY: @"dfs$extract_struct_of_aggregate11" + ; LEGACY: [[E:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[E11:%.*]] = extractvalue { i16, [4 x i16], i16, { i16, i16 } } [[E]], 1, 1 + ; LEGACY: store i16 [[E11]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + + %e11 = extractvalue %StructOfAggr %s, 1, 1 + ret i2 %e11 +} + +define [4 x i2] @extract_struct_of_aggregate1(%StructOfAggr %s) { + ; LEGACY: @"dfs$extract_struct_of_aggregate1" + ; LEGACY: [[E:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[E1:%.*]] = extractvalue { i16, [4 x i16], i16, { i16, i16 } } [[E]], 1 + ; LEGACY: store [4 x i16] [[E1]], [4 x i16]* bitcast ([100 x i64]* @__dfsan_retval_tls to [4 x i16]*), align 8 + %e1 = extractvalue %StructOfAggr %s, 1 + ret [4 x i2] %e1 +} + +define <4 x i3> @extract_struct_of_aggregate2(%StructOfAggr %s) { + ; LEGACY: @"dfs$extract_struct_of_aggregate2" + ; LEGACY: [[E:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[E2:%.*]] = extractvalue { i16, [4 x i16], i16, { i16, i16 } } [[E]], 2 + ; LEGACY: store i16 [[E2]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %e2 = extractvalue %StructOfAggr %s, 2 + ret <4 x i3> %e2 +} + +define { i1, i1 } @extract_struct_of_aggregate3(%StructOfAggr %s) { + ; LEGACY: @"dfs$extract_struct_of_aggregate3" + ; LEGACY: [[E:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[E3:%.*]] = extractvalue { i16, [4 x i16], i16, { i16, i16 } } [[E]], 3 + ; LEGACY: store { i16, i16 } [[E3]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + %e3 = extractvalue %StructOfAggr %s, 3 + ret { i1, i1 } %e3 +} + +define i1 @extract_struct_of_aggregate31(%StructOfAggr %s) { + ; LEGACY: @"dfs$extract_struct_of_aggregate31" + ; LEGACY: [[E:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[E31:%.*]] = extractvalue { i16, [4 x i16], i16, { i16, i16 } } [[E]], 3, 1 + ; LEGACY: store i16 [[E31]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + %e31 = extractvalue %StructOfAggr %s, 3, 1 + ret i1 %e31 +} + +define %StructOfAggr @insert_struct_of_aggregate11(%StructOfAggr %s, i2 %e11) { + ; LEGACY: @"dfs$insert_struct_of_aggregate11" + ; LEGACY: [[E11:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 16) to i16*), align 8 + ; LEGACY: [[S:%.*]] = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: [[S1:%.*]] = insertvalue { i16, [4 x i16], i16, { i16, i16 } } [[S]], i16 [[E11]], 1, 1 + ; LEGACY: store { i16, [4 x i16], i16, { i16, i16 } } [[S1]], { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + + %s1 = insertvalue %StructOfAggr %s, i2 %e11, 1, 1 + ret %StructOfAggr %s1 +} + +define {i8*, i32} @call_struct({i8*, i32} %s) { + ; LEGACY: @"dfs$call_struct" + ; LEGACY: [[S:%.*]] = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; LEGACY: store { i16, i16 } [[S]], { i16, i16 }* bitcast ([100 x i64]* @__dfsan_arg_tls to { i16, i16 }*), align 8 + ; LEGACY: %_dfsret = load { i16, i16 }, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + ; LEGACY: store { i16, i16 } %_dfsret, { i16, i16 }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, i16 }*), align 8 + + %r = call {i8*, i32} @pass_struct({i8*, i32} %s) + ret {i8*, i32} %r +} + +declare %StructOfAggr @fun_with_mang_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s) + +define %StructOfAggr @call_many_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s) { + ; LEGACY: @"dfs$call_many_aggr_args" + ; LEGACY: [[S:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 16) to { i16, i16 }*), align 8 + ; LEGACY: [[A:%.*]] = load [2 x i16], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; LEGACY: [[V:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: store i16 [[V]], i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: store [2 x i16] [[A]], [2 x i16]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to [2 x i16]*), align 8 + ; LEGACY: store { i16, i16 } [[S]], { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 16) to { i16, i16 }*), align 8 + ; LEGACY: %_dfsret = load { i16, [4 x i16], i16, { i16, i16 } }, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + ; LEGACY: store { i16, [4 x i16], i16, { i16, i16 } } %_dfsret, { i16, [4 x i16], i16, { i16, i16 } }* bitcast ([100 x i64]* @__dfsan_retval_tls to { i16, [4 x i16], i16, { i16, i16 } }*), align 8 + + %r = call %StructOfAggr @fun_with_mang_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s) + ret %StructOfAggr %r +} \ No newline at end of file diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/union-large.ll b/llvm/test/Instrumentation/DataFlowSanitizer/union-large.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/union-large.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/union-large.ll @@ -5,7 +5,7 @@ ; Check that we use dfsan_union in large functions instead of __dfsan_union. ; CHECK-LABEL: @"dfs$foo" -define i32 @foo(i32 %a, i32 %b) { +define {i32, i32} @foo(i1 %c, {i32, i32} %a, {i32, i32} %b) { bb0: br label %bb1 @@ -3009,6 +3009,6 @@ bb1000: ; CHECK: call{{.*}}@dfsan_union ; CHECK-NOT: phi - %ab = mul i32 %a, %b - ret i32 %ab + %ab = select i1 %c, {i32, i32} %a, {i32, i32} %b + ret {i32, i32} %ab } diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/vector.ll b/llvm/test/Instrumentation/DataFlowSanitizer/vector.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/vector.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -dfsan -S | FileCheck %s --check-prefix=LEGACY +; RUN: opt < %s -dfsan -dfsan-event-callbacks=true -S | FileCheck %s --check-prefix=EVENT_CALLBACKS +; RUN: opt < %s -dfsan -dfsan-args-abi -S | FileCheck %s --check-prefix=ARGS_ABI +; RUN: opt < %s -dfsan -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=FAST16 +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-load=false -S | FileCheck %s --check-prefix=NO_COMBINE_LOAD_PTR +; RUN: opt < %s -dfsan -dfsan-combine-pointer-labels-on-store=true -S | FileCheck %s --check-prefix=COMBINE_STORE_PTR +; RUN: opt < %s -dfsan -dfsan-debug-nonzero-labels -S | FileCheck %s --check-prefix=DEBUG_NONZERO_LABELS +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define <4 x i4> @pass_vector(<4 x i4> %v) { + ; NO_COMBINE_LOAD_PTR: @"dfs$pass_vector" + ; NO_COMBINE_LOAD_PTR: %1 = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; NO_COMBINE_LOAD_PTR: store i16 %1, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + + ; ARGS_ABI: @"dfs$pass_vector" + ; ARGS_ABI: ret { <4 x i4>, i16 } + ret <4 x i4> %v +} + +define void @load_update_store_vector(<4 x i4>* %p) { + ; EVENT_CALLBACKS: @"dfs$load_update_store_vector" + ; FAST16: @"dfs$load_update_store_vector" + ; COMBINE_STORE_PTR: @"dfs$load_update_store_vector" + ; DEBUG_NONZERO_LABELS: @"dfs$load_update_store_vector" + + %v = load <4 x i4>, <4 x i4>* %p + %e2 = extractelement <4 x i4> %v, i32 2 + %v1 = insertelement <4 x i4> %v, i4 %e2, i32 0 + store <4 x i4> %v1, <4 x i4>* %p + ret void +} + +define <4 x i1> @icmp_vector(<4 x i8> %a, <4 x i8> %b) { + ; LEGACY: @"dfs$icmp_vector" + ; LEGACY: [[B:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 8) to i16*), align 8 + ; LEGACY: [[A:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: [[U:%.*]] = call zeroext i16 @__dfsan_union(i16 zeroext [[A]], i16 zeroext [[B]]) + ; LEGACY: [[PH:%.*]] = phi i16 [ [[U]], {{.*}} ], [ [[A]], {{.*}} ] + ; LEGACY: store i16 [[PH]], i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + + %r = icmp eq <4 x i8> %a, %b + ret <4 x i1> %r +} + +define <2 x i32> @const_vector() { + ; LEGACY: @"dfs$const_vector" + ; LEGACY: store i16 0, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + ret <2 x i32> < i32 42, i32 11 > +} + +define <4 x i4> @call_vector(<4 x i4> %v) { + ; LEGACY: @"dfs$call_vector" + ; LEGACY: [[V:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: store i16 [[V]], i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 8 + ; LEGACY: %_dfsret = load i16, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + ; LEGACY: store i16 %_dfsret, i16* bitcast ([100 x i64]* @__dfsan_retval_tls to i16*), align 8 + + %r = call <4 x i4> @pass_vector(<4 x i4> %v) + ret <4 x i4> %r +} + +