@@ -493,6 +493,60 @@ class ValueToShadowMap {
493
493
DenseMap<Value *, Value *> Map;
494
494
};
495
495
496
+ class NsanMemOpFn {
497
+ public:
498
+ NsanMemOpFn (Module &M, ArrayRef<StringRef> Sized, StringRef Fallback,
499
+ size_t NumArgs);
500
+ FunctionCallee getFunctionFor (uint64_t MemOpSize) const ;
501
+ FunctionCallee getFallback () const ;
502
+
503
+ private:
504
+ SmallVector<FunctionCallee> Funcs;
505
+ size_t NumSizedFuncs;
506
+ };
507
+
508
+ NsanMemOpFn::NsanMemOpFn (Module &M, ArrayRef<StringRef> Sized,
509
+ StringRef Fallback, size_t NumArgs) {
510
+ LLVMContext &Ctx = M.getContext ();
511
+ AttributeList Attr;
512
+ Attr = Attr.addFnAttribute (Ctx, Attribute::NoUnwind);
513
+ Type *PtrTy = PointerType::getUnqual (Ctx);
514
+ Type *VoidTy = Type::getVoidTy (Ctx);
515
+ IntegerType *IntptrTy = M.getDataLayout ().getIntPtrType (Ctx);
516
+ FunctionType *SizedFnTy = nullptr ;
517
+
518
+ NumSizedFuncs = Sized.size ();
519
+
520
+ // First entry is fallback function
521
+ if (NumArgs == 3 ) {
522
+ Funcs.push_back (
523
+ M.getOrInsertFunction (Fallback, Attr, VoidTy, PtrTy, PtrTy, IntptrTy));
524
+ SizedFnTy = FunctionType::get (VoidTy, {PtrTy, PtrTy}, false );
525
+ } else if (NumArgs == 2 ) {
526
+ Funcs.push_back (
527
+ M.getOrInsertFunction (Fallback, Attr, VoidTy, PtrTy, IntptrTy));
528
+ SizedFnTy = FunctionType::get (VoidTy, {PtrTy}, false );
529
+ } else {
530
+ assert (!" Unexpected value of sized functions arguments" );
531
+ }
532
+
533
+ for (size_t i = 0 ; i < NumSizedFuncs; ++i)
534
+ Funcs.push_back (M.getOrInsertFunction (Sized[i], SizedFnTy, Attr));
535
+ }
536
+
537
+ FunctionCallee NsanMemOpFn::getFunctionFor (uint64_t MemOpSize) const {
538
+ // Now `getFunctionFor` operates on `Funcs` of size 4 (at least) and the
539
+ // following code assumes that the number of functions in `Func` is sufficient
540
+ assert (NumSizedFuncs >= 3 && " Unexpected number of sized functions" );
541
+
542
+ size_t Idx =
543
+ MemOpSize == 4 ? 1 : (MemOpSize == 8 ? 2 : (MemOpSize == 16 ? 3 : 0 ));
544
+
545
+ return Funcs[Idx];
546
+ }
547
+
548
+ FunctionCallee NsanMemOpFn::getFallback () const { return Funcs[0 ]; }
549
+
496
550
// / Instantiating NumericalStabilitySanitizer inserts the nsan runtime library
497
551
// / API function declarations into the module if they don't exist already.
498
552
// / Instantiating ensures the __nsan_init function is in the list of global
@@ -550,12 +604,16 @@ class NumericalStabilitySanitizer {
550
604
LLVMContext &Context;
551
605
MappingConfig Config;
552
606
IntegerType *IntptrTy = nullptr ;
607
+
608
+ // TODO: Use std::array instead?
553
609
FunctionCallee NsanGetShadowPtrForStore[FTValueType::kNumValueTypes ] = {};
554
610
FunctionCallee NsanGetShadowPtrForLoad[FTValueType::kNumValueTypes ] = {};
555
611
FunctionCallee NsanCheckValue[FTValueType::kNumValueTypes ] = {};
556
612
FunctionCallee NsanFCmpFail[FTValueType::kNumValueTypes ] = {};
557
- FunctionCallee NsanCopyValues;
558
- FunctionCallee NsanSetValueUnknown;
613
+
614
+ NsanMemOpFn NsanCopyFns;
615
+ NsanMemOpFn NsanSetUnknownFns;
616
+
559
617
FunctionCallee NsanGetRawShadowTypePtr;
560
618
FunctionCallee NsanGetRawShadowPtr;
561
619
GlobalValue *NsanShadowRetTag = nullptr ;
@@ -598,7 +656,14 @@ static GlobalValue *createThreadLocalGV(const char *Name, Module &M, Type *Ty) {
598
656
}
599
657
600
658
NumericalStabilitySanitizer::NumericalStabilitySanitizer (Module &M)
601
- : DL(M.getDataLayout()), Context(M.getContext()), Config(Context) {
659
+ : DL(M.getDataLayout()), Context(M.getContext()), Config(Context),
660
+ NsanCopyFns(M, {" __nsan_copy_4" , " __nsan_copy_8" , " __nsan_copy_16" },
661
+ " __nsan_copy_values" , /* NumArgs=*/ 3 ),
662
+ NsanSetUnknownFns(M,
663
+ {" __nsan_set_value_unknown_4" ,
664
+ " __nsan_set_value_unknown_8" ,
665
+ " __nsan_set_value_unknown_16" },
666
+ " __nsan_set_value_unknown" , /* NumArgs=*/ 2 ) {
602
667
IntptrTy = DL.getIntPtrType (Context);
603
668
Type *PtrTy = PointerType::getUnqual (Context);
604
669
Type *Int32Ty = Type::getInt32Ty (Context);
@@ -634,11 +699,6 @@ NumericalStabilitySanitizer::NumericalStabilitySanitizer(Module &M)
634
699
Attr, VoidTy, VTTy, VTTy, ShadowTy, ShadowTy, Int32Ty, Int1Ty, Int1Ty);
635
700
}
636
701
637
- NsanCopyValues = M.getOrInsertFunction (" __nsan_copy_values" , Attr, VoidTy,
638
- PtrTy, PtrTy, IntptrTy);
639
- NsanSetValueUnknown = M.getOrInsertFunction (" __nsan_set_value_unknown" , Attr,
640
- VoidTy, PtrTy, IntptrTy);
641
-
642
702
// TODO: Add attributes nofree, nosync, readnone, readonly,
643
703
NsanGetRawShadowTypePtr = M.getOrInsertFunction (
644
704
" __nsan_internal_get_raw_shadow_type_ptr" , Attr, PtrTy, PtrTy);
@@ -1880,7 +1940,7 @@ void NumericalStabilitySanitizer::propagateNonFTStore(
1880
1940
}
1881
1941
}
1882
1942
// All other stores just reset the shadow value to unknown.
1883
- Builder.CreateCall (NsanSetValueUnknown , {Dst, ValueSize});
1943
+ Builder.CreateCall (NsanSetUnknownFns. getFallback () , {Dst, ValueSize});
1884
1944
}
1885
1945
1886
1946
void NumericalStabilitySanitizer::propagateShadowValues (
@@ -2123,21 +2183,45 @@ bool NumericalStabilitySanitizer::sanitizeFunction(
2123
2183
return !ValueToShadow.empty ();
2124
2184
}
2125
2185
2186
+ static uint64_t GetMemOpSize (Value *V) {
2187
+ uint64_t OpSize = 0 ;
2188
+ if (Constant *C = dyn_cast<Constant>(V)) {
2189
+ auto *CInt = dyn_cast<ConstantInt>(C);
2190
+ if (CInt && CInt->getValue ().getBitWidth () <= 64 )
2191
+ OpSize = CInt->getValue ().getZExtValue ();
2192
+ }
2193
+
2194
+ return OpSize;
2195
+ }
2196
+
2126
2197
// Instrument the memory intrinsics so that they properly modify the shadow
2127
2198
// memory.
2128
2199
bool NumericalStabilitySanitizer::instrumentMemIntrinsic (MemIntrinsic *MI) {
2129
2200
IRBuilder<> Builder (MI);
2130
2201
if (auto *M = dyn_cast<MemSetInst>(MI)) {
2131
- Builder.CreateCall (
2132
- NsanSetValueUnknown,
2133
- {/* Address=*/ M->getArgOperand (0 ),
2134
- /* Size=*/ Builder.CreateIntCast (M->getArgOperand (2 ), IntptrTy, false )});
2202
+ FunctionCallee SetUnknownFn =
2203
+ NsanSetUnknownFns.getFunctionFor (GetMemOpSize (M->getArgOperand (2 )));
2204
+ if (SetUnknownFn.getFunctionType ()->getNumParams () == 1 )
2205
+ Builder.CreateCall (SetUnknownFn, {/* Address=*/ M->getArgOperand (0 )});
2206
+ else
2207
+ Builder.CreateCall (SetUnknownFn,
2208
+ {/* Address=*/ M->getArgOperand (0 ),
2209
+ /* Size=*/ Builder.CreateIntCast (M->getArgOperand (2 ),
2210
+ IntptrTy, false )});
2211
+
2135
2212
} else if (auto *M = dyn_cast<MemTransferInst>(MI)) {
2136
- Builder.CreateCall (
2137
- NsanCopyValues,
2138
- {/* Destination=*/ M->getArgOperand (0 ),
2139
- /* Source=*/ M->getArgOperand (1 ),
2140
- /* Size=*/ Builder.CreateIntCast (M->getArgOperand (2 ), IntptrTy, false )});
2213
+ FunctionCallee CopyFn =
2214
+ NsanCopyFns.getFunctionFor (GetMemOpSize (M->getArgOperand (2 )));
2215
+
2216
+ if (CopyFn.getFunctionType ()->getNumParams () == 2 )
2217
+ Builder.CreateCall (CopyFn, {/* Destination=*/ M->getArgOperand (0 ),
2218
+ /* Source=*/ M->getArgOperand (1 )});
2219
+ else
2220
+ Builder.CreateCall (CopyFn, {/* Destination=*/ M->getArgOperand (0 ),
2221
+ /* Source=*/ M->getArgOperand (1 ),
2222
+ /* Size=*/
2223
+ Builder.CreateIntCast (M->getArgOperand (2 ),
2224
+ IntptrTy, false )});
2141
2225
}
2142
2226
return false ;
2143
2227
}
0 commit comments