Skip to content

Commit deeba4e

Browse files
Matthew NagygbMattN
authored andcommitted
[TySan] Add option to outline instrumentation
1 parent 95eb49a commit deeba4e

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;
@@ -207,6 +208,64 @@ static void reportError(void *Addr, int Size, tysan_type_descriptor *TD,
207208
}
208209
}
209210

211+
ALWAYS_INLINE
212+
static void SetShadowType(tysan_type_descriptor *td,
213+
tysan_type_descriptor **shadowData,
214+
uint64_t AccessSize) {
215+
*shadowData = td;
216+
uint64_t shadowDataInt = (uint64_t)shadowData;
217+
218+
for (uint64_t i = 1; i < AccessSize; ++i) {
219+
int64_t dataOffset = i << PtrShift();
220+
int64_t *badShadowData = (int64_t *)(shadowDataInt + dataOffset);
221+
int64_t badTD = int64_t(i) * -1;
222+
*badShadowData = badTD;
223+
}
224+
}
225+
226+
ALWAYS_INLINE
227+
static bool GetNotAllBadTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
228+
bool notAllBadTD = false;
229+
for (uint64_t i = 1; i < AccessSize; ++i) {
230+
int64_t **unkShadowData = (int64_t **)(ShadowDataInt + (i << PtrShift()));
231+
int64_t *ILdTD = *unkShadowData;
232+
notAllBadTD = notAllBadTD || (ILdTD != nullptr);
233+
}
234+
return notAllBadTD;
235+
}
236+
237+
ALWAYS_INLINE
238+
static bool GetNotAllUnkTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
239+
bool notAllBadTD = false;
240+
for (uint64_t i = 1; i < AccessSize; ++i) {
241+
int64_t *badShadowData = (int64_t *)(ShadowDataInt + (i << PtrShift()));
242+
int64_t ILdTD = *badShadowData;
243+
notAllBadTD = notAllBadTD || (ILdTD >= 0);
244+
}
245+
return notAllBadTD;
246+
}
247+
248+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
249+
__tysan_instrument_mem_inst(char *dest, char *src, uint64_t size,
250+
bool needsMemMove) {
251+
tysan_type_descriptor **destShadowDataPtr = shadow_for(dest);
252+
253+
if(!src){
254+
internal_memset((char*) destShadowDataPtr, 0, size << PtrShift());
255+
return;
256+
}
257+
258+
uint64_t srcInt = (uint64_t)src;
259+
uint64_t srcShadowInt = ((srcInt & AppMask()) << PtrShift()) + ShadowAddr();
260+
uint64_t *srcShadow = (uint64_t *)srcShadowInt;
261+
262+
if (needsMemMove) {
263+
internal_memmove((char*) destShadowDataPtr, srcShadow, size << PtrShift());
264+
} else {
265+
internal_memcpy((char*) destShadowDataPtr, srcShadow, size << PtrShift());
266+
}
267+
}
268+
210269
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
211270
__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
212271
GET_CALLER_PC_BP_SP;
@@ -253,6 +312,54 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
253312
}
254313
}
255314

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

258365
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) {
@@ -593,6 +629,28 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
593629

594630
Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy());
595631

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

843-
if (!ShadowBase)
844-
ShadowBase = getShadowBase(*F);
845-
if (!AppMemMask)
846-
AppMemMask = getAppMemMask(*F);
847-
848-
Value *ShadowDataInt = IRB.CreateAdd(
849-
IRB.CreateShl(
850-
IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
851-
PtrShift),
852-
ShadowBase);
853-
Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
854-
855-
if (!Src) {
856-
IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
857-
Align(1ull << PtrShift));
858-
return true;
901+
if (ClOutlineInstrumentation) {
902+
if(!Src){
903+
Src = ConstantPointerNull::get(IRB.getPtrTy());
904+
}
905+
IRB.CreateCall(TysanIntrumentMemInst, {
906+
Dest, Src, Size, NeedsMemMove ? IRB.getTrue() : IRB.getFalse()
907+
});
859908
}
909+
else {
910+
if (!ShadowBase)
911+
ShadowBase = getShadowBase(*F);
912+
if (!AppMemMask)
913+
AppMemMask = getAppMemMask(*F);
914+
915+
Value *ShadowDataInt = IRB.CreateAdd(
916+
IRB.CreateShl(
917+
IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
918+
PtrShift),
919+
ShadowBase);
920+
Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
921+
922+
if (!Src) {
923+
IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
924+
Align(1ull << PtrShift));
925+
return true;
926+
}
860927

861-
Value *SrcShadowDataInt = IRB.CreateAdd(
862-
IRB.CreateShl(
863-
IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
864-
PtrShift),
865-
ShadowBase);
866-
Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
928+
Value *SrcShadowDataInt = IRB.CreateAdd(
929+
IRB.CreateShl(
930+
IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
931+
PtrShift),
932+
ShadowBase);
933+
Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
867934

868-
if (NeedsMemMove) {
869-
IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData,
935+
if (NeedsMemMove) {
936+
IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData,
937+
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
938+
} else {
939+
IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData,
870940
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
871-
} else {
872-
IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData,
873-
Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));
941+
}
874942
}
875943

876944
return true;

0 commit comments

Comments
 (0)