Skip to content

Commit fd88089

Browse files
committed
-fsanitize=vptr: Change hash function and simplify bit mixer
llvm::hash_value is not guaranteed to be deterministic. Use the deterministic xxh3_64bits. A strong bit mixer isn't necessary. Use a simpler one that works well with pointers.
1 parent ac02bf7 commit fd88089

File tree

2 files changed

+18
-32
lines changed

2 files changed

+18
-32
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -650,16 +650,13 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
650650
->getZExtValue();
651651
}
652652

653-
/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h.
654-
static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
655-
llvm::Value *High) {
656-
llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL);
657-
llvm::Value *K47 = Builder.getInt64(47);
658-
llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul);
659-
llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0);
660-
llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul);
661-
llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0);
662-
return Builder.CreateMul(B1, KMul);
653+
static llvm::Value *emitHashMix(CGBuilderTy &Builder, llvm::Value *Acc,
654+
llvm::Value *Ptr) {
655+
llvm::Value *A0 =
656+
Builder.CreateMul(Ptr, Builder.getInt64(0xbf58476d1ce4e5b9u));
657+
llvm::Value *A1 =
658+
Builder.CreateXor(A0, Builder.CreateLShr(A0, Builder.getInt64(31)));
659+
return Builder.CreateXor(Acc, A1);
663660
}
664661

665662
bool CodeGenFunction::isNullPointerAllowed(TypeCheckKind TCK) {
@@ -821,11 +818,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
821818
EmitBlock(VptrNotNull);
822819
}
823820

824-
// Compute a hash of the mangled name of the type.
825-
//
826-
// FIXME: This is not guaranteed to be deterministic! Move to a
827-
// fingerprinting mechanism once LLVM provides one. For the time
828-
// being the implementation happens to be deterministic.
821+
// Compute a deterministic hash of the mangled name of the type.
829822
SmallString<64> MangledName;
830823
llvm::raw_svector_ostream Out(MangledName);
831824
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
@@ -834,15 +827,13 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
834827
// Contained in NoSanitizeList based on the mangled type.
835828
if (!CGM.getContext().getNoSanitizeList().containsType(SanitizerKind::Vptr,
836829
Out.str())) {
837-
llvm::hash_code TypeHash = hash_value(Out.str());
838-
839-
// Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
840-
llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
830+
// Load the vptr, and mix it with TypeHash.
831+
llvm::Value *TypeHash =
832+
llvm::ConstantInt::get(Int64Ty, xxh3_64bits(Out.str()));
841833
Address VPtrAddr(Ptr, IntPtrTy, getPointerAlign());
842834
llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
843-
llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
844-
845-
llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
835+
llvm::Value *Hash =
836+
emitHashMix(Builder, TypeHash, Builder.CreateZExt(VPtrVal, Int64Ty));
846837
Hash = Builder.CreateTrunc(Hash, IntPtrTy);
847838

848839
// Look the hash up in our cache.

clang/test/CodeGenCXX/catch-undef-behavior.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,10 @@ void member_access(S *p) {
6767
// The two hash values are for 64- and 32-bit Clang binaries, respectively.
6868
// FIXME: We should produce a 64-bit value either way.
6969
//
70-
// CHECK-NEXT: xor i64 {{-4030275160588942838|1107558922}}, %[[VPTR]]
71-
// CHECK-NEXT: mul i64 {{.*}}, -7070675565921424023
72-
// CHECK-NEXT: lshr i64 {{.*}}, 47
73-
// CHECK-NEXT: xor i64
74-
// CHECK-NEXT: xor i64 %[[VPTR]]
75-
// CHECK-NEXT: mul i64 {{.*}}, -7070675565921424023
76-
// CHECK-NEXT: lshr i64 {{.*}}, 47
77-
// CHECK-NEXT: xor i64
78-
// CHECK-NEXT: %[[HASH:.*]] = mul i64 {{.*}}, -7070675565921424023
70+
// CHECK-NEXT: mul i64 %[[VPTR]], -4658895280553007687, !nosanitize
71+
// CHECK-NEXT: lshr i64 {{.*}}, 31
72+
// CHECK-NEXT: xor i64 %[[#]], %[[#]]
73+
// CHECK-NEXT: %[[HASH:.*]] = xor i64 4589795628539611399, %[[#]], !nosanitize
7974
//
8075
// Check the hash against the table:
8176
//
@@ -116,7 +111,7 @@ void member_access(S *p) {
116111
// (3b) Check that 'p' actually points to an 'S'
117112

118113
// CHECK: load i64, ptr
119-
// CHECK-NEXT: xor i64 {{-4030275160588942838|1107558922}},
114+
// CHECK-NEXT: mul i64 %[[#]], -4658895280553007687, !nosanitize
120115
// [...]
121116
// CHECK: getelementptr inbounds [128 x i64], ptr @__ubsan_vptr_type_cache, i32 0, i64 %
122117
// CHECK: br i1

0 commit comments

Comments
 (0)