Skip to content

Commit a45fd43

Browse files
committed
[dfsan] Fix origin tracking for fast8
The problem is the following. With fast8, we broke an important invariant when loading shadows. A wide shadow of 64 bits used to correspond to 4 application bytes with fast16; so, generating a single load was okay since those 4 application bytes would share a single origin. Now, using fast8, a wide shadow of 64 bits corresponds to 8 application bytes that should be backed by 2 origins (but we kept generating just one). Let’s say our wide shadow is 64-bit and consists of the following: 0xABCDEFGH. To check if we need the second origin value, we could do the following (on the 64-bit wide shadow) case: - bitwise shift the wide shadow left by 32 bits (yielding 0xEFGH0000) - push the result along with the first origin load to the shadow/origin vectors - load the second 32-bit origin of the 64-bit wide shadow - push the wide shadow along with the second origin to the shadow/origin vectors. The combineOrigins would then select the second origin if the wide shadow is of the form 0xABCDE0000. The tests illustrate how this change affects the generated bitcode. Reviewed By: stephan.yichao.zhao Differential Revision: https://reviews.llvm.org/D101584
1 parent 421569b commit a45fd43

File tree

2 files changed

+62
-15
lines changed

2 files changed

+62
-15
lines changed

llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,11 @@ class DataFlowSanitizer {
505505

506506
bool init(Module &M);
507507

508+
/// Advances \p OriginAddr to point to the next 32-bit origin and then loads
509+
/// from it. Returns the origin's loaded value.
510+
Value *loadNextOrigin(Instruction *Pos, Align OriginAlign,
511+
Value **OriginAddr);
512+
508513
/// Returns whether fast8 or fast16 mode has been specified.
509514
bool hasFastLabelsEnabled();
510515

@@ -2094,6 +2099,14 @@ bool DFSanFunction::useCallbackLoadLabelAndOrigin(uint64_t Size,
20942099
return Alignment < MinOriginAlignment || !DFS.hasLoadSizeForFastPath(Size);
20952100
}
20962101

2102+
Value *DataFlowSanitizer::loadNextOrigin(Instruction *Pos, Align OriginAlign,
2103+
Value **OriginAddr) {
2104+
IRBuilder<> IRB(Pos);
2105+
*OriginAddr =
2106+
IRB.CreateGEP(OriginTy, *OriginAddr, ConstantInt::get(IntptrTy, 1));
2107+
return IRB.CreateAlignedLoad(OriginTy, *OriginAddr, OriginAlign);
2108+
}
2109+
20972110
std::pair<Value *, Value *> DFSanFunction::loadFast16ShadowFast(
20982111
Value *ShadowAddr, Value *OriginAddr, uint64_t Size, Align ShadowAlign,
20992112
Align OriginAlign, Value *FirstOrigin, Instruction *Pos) {
@@ -2125,19 +2138,39 @@ std::pair<Value *, Value *> DFSanFunction::loadFast16ShadowFast(
21252138
Value *CombinedWideShadow =
21262139
IRB.CreateAlignedLoad(WideShadowTy, WideAddr, ShadowAlign);
21272140

2128-
if (ShouldTrackOrigins) {
2129-
Shadows.push_back(CombinedWideShadow);
2130-
Origins.push_back(FirstOrigin);
2131-
}
2141+
unsigned WideShadowBitWidth = WideShadowTy->getIntegerBitWidth();
2142+
const uint64_t BytesPerWideShadow = WideShadowBitWidth / DFS.ShadowWidthBits;
2143+
2144+
auto AppendWideShadowAndOrigin = [&](Value *WideShadow, Value *Origin) {
2145+
if (BytesPerWideShadow > 4) {
2146+
assert(BytesPerWideShadow == 8);
2147+
// The wide shadow relates to two origin pointers: one for the first four
2148+
// application bytes, and one for the latest four. We use a left shift to
2149+
// get just the shadow bytes that correspond to the first origin pointer,
2150+
// and then the entire shadow for the second origin pointer (which will be
2151+
// chosen by combineOrigins() iff the least-significant half of the wide
2152+
// shadow was empty but the other half was not).
2153+
Value *WideShadowLo = IRB.CreateShl(
2154+
WideShadow, ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2));
2155+
Shadows.push_back(WideShadow);
2156+
Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));
2157+
2158+
Shadows.push_back(WideShadowLo);
2159+
Origins.push_back(Origin);
2160+
} else {
2161+
Shadows.push_back(WideShadow);
2162+
Origins.push_back(Origin);
2163+
}
2164+
};
2165+
2166+
if (ShouldTrackOrigins)
2167+
AppendWideShadowAndOrigin(CombinedWideShadow, FirstOrigin);
21322168

21332169
// First OR all the WideShadows (i.e., 64bit or 32bit shadow chunks) linearly;
21342170
// then OR individual shadows within the combined WideShadow by binary ORing.
21352171
// This is fewer instructions than ORing shadows individually, since it
21362172
// needs logN shift/or instructions (N being the bytes of the combined wide
21372173
// shadow).
2138-
unsigned WideShadowBitWidth = WideShadowTy->getIntegerBitWidth();
2139-
const uint64_t BytesPerWideShadow = WideShadowBitWidth / DFS.ShadowWidthBits;
2140-
21412174
for (uint64_t ByteOfs = BytesPerWideShadow; ByteOfs < Size;
21422175
ByteOfs += BytesPerWideShadow) {
21432176
WideAddr = IRB.CreateGEP(WideShadowTy, WideAddr,
@@ -2146,11 +2179,8 @@ std::pair<Value *, Value *> DFSanFunction::loadFast16ShadowFast(
21462179
IRB.CreateAlignedLoad(WideShadowTy, WideAddr, ShadowAlign);
21472180
CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, NextWideShadow);
21482181
if (ShouldTrackOrigins) {
2149-
Shadows.push_back(NextWideShadow);
2150-
OriginAddr = IRB.CreateGEP(DFS.OriginTy, OriginAddr,
2151-
ConstantInt::get(DFS.IntptrTy, 1));
2152-
Origins.push_back(
2153-
IRB.CreateAlignedLoad(DFS.OriginTy, OriginAddr, OriginAlign));
2182+
Value *NextOrigin = DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr);
2183+
AppendWideShadowAndOrigin(NextWideShadow, NextOrigin);
21542184
}
21552185
}
21562186
for (unsigned Width = WideShadowBitWidth / 2; Width >= DFS.ShadowWidthBits;

llvm/test/Instrumentation/DataFlowSanitizer/origin_load.ll

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,18 @@ define i64 @load64(i64* %p) {
191191
; CHECK16-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW_NZ]], i32 %[[#ORIGIN2]], i32 %[[#ORIGIN]]
192192

193193
; COMM: On fast8, no need to OR the wide shadow but one more shift is needed.
194+
; CHECK8-NEXT: %[[#WIDE_SHADOW_LO:]] = shl i64 %[[#WIDE_SHADOW]], 32
195+
; CHECK8-NEXT: %[[#ORIGIN_PTR2:]] = getelementptr i32, i32* %[[#ORIGIN_PTR]], i64 1
196+
; CHECK8-NEXT: %[[#ORIGIN2:]] = load i32, i32* %[[#ORIGIN_PTR2]], align 8
194197
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 32
195198
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
196199
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 16
197200
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
198201
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 8
199202
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
200203
; CHECK8-NEXT: %[[#SHADOW:]] = trunc i64 %[[#WIDE_SHADOW]] to i[[#SBITS]]
204+
; CHECK8-NEXT: %[[#SHADOW_NZ:]] = icmp ne i64 %[[#WIDE_SHADOW_LO]], 0
205+
; CHECK8-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW_NZ]], i32 %[[#ORIGIN]], i32 %[[#ORIGIN2]]
201206

202207
; COMBINE_LOAD_PTR-NEXT: %[[#SHADOW:]] = or i[[#SBITS]] %[[#SHADOW]], %[[#PS]]
203208
; COMBINE_LOAD_PTR-NEXT: %[[#NZ:]] = icmp ne i[[#SBITS]] %[[#PS]], 0
@@ -250,13 +255,16 @@ define i128 @load128(i128* %p) {
250255
; CHECK-NEXT: %[[#ORIGIN:]] = load i32, i32* %[[#ORIGIN_PTR]], align 8
251256
; CHECK-NEXT: %[[#WIDE_SHADOW_PTR:]] = bitcast i[[#SBITS]]* %[[#SHADOW_PTR]] to i64*
252257
; CHECK-NEXT: %[[#WIDE_SHADOW:]] = load i64, i64* %[[#WIDE_SHADOW_PTR]], align [[#SBYTES]]
258+
; CHECK8-NEXT: %[[#WIDE_SHADOW_LO:]] = shl i64 %[[#WIDE_SHADOW]], 32
259+
; CHECK8-NEXT: %[[#ORIGIN_PTR2:]] = getelementptr i32, i32* %[[#ORIGIN_PTR]], i64 1
260+
; CHECK8-NEXT: %[[#ORIGIN2:]] = load i32, i32* %[[#ORIGIN_PTR2]], align 8
253261
; CHECK-NEXT: %[[#WIDE_SHADOW_PTR2:]] = getelementptr i64, i64* %[[#WIDE_SHADOW_PTR]], i64 1
254262
; CHECK-NEXT: %[[#WIDE_SHADOW2:]] = load i64, i64* %[[#WIDE_SHADOW_PTR2]], align [[#SBYTES]]
255263
; CHECK-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW2]]
256-
; CHECK-NEXT: %[[#ORIGIN_PTR2:]] = getelementptr i32, i32* %[[#ORIGIN_PTR]], i64 1
257-
; CHECK-NEXT: %[[#ORIGIN2:]] = load i32, i32* %[[#ORIGIN_PTR2]], align 8
258264

259265
; COMM: On fast16, we need to OR 4x64bits for the wide shadow, before ORing its bytes.
266+
; CHECK16-NEXT: %[[#ORIGIN_PTR2:]] = getelementptr i32, i32* %[[#ORIGIN_PTR]], i64 1
267+
; CHECK16-NEXT: %[[#ORIGIN2:]] = load i32, i32* %[[#ORIGIN_PTR2]], align 8
260268
; CHECK16-NEXT: %[[#WIDE_SHADOW_PTR3:]] = getelementptr i64, i64* %[[#WIDE_SHADOW_PTR2]], i64 1
261269
; CHECK16-NEXT: %[[#WIDE_SHADOW3:]] = load i64, i64* %[[#WIDE_SHADOW_PTR3]], align [[#SBYTES]]
262270
; CHECK16-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW3]]
@@ -280,15 +288,24 @@ define i128 @load128(i128* %p) {
280288
; CHECK16-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW4_NZ]], i32 %[[#ORIGIN4]], i32 %[[#ORIGIN]]
281289

282290
; COMM: On fast8, we need to OR 2x64bits for the wide shadow, before ORing its bytes (one more shift).
291+
; CHECK8-NEXT: %[[#ORIGIN_PTR3:]] = getelementptr i32, i32* %[[#ORIGIN_PTR2]], i64 1
292+
; CHECK8-NEXT: %[[#ORIGIN3:]] = load i32, i32* %[[#ORIGIN_PTR3]], align 8
293+
; CHECK8-NEXT: %[[#WIDE_SHADOW2_LO:]] = shl i64 %[[#WIDE_SHADOW2]], 32
294+
; CHECK8-NEXT: %[[#ORIGIN_PTR4:]] = getelementptr i32, i32* %[[#ORIGIN_PTR3]], i64 1
295+
; CHECK8-NEXT: %[[#ORIGIN4:]] = load i32, i32* %[[#ORIGIN_PTR4]], align 8
283296
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 32
284297
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
285298
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 16
286299
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
287300
; CHECK8-NEXT: %[[#WIDE_SHADOW_SHIFTED:]] = lshr i64 %[[#WIDE_SHADOW]], 8
288301
; CHECK8-NEXT: %[[#WIDE_SHADOW:]] = or i64 %[[#WIDE_SHADOW]], %[[#WIDE_SHADOW_SHIFTED]]
289302
; CHECK8-NEXT: %[[#SHADOW:]] = trunc i64 %[[#WIDE_SHADOW]] to i[[#SBITS]]
303+
; CHECK8-NEXT: %[[#SHADOW_LO_NZ:]] = icmp ne i64 %[[#WIDE_SHADOW_LO]], 0
304+
; CHECK8-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW_LO_NZ]], i32 %[[#ORIGIN]], i32 %[[#ORIGIN2]]
290305
; CHECK8-NEXT: %[[#SHADOW2_NZ:]] = icmp ne i64 %[[#WIDE_SHADOW2]], 0
291-
; CHECK8-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW2_NZ]], i32 %[[#ORIGIN2]], i32 %[[#ORIGIN]]
306+
; CHECK8-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW2_NZ]], i32 %[[#ORIGIN4]], i32 %[[#ORIGIN]]
307+
; CHECK8-NEXT: %[[#SHADOW2_LO_NZ:]] = icmp ne i64 %[[#WIDE_SHADOW2_LO]], 0
308+
; CHECK8-NEXT: %[[#ORIGIN:]] = select i1 %[[#SHADOW2_LO_NZ]], i32 %[[#ORIGIN3]], i32 %[[#ORIGIN]]
292309

293310
; COMBINE_LOAD_PTR-NEXT: %[[#SHADOW:]] = or i[[#SBITS]] %[[#SHADOW]], %[[#PS]]
294311
; COMBINE_LOAD_PTR-NEXT: %[[#NZ:]] = icmp ne i[[#SBITS]] %[[#PS]], 0

0 commit comments

Comments
 (0)