Skip to content

Commit 09a8b7c

Browse files
authored
[TySan] Fix struct access with different bases (#120412)
Original pull request [here](#108385) Fixes issue #105960 If a member in a struct is also a struct, accessing a member partway through this inner struct currently causes a false positive. This is because when checking aliasing, the access offset is seen as greater than the starting offset of the inner struct, so the loop continues one iteration, and believes we are accessing the member after the inner struct. The next member's offset is greater than the offset we are looking for, so when we subtract the next member's offset from what we are looking for, the offset underflows. To fix this, we check if the member we think we are accessing has a greater offset than the offset we are looking for. If so, we take a step back. We cannot do this in the loop, since the loop does not check the final member. This means the penultimate member would still cause false positives.
1 parent af524de commit 09a8b7c

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

compiler-rt/lib/tysan/tysan.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
131131
break;
132132
}
133133

134+
// This offset can't be negative. Therefore we must be accessing something
135+
// before the current type (not legal) or partially inside the last type.
136+
// In the latter case, we adjust Idx.
137+
if (TDA->Struct.Members[Idx].Offset > OffsetA) {
138+
// Trying to access something before the current type.
139+
if (!Idx)
140+
return false;
141+
142+
Idx -= 1;
143+
}
144+
134145
OffsetA -= TDA->Struct.Members[Idx].Offset;
135146
TDA = TDA->Struct.Members[Idx].Type;
136147
} else {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clangxx_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
2+
// RUN: FileCheck %s --implicit-check-not ERROR < %t.out
3+
4+
// Modified reproducer from https://github.com/llvm/llvm-project/issues/105960
5+
6+
#include <stdio.h>
7+
8+
struct inner1 {
9+
char buffer;
10+
int i;
11+
};
12+
13+
struct inner2 {
14+
char buffer;
15+
int i;
16+
float endBuffer;
17+
};
18+
19+
void init_inner1(inner1 *iPtr) { iPtr->i = 200; }
20+
void init_inner2(inner2 *iPtr) {
21+
iPtr->i = 400;
22+
iPtr->endBuffer = 413.0f;
23+
}
24+
25+
struct outer {
26+
inner1 foo;
27+
inner2 bar;
28+
char buffer;
29+
};
30+
31+
int main(void) {
32+
outer *l = new outer();
33+
34+
init_inner1(&l->foo);
35+
init_inner2(&l->bar);
36+
37+
int access = l->foo.i;
38+
printf("Accessed value 1 is %d\n", access);
39+
access = l->bar.i;
40+
printf("Accessed value 2 is %d\n", access);
41+
float fAccess = l->bar.endBuffer;
42+
printf("Accessed value 3 is %f\n", fAccess);
43+
44+
return 0;
45+
}
46+
47+
// CHECK: Accessed value 1 is 200
48+
// CHECK: Accessed value 2 is 400
49+
// CHECK: Accessed value 3 is 413.0

0 commit comments

Comments
 (0)