Skip to content
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

[TySan] Fix false positives with derived classes #126260

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gbMattN
Copy link
Contributor

@gbMattN gbMattN commented Feb 7, 2025

Fixes issue #125079 as well as another case I discovered while trying to build LLVM with TySan.
The case when the access has an offset needs some slightly different legwork to the average check.

@llvmbot
Copy link
Member

llvmbot commented Feb 7, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: None (gbMattN)

Changes

Fixes issue #125079 as well as another case I discovered while trying to build LLVM with TySan.
The case when your access has an offset needs some slightly different legwork to the average check.


Full diff: https://github.com/llvm/llvm-project/pull/126260.diff

3 Files Affected:

  • (modified) compiler-rt/lib/tysan/tysan.cpp (+42-18)
  • (added) compiler-rt/test/tysan/derrived_default_constructor.cpp (+27)
  • (added) compiler-rt/test/tysan/inherited_member.cpp (+23)
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp
index f0230df9260e3a1..cf2b7d6bad564ec 100644
--- a/compiler-rt/lib/tysan/tysan.cpp
+++ b/compiler-rt/lib/tysan/tysan.cpp
@@ -102,20 +102,10 @@ static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) {
   return RootTD;
 }
 
-static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
-                              tysan_type_descriptor *TDB, int TDAOffset) {
-  // Walk up the tree starting with TDA to see if we reach TDB.
-  uptr OffsetA = 0, OffsetB = 0;
-  if (TDB->Tag == TYSAN_MEMBER_TD) {
-    OffsetB = TDB->Member.Offset;
-    TDB = TDB->Member.Base;
-  }
-
-  if (TDA->Tag == TYSAN_MEMBER_TD) {
-    OffsetA = TDA->Member.Offset - TDAOffset;
-    TDA = TDA->Member.Base;
-  }
-
+bool walkAliasTree(
+  tysan_type_descriptor* TDA, tysan_type_descriptor* TDB,
+  uptr OffsetA, uptr OffsetB
+){
   do {
     if (TDA == TDB)
       return OffsetA == OffsetB;
@@ -153,8 +143,43 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
   return false;
 }
 
+static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
+                              tysan_type_descriptor *TDB) {
+  // Walk up the tree starting with TDA to see if we reach TDB.
+  uptr OffsetA = 0, OffsetB = 0;
+  if (TDB->Tag == TYSAN_MEMBER_TD) {
+    OffsetB = TDB->Member.Offset;
+    TDB = TDB->Member.Base;
+  }
+
+  if (TDA->Tag == TYSAN_MEMBER_TD) {
+    OffsetA = TDA->Member.Offset;
+    TDA = TDA->Member.Base;
+  }
+
+  return walkAliasTree(TDA, TDB, OffsetA, OffsetB);
+}
+
+static bool isAliasingLegalWithOffset(tysan_type_descriptor *AccessTD, tysan_type_descriptor *ShadowTD, int OffsetInShadow){
+  // This is handled in the other cases
+  if(OffsetInShadow == 0)
+    return false;
+  
+  // You can't have an offset into a member
+  if(ShadowTD->Tag == TYSAN_MEMBER_TD)
+    return false;
+
+  int OffsetInAccess = 0;
+  if(AccessTD->Tag == TYSAN_MEMBER_TD){
+    OffsetInAccess = AccessTD->Member.Offset;
+    AccessTD = AccessTD->Member.Base;
+  }
+
+  return walkAliasTree(ShadowTD, AccessTD, OffsetInShadow, OffsetInAccess);
+}
+
 static bool isAliasingLegal(tysan_type_descriptor *TDA,
-                            tysan_type_descriptor *TDB, int TDAOffset = 0) {
+                            tysan_type_descriptor *TDB) {
   if (TDA == TDB || !TDB || !TDA)
     return true;
 
@@ -165,8 +190,7 @@ static bool isAliasingLegal(tysan_type_descriptor *TDA,
   // TDB may have been adjusted by offset TDAOffset in the caller to point to
   // the outer type. Check for aliasing with and without adjusting for this
   // offset.
-  return isAliasingLegalUp(TDA, TDB, 0) || isAliasingLegalUp(TDB, TDA, 0) ||
-         isAliasingLegalUp(TDA, TDB, TDAOffset);
+  return isAliasingLegalUp(TDA, TDB) || isAliasingLegalUp(TDB, TDA);
 }
 
 namespace __tysan {
@@ -243,7 +267,7 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
     OldTDPtr -= i;
     OldTD = *OldTDPtr;
 
-    if (!isAliasingLegal(td, OldTD, i))
+    if (!isAliasingLegal(td, OldTD) && !isAliasingLegalWithOffset(td, OldTD, i))
       reportError(addr, size, td, OldTD, AccessStr,
                   "accesses part of an existing object", -i, pc, bp, sp);
 
diff --git a/compiler-rt/test/tysan/derrived_default_constructor.cpp b/compiler-rt/test/tysan/derrived_default_constructor.cpp
new file mode 100644
index 000000000000000..b232d7949397c35
--- /dev/null
+++ b/compiler-rt/test/tysan/derrived_default_constructor.cpp
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tysan %s -o %t && %run %t 2>&1 | FileCheck --implicit-check-not ERROR %s
+
+#include <stdio.h>
+
+class Inner{
+public:
+    void* ptr = nullptr;
+};
+
+class Base{
+public:
+    void* buffer1;
+    Inner inside;
+    void* buffer2;
+};
+
+class Derrived : public Base{
+
+};
+
+Derrived derr;
+
+int main(){
+    printf("%p", derr.inside.ptr);
+
+    return 0;
+}
diff --git a/compiler-rt/test/tysan/inherited_member.cpp b/compiler-rt/test/tysan/inherited_member.cpp
new file mode 100644
index 000000000000000..9a96f6f40021391
--- /dev/null
+++ b/compiler-rt/test/tysan/inherited_member.cpp
@@ -0,0 +1,23 @@
+// RUN: %clangxx_tysan %s -o %t && %run %t 2>&1 | FileCheck --implicit-check-not ERROR %s
+
+#include <stdio.h>
+
+class Base{
+public:
+    void* first;
+    void* second;
+    void* third;
+};
+
+class Derrived : public Base{
+
+};
+
+Derrived derr;
+
+int main(){
+    derr.second = nullptr;
+    printf("%p", derr.second);
+
+    return 0;
+}

Copy link

github-actions bot commented Feb 7, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 025541ddedd23e39d9394ea8a1e41a64dfbe4e94 0a94da3186ae40a9a8999d4b3f8e0f47643fce42 --extensions cpp -- compiler-rt/test/tysan/derrived_default_constructor.cpp compiler-rt/test/tysan/inherited_member.cpp compiler-rt/lib/tysan/tysan.cpp
View the diff from clang-format here.
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp
index cf2b7d6bad..1c1580e193 100644
--- a/compiler-rt/lib/tysan/tysan.cpp
+++ b/compiler-rt/lib/tysan/tysan.cpp
@@ -102,10 +102,8 @@ static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) {
   return RootTD;
 }
 
-bool walkAliasTree(
-  tysan_type_descriptor* TDA, tysan_type_descriptor* TDB,
-  uptr OffsetA, uptr OffsetB
-){
+bool walkAliasTree(tysan_type_descriptor *TDA, tysan_type_descriptor *TDB,
+                   uptr OffsetA, uptr OffsetB) {
   do {
     if (TDA == TDB)
       return OffsetA == OffsetB;
@@ -160,17 +158,19 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
   return walkAliasTree(TDA, TDB, OffsetA, OffsetB);
 }
 
-static bool isAliasingLegalWithOffset(tysan_type_descriptor *AccessTD, tysan_type_descriptor *ShadowTD, int OffsetInShadow){
+static bool isAliasingLegalWithOffset(tysan_type_descriptor *AccessTD,
+                                      tysan_type_descriptor *ShadowTD,
+                                      int OffsetInShadow) {
   // This is handled in the other cases
-  if(OffsetInShadow == 0)
+  if (OffsetInShadow == 0)
     return false;
-  
+
   // You can't have an offset into a member
-  if(ShadowTD->Tag == TYSAN_MEMBER_TD)
+  if (ShadowTD->Tag == TYSAN_MEMBER_TD)
     return false;
 
   int OffsetInAccess = 0;
-  if(AccessTD->Tag == TYSAN_MEMBER_TD){
+  if (AccessTD->Tag == TYSAN_MEMBER_TD) {
     OffsetInAccess = AccessTD->Member.Offset;
     AccessTD = AccessTD->Member.Base;
   }
diff --git a/compiler-rt/test/tysan/derrived_default_constructor.cpp b/compiler-rt/test/tysan/derrived_default_constructor.cpp
index b232d79493..39705bfbb3 100644
--- a/compiler-rt/test/tysan/derrived_default_constructor.cpp
+++ b/compiler-rt/test/tysan/derrived_default_constructor.cpp
@@ -2,26 +2,24 @@
 
 #include <stdio.h>
 
-class Inner{
+class Inner {
 public:
-    void* ptr = nullptr;
+  void *ptr = nullptr;
 };
 
-class Base{
+class Base {
 public:
-    void* buffer1;
-    Inner inside;
-    void* buffer2;
+  void *buffer1;
+  Inner inside;
+  void *buffer2;
 };
 
-class Derrived : public Base{
-
-};
+class Derrived : public Base {};
 
 Derrived derr;
 
-int main(){
-    printf("%p", derr.inside.ptr);
+int main() {
+  printf("%p", derr.inside.ptr);
 
-    return 0;
+  return 0;
 }
diff --git a/compiler-rt/test/tysan/inherited_member.cpp b/compiler-rt/test/tysan/inherited_member.cpp
index 9a96f6f400..f23d69e6c8 100644
--- a/compiler-rt/test/tysan/inherited_member.cpp
+++ b/compiler-rt/test/tysan/inherited_member.cpp
@@ -2,22 +2,20 @@
 
 #include <stdio.h>
 
-class Base{
+class Base {
 public:
-    void* first;
-    void* second;
-    void* third;
+  void *first;
+  void *second;
+  void *third;
 };
 
-class Derrived : public Base{
-
-};
+class Derrived : public Base {};
 
 Derrived derr;
 
-int main(){
-    derr.second = nullptr;
-    printf("%p", derr.second);
+int main() {
+  derr.second = nullptr;
+  printf("%p", derr.second);
 
-    return 0;
+  return 0;
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants