Skip to content

[TySan] Fixed false positive when accessing offset member variables #120406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion compiler-rt/lib/tysan/tysan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,31 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
OldTDPtr -= i;
OldTD = *OldTDPtr;

if (!isAliasingLegal(td, OldTD, i))
tysan_type_descriptor *AccessedType = OldTD;

// Only check if we are accessing members if the type exists
if (OldTD != nullptr) {
// When shadow memory is set for global objects, the entire object is
// tagged with the struct type This means that when you access a member
// variable, tysan reads that as you accessing a struct midway through,
// with 'i' being the offset Therefore, if you are accessing a struct, we
// need to find the member type. We can go through the members of the
// struct type and see if there is a member at the offset you are
// accessing the struct by. If there is indeed a member starting at offset
// 'i' in the struct, we should check aliasing legality with that type. If
// there isn't, we run alias checking on the struct which will give us the
// correct error.
if (OldTD->Tag == TYSAN_STRUCT_TD) {
for (int j = 0; j < OldTD->Struct.MemberCount; ++j) {
if (OldTD->Struct.Members[j].Offset == i) {
AccessedType = OldTD->Struct.Members[j].Type;
break;
}
}
}
}

if (!isAliasingLegal(td, AccessedType, i))
reportError(addr, size, td, OldTD, AccessStr,
"accesses part of an existing object", -i, pc, bp, sp);

Expand Down
30 changes: 30 additions & 0 deletions compiler-rt/test/tysan/global-struct-members.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
// RUN: FileCheck %s --implicit-check-not ERROR < %t.out

#include <stdio.h>

struct X {
int a, b, c;
} x;

static struct X xArray[2];

int main() {
x.a = 1;
x.b = 2;
x.c = 3;

printf("%d %d %d\n", x.a, x.b, x.c);

for (size_t i = 0; i < 2; i++) {
xArray[i].a = 1;
xArray[i].b = 1;
xArray[i].c = 1;
}

struct X *xPtr = (struct X *)&(xArray[0].c);
xPtr->a = 1;
// CHECK: ERROR: TypeSanitizer: type-aliasing-violation
// CHECK-NEXT: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 8)
// CHECK-NEXT: #0 0x{{.*}} in main {{.*}}struct-members.c:[[@LINE-3]]
}
Loading