Skip to content

Commit b218336

Browse files
Matthew NagygbMattN
authored andcommitted
[TySan] Add option to outline instrumentation
1 parent 1a48e1d commit b218336

File tree

5 files changed

+283
-29
lines changed

5 files changed

+283
-29
lines changed

compiler-rt/lib/tysan/tysan.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "tysan/tysan.h"
2424

25+
#include <stdint.h>
2526
#include <string.h>
2627

2728
using namespace __sanitizer;
@@ -222,6 +223,64 @@ static void reportError(void *Addr, int Size, tysan_type_descriptor *TD,
222223
}
223224
}
224225

226+
ALWAYS_INLINE
227+
static void SetShadowType(tysan_type_descriptor *td,
228+
tysan_type_descriptor **shadowData,
229+
uint64_t AccessSize) {
230+
*shadowData = td;
231+
uint64_t shadowDataInt = (uint64_t)shadowData;
232+
233+
for (uint64_t i = 1; i < AccessSize; ++i) {
234+
int64_t dataOffset = i << PtrShift();
235+
int64_t *badShadowData = (int64_t *)(shadowDataInt + dataOffset);
236+
int64_t badTD = int64_t(i) * -1;
237+
*badShadowData = badTD;
238+
}
239+
}
240+
241+
ALWAYS_INLINE
242+
static bool GetNotAllBadTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
243+
bool notAllBadTD = false;
244+
for (uint64_t i = 1; i < AccessSize; ++i) {
245+
int64_t **unkShadowData = (int64_t **)(ShadowDataInt + (i << PtrShift()));
246+
int64_t *ILdTD = *unkShadowData;
247+
notAllBadTD = notAllBadTD || (ILdTD != nullptr);
248+
}
249+
return notAllBadTD;
250+
}
251+
252+
ALWAYS_INLINE
253+
static bool GetNotAllUnkTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
254+
bool notAllBadTD = false;
255+
for (uint64_t i = 1; i < AccessSize; ++i) {
256+
int64_t *badShadowData = (int64_t *)(ShadowDataInt + (i << PtrShift()));
257+
int64_t ILdTD = *badShadowData;
258+
notAllBadTD = notAllBadTD || (ILdTD >= 0);
259+
}
260+
return notAllBadTD;
261+
}
262+
263+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
264+
__tysan_instrument_mem_inst(char *dest, char *src, uint64_t size,
265+
bool needsMemMove) {
266+
tysan_type_descriptor **destShadowDataPtr = shadow_for(dest);
267+
268+
if(!src){
269+
internal_memset((char*) destShadowDataPtr, 0, size << PtrShift());
270+
return;
271+
}
272+
273+
uint64_t srcInt = (uint64_t)src;
274+
uint64_t srcShadowInt = ((srcInt & AppMask()) << PtrShift()) + ShadowAddr();
275+
uint64_t *srcShadow = (uint64_t *)srcShadowInt;
276+
277+
if (needsMemMove) {
278+
internal_memmove((char*) destShadowDataPtr, srcShadow, size << PtrShift());
279+
} else {
280+
internal_memcpy((char*) destShadowDataPtr, srcShadow, size << PtrShift());
281+
}
282+
}
283+
225284
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
226285
__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
227286
GET_CALLER_PC_BP_SP;
@@ -268,6 +327,54 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
268327
}
269328
}
270329

330+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
331+
__tysan_instrument_with_shadow_update(void *ptr, tysan_type_descriptor *td,
332+
bool sanitizeFunction,
333+
uint64_t accessSize, int flags) {
334+
tysan_type_descriptor **shadowData = shadow_for(ptr);
335+
tysan_type_descriptor *loadedTD = *shadowData;
336+
bool shadowIsNull = loadedTD == nullptr;
337+
338+
// TODO, sanitizeFunction is known at compile time, so maybe this is split
339+
// into two different functions
340+
if (sanitizeFunction) {
341+
342+
if (td != loadedTD) {
343+
344+
// We now know that the types did not match (we're on the slow path). If
345+
// the type is unknown, then set it.
346+
if (shadowIsNull) {
347+
// We're about to set the type. Make sure that all bytes in the value
348+
// are also of unknown type.
349+
bool isAllUnknownTD = GetNotAllUnkTD((uint64_t)shadowData, accessSize);
350+
if (isAllUnknownTD)
351+
__tysan_check(ptr, accessSize, td, flags);
352+
SetShadowType(td, shadowData, accessSize);
353+
} else {
354+
__tysan_check(ptr, accessSize, td, flags);
355+
}
356+
} else {
357+
// We appear to have the right type. Make sure that all other bytes in
358+
// the type are still marked as interior bytes. If not, call the runtime.
359+
bool isNotAllBadTD = GetNotAllBadTD((uint64_t)shadowData, accessSize);
360+
if (isNotAllBadTD) {
361+
__tysan_check(ptr, accessSize, td, flags);
362+
}
363+
}
364+
} else if (shadowIsNull) {
365+
SetShadowType(td, shadowData, accessSize);
366+
}
367+
}
368+
369+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
370+
__tysan_set_shadow_type(void *ptr, tysan_type_descriptor *td,
371+
uint64_t accessSize) {
372+
// In the mode where writes always set the type, for a write (which does
373+
// not also read), we just set the type.
374+
tysan_type_descriptor **shadow = shadow_for(ptr);
375+
SetShadowType(td, shadow, accessSize);
376+
}
377+
271378
Flags __tysan::flags_data;
272379

273380
SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address;

compiler-rt/lib/tysan/tysan_platform.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,28 @@ struct Mapping {
2121
static const uptr kShadowAddr = 0x010000000000ull;
2222
static const uptr kAppAddr = 0x550000000000ull;
2323
static const uptr kAppMemMsk = ~0x780000000000ull;
24+
static const uptr kPtrShift = 3;
2425
};
2526
#elif defined(__aarch64__)
2627
struct Mapping39 {
2728
static const uptr kShadowAddr = 0x0800000000ull;
2829
static const uptr kAppAddr = 0x5500000000ull;
2930
static const uptr kAppMemMsk = ~0x7800000000ull;
31+
static const uptr kPtrShift = 3;
3032
};
3133

3234
struct Mapping42 {
3335
static const uptr kShadowAddr = 0x10000000000ull;
3436
static const uptr kAppAddr = 0x2aa00000000ull;
3537
static const uptr kAppMemMsk = ~0x3c000000000ull;
38+
static const uptr kPtrShift = 3;
3639
};
3740

3841
struct Mapping48 {
3942
static const uptr kShadowAddr = 0x0002000000000ull;
4043
static const uptr kAppAddr = 0x0aaaa00000000ull;
4144
static const uptr kAppMemMsk = ~0x0fff800000000ull;
45+
static const uptr kPtrShift = 3;
4246
};
4347
#define TYSAN_RUNTIME_VMA 1
4448
#else
@@ -49,7 +53,12 @@ struct Mapping48 {
4953
extern int vmaSize;
5054
#endif
5155

52-
enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK };
56+
enum MappingType {
57+
MAPPING_SHADOW_ADDR,
58+
MAPPING_APP_ADDR,
59+
MAPPING_APP_MASK,
60+
MAPPING_PTR_SHIFT
61+
};
5362

5463
template <typename Mapping, int Type> uptr MappingImpl(void) {
5564
switch (Type) {
@@ -59,6 +68,8 @@ template <typename Mapping, int Type> uptr MappingImpl(void) {
5968
return Mapping::kAppAddr;
6069
case MAPPING_APP_MASK:
6170
return Mapping::kAppMemMsk;
71+
case MAPPING_PTR_SHIFT:
72+
return Mapping::kPtrShift;
6273
}
6374
}
6475

@@ -88,6 +99,9 @@ uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); }
8899
ALWAYS_INLINE
89100
uptr AppMask() { return MappingArchImpl<MAPPING_APP_MASK>(); }
90101

102+
ALWAYS_INLINE
103+
uptr PtrShift() { return MappingArchImpl<MAPPING_PTR_SHIFT>(); }
104+
91105
} // namespace __tysan
92106

93107
#endif

llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ static cl::opt<bool>
6262
cl::desc("Writes always set the type"), cl::Hidden,
6363
cl::init(false));
6464

65+
static cl::opt<bool> ClOutlineInstrumentation(
66+
"tysan-outline-instrumentation",
67+
cl::desc("Uses function calls for all TySan instrumentation, reducing "
68+
"ELF size"),
69+
cl::Hidden, cl::init(false));
70+
6571
STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses");
6672

6773
namespace {
@@ -109,12 +115,16 @@ struct TypeSanitizer {
109115
Regex AnonNameRegex;
110116
Type *IntptrTy;
111117
uint64_t PtrShift;
112-
IntegerType *OrdTy;
118+
IntegerType *OrdTy, *U64Ty;
113119

114120
/// Callbacks to run-time library are computed in initializeCallbacks.
115121
FunctionCallee TysanCheck;
116122
FunctionCallee TysanCtorFunction;
117123

124+
FunctionCallee TysanIntrumentMemInst;
125+
FunctionCallee TysanInstrumentWithShadowUpdate;
126+
FunctionCallee TysanSetShadowType;
127+
118128
/// Callback to set types for gloabls.
119129
Function *TysanGlobalsSetTypeFunction;
120130
};
@@ -134,6 +144,8 @@ TypeSanitizer::TypeSanitizer(Module &M)
134144
void TypeSanitizer::initializeCallbacks(Module &M) {
135145
IRBuilder<> IRB(M.getContext());
136146
OrdTy = IRB.getInt32Ty();
147+
U64Ty = IRB.getInt64Ty();
148+
Type *BoolType = IRB.getInt1Ty();
137149

138150
AttributeList Attr;
139151
Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind);
@@ -148,6 +160,30 @@ void TypeSanitizer::initializeCallbacks(Module &M) {
148160

149161
TysanCtorFunction =
150162
M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy());
163+
164+
TysanIntrumentMemInst =
165+
M.getOrInsertFunction("__tysan_instrument_mem_inst", Attr, IRB.getVoidTy(),
166+
IRB.getPtrTy(), // Pointer of data to be written to
167+
IRB.getPtrTy(), // Pointer of data to write
168+
U64Ty, // Size of the data in bytes
169+
BoolType // Do we need to call memmove
170+
);
171+
172+
TysanInstrumentWithShadowUpdate =
173+
M.getOrInsertFunction("__tysan_instrument_with_shadow_update", Attr, IRB.getVoidTy(),
174+
IRB.getPtrTy(), // Pointer to data to be read
175+
IRB.getPtrTy(), // Pointer to type descriptor
176+
BoolType, // Do we need to type check this
177+
U64Ty, // Size of data we access in bytes
178+
OrdTy // Flags
179+
);
180+
181+
TysanSetShadowType =
182+
M.getOrInsertFunction("__tysan_set_shadow_type", Attr, IRB.getVoidTy(),
183+
IRB.getPtrTy(), // Pointer of data to be written to
184+
IRB.getPtrTy(), // Pointer to the new type descriptor
185+
U64Ty // Size of data we access in bytes
186+
);
151187
}
152188

153189
void TypeSanitizer::instrumentGlobals(Module &M) {
@@ -591,6 +627,28 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
591627

592628
Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy());
593629

630+
if(ClOutlineInstrumentation){
631+
if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) {
632+
// We need to check the type here. If the type is unknown, then the read
633+
// sets the type. If the type is known, then it is checked. If the type
634+
// doesn't match, then we call the runtime (which may yet determine that
635+
// the mismatch is okay).
636+
637+
Constant *Flags =
638+
ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1));
639+
640+
IRB.CreateCall(TysanInstrumentWithShadowUpdate,
641+
{Ptr, TD, SanitizeFunction ? IRB.getTrue() : IRB.getFalse(),
642+
IRB.getInt64(AccessSize), Flags});
643+
} else if (ForceSetType || IsWrite) {
644+
// In the mode where writes always set the type, for a write (which does
645+
// not also read), we just set the type.
646+
IRB.CreateCall(TysanSetShadowType, {Ptr, TD, IRB.getInt64(AccessSize)});
647+
}
648+
649+
return true;
650+
}
651+
594652
Value *ShadowDataInt = convertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
595653
ShadowBase, AppMemMask);
596654
Type *Int8PtrPtrTy = PointerType::get(IRB.getContext(), 0);
@@ -834,37 +892,47 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Instruction *ShadowBase,
834892
}
835893
}
836894

837-
if (!ShadowBase)
838-
ShadowBase = getShadowBase(*F);
839-
if (!AppMemMask)
840-
AppMemMask = getAppMemMask(*F);
841-
842-
Value *ShadowDataInt = IRB.CreateAdd(
843-
IRB.CreateShl(
844-
IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
845-
PtrShift),
846-
ShadowBase);
847-
Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
848-
849-
if (!Src) {
850-
IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
851-
Align(1ull << PtrShift));
852-
return true;
895+
if (ClOutlineInstrumentation) {
896+
if(!Src){
897+
Src = ConstantPointerNull::get(IRB.getPtrTy());
898+
}
899+
IRB.CreateCall(TysanIntrumentMemInst, {
900+
Dest, Src, Size, NeedsMemMove ? IRB.getTrue() : IRB.getFalse()
901+
});
853902
}
903+
else {
904+
if (!ShadowBase)
905+
ShadowBase = getShadowBase(*F);
906+
if (!AppMemMask)
907+
AppMemMask = getAppMemMask(*F);
908+
909+
Value *ShadowDataInt = IRB.CreateAdd(
910+
IRB.CreateShl(
911+
IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
912+
PtrShift),
913+
ShadowBase);
914+
Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
915+
916+
if (!Src) {
917+
IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
918+
Align(1ull << PtrShift));
919+
return true;
920+
}
854921

855-
Value *SrcShadowDataInt = IRB.CreateAdd(
856-
IRB.CreateShl(
857-
IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
858-
PtrShift),
859-
ShadowBase);
860-
Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
922+
Value *SrcShadowDataInt = IRB.CreateAdd(
923+
IRB.CreateShl(
924+
IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
925+
PtrShift),
926+
ShadowBase);
927+
Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
861928

862-
if (NeedsMemMove) {
863-
IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData,
929+
if (NeedsMemMove) {
930+
IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData,
931+
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
932+
} else {
933+
IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData,
864934
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
865-
} else {
866-
IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData,
867-
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
935+
}
868936
}
869937

870938
return true;

0 commit comments

Comments
 (0)