[compiler-rt] [asan] Add test case for alignment of FakeStack frames (PR #152889)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 11 14:49:19 PDT 2025


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/152889

>From b8dd31dd354eb469adcf836a3ca7f7fe1efac8eb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sun, 10 Aug 2025 05:00:22 +0000
Subject: [PATCH 1/7] [asan] Add test case for alignment of FakeStack frames

This test case demonstrates that ASan does not currently align FakeStack frames correctly.
(https://github.com/llvm/llvm-project/pull/152819 will fix it.)
---
 .../asan/TestCases/fakestack_alignment.cpp    | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 compiler-rt/test/asan/TestCases/fakestack_alignment.cpp

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
new file mode 100644
index 0000000000000..597a486e26534
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -0,0 +1,74 @@
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 %s -o %t && %run %t 2>&1
+// XFAIL: *
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct alignas(4096) page {
+    int x;
+};
+
+struct alignas(16384) larry {
+    int x;
+};
+
+bool misaligned = false;
+
+void grandchild(void) {
+  larry l2;
+  uint alignment = (unsigned long)&l2 % alignof(larry);
+  if (alignment != 0)
+    misaligned = true;
+
+  printf ("Grandchild: address modulo alignment %u\n", alignment);
+}
+
+// Even if the FakeStack frame is aligned by chance to 16384, we can use an
+// intervening stack frame to knock it out of alignment.
+void child(void) {
+  page p1;
+  uint alignment = (unsigned long)&p1 % alignof(page);
+  printf ("Child: address modulo alignment is %u\n", alignment);
+  if (alignment != 0)
+    misaligned = true;
+
+  grandchild();
+}
+
+// Check whether the FakeStack frame is sufficiently aligned. Alignment can
+// happen by chance, so try this on many threads if you don't want
+void *Thread(void *unused)  {
+  larry l1;
+  uint alignment = (unsigned long)&l1 % alignof(larry);
+  printf ("Thread: address modulo alignment is %u\n", alignment);
+  if (alignment != 0)
+    misaligned = true;
+
+  child();
+
+  return NULL;
+}
+
+int main(int argc, char **argv) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+
+  pthread_t t[10];
+  for (int i = 0; i < 10; i++) {
+     pthread_create(&t[i], &attr, Thread, 0);
+  }
+  pthread_attr_destroy(&attr);
+  for (int i = 0; i < 10; i++) {
+     pthread_join(t[i], 0);
+  }
+
+  if (misaligned) {
+    printf ("Test failed: not perfectly aligned\n");
+    exit(1);
+  }
+
+  return 0;
+}

>From 115b11b6cf2606396cfbb9b157e6a9bb43bff875 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sun, 10 Aug 2025 06:07:55 +0000
Subject: [PATCH 2/7] clang-format

---
 .../asan/TestCases/fakestack_alignment.cpp     | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index 597a486e26534..0b0dbd17571bb 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -8,11 +8,11 @@
 #include <string.h>
 
 struct alignas(4096) page {
-    int x;
+  int x;
 };
 
 struct alignas(16384) larry {
-    int x;
+  int x;
 };
 
 bool misaligned = false;
@@ -23,7 +23,7 @@ void grandchild(void) {
   if (alignment != 0)
     misaligned = true;
 
-  printf ("Grandchild: address modulo alignment %u\n", alignment);
+  printf("Grandchild: address modulo alignment %u\n", alignment);
 }
 
 // Even if the FakeStack frame is aligned by chance to 16384, we can use an
@@ -31,7 +31,7 @@ void grandchild(void) {
 void child(void) {
   page p1;
   uint alignment = (unsigned long)&p1 % alignof(page);
-  printf ("Child: address modulo alignment is %u\n", alignment);
+  printf("Child: address modulo alignment is %u\n", alignment);
   if (alignment != 0)
     misaligned = true;
 
@@ -40,10 +40,10 @@ void child(void) {
 
 // Check whether the FakeStack frame is sufficiently aligned. Alignment can
 // happen by chance, so try this on many threads if you don't want
-void *Thread(void *unused)  {
+void *Thread(void *unused) {
   larry l1;
   uint alignment = (unsigned long)&l1 % alignof(larry);
-  printf ("Thread: address modulo alignment is %u\n", alignment);
+  printf("Thread: address modulo alignment is %u\n", alignment);
   if (alignment != 0)
     misaligned = true;
 
@@ -58,15 +58,15 @@ int main(int argc, char **argv) {
 
   pthread_t t[10];
   for (int i = 0; i < 10; i++) {
-     pthread_create(&t[i], &attr, Thread, 0);
+    pthread_create(&t[i], &attr, Thread, 0);
   }
   pthread_attr_destroy(&attr);
   for (int i = 0; i < 10; i++) {
-     pthread_join(t[i], 0);
+    pthread_join(t[i], 0);
   }
 
   if (misaligned) {
-    printf ("Test failed: not perfectly aligned\n");
+    printf("Test failed: not perfectly aligned\n");
     exit(1);
   }
 

>From ad9be29dfad441a0a3bc9b3730e8e53f4300be4b Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sun, 10 Aug 2025 06:24:32 +0000
Subject: [PATCH 3/7] Simplify test case by removing useless steps

---
 .../asan/TestCases/fakestack_alignment.cpp    | 29 +++----------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index 0b0dbd17571bb..7c7105398d955 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -17,29 +17,8 @@ struct alignas(16384) larry {
 
 bool misaligned = false;
 
-void grandchild(void) {
-  larry l2;
-  uint alignment = (unsigned long)&l2 % alignof(larry);
-  if (alignment != 0)
-    misaligned = true;
-
-  printf("Grandchild: address modulo alignment %u\n", alignment);
-}
-
-// Even if the FakeStack frame is aligned by chance to 16384, we can use an
-// intervening stack frame to knock it out of alignment.
-void child(void) {
-  page p1;
-  uint alignment = (unsigned long)&p1 % alignof(page);
-  printf("Child: address modulo alignment is %u\n", alignment);
-  if (alignment != 0)
-    misaligned = true;
-
-  grandchild();
-}
-
 // Check whether the FakeStack frame is sufficiently aligned. Alignment can
-// happen by chance, so try this on many threads if you don't want
+// happen by chance, so try this on many threads.
 void *Thread(void *unused) {
   larry l1;
   uint alignment = (unsigned long)&l1 % alignof(larry);
@@ -56,12 +35,12 @@ int main(int argc, char **argv) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
 
-  pthread_t t[10];
-  for (int i = 0; i < 10; i++) {
+  pthread_t t[32];
+  for (int i = 0; i < 32; i++) {
     pthread_create(&t[i], &attr, Thread, 0);
   }
   pthread_attr_destroy(&attr);
-  for (int i = 0; i < 10; i++) {
+  for (int i = 0; i < 32; i++) {
     pthread_join(t[i], 0);
   }
 

>From cd20b4aff95feb8c90935e19e588fea7fe8d0321 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 11 Aug 2025 21:25:17 +0000
Subject: [PATCH 4/7] Merge with other test case: FakeStack frames for 4KB
 objects with smaller thread stack sizes

---
 .../asan/TestCases/fakestack_alignment.cpp    | 35 +++++++++++--------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index 7c7105398d955..05a2f2648fcb2 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -1,4 +1,12 @@
-// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 %s -o %t && %run %t 2>&1
+// This deterministically fails: when the stack size is 1<<16, FakeStack's
+// GetFrame() is out of alignment, because SizeRequiredForFlags(16) == 2K.
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=4096 -DTHREAD_COUNT=1 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
+
+// The FakeStack frame is not guaranteed to be aligned, but alignment can
+// happen by chance, so try this on many threads.
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=8192 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=16384 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+
 // XFAIL: *
 
 #include <assert.h>
@@ -7,11 +15,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-struct alignas(4096) page {
-  int x;
-};
-
-struct alignas(16384) larry {
+struct alignas(ALIGNMENT) big_object {
   int x;
 };
 
@@ -20,29 +24,30 @@ bool misaligned = false;
 // Check whether the FakeStack frame is sufficiently aligned. Alignment can
 // happen by chance, so try this on many threads.
 void *Thread(void *unused) {
-  larry l1;
-  uint alignment = (unsigned long)&l1 % alignof(larry);
+  big_object x;
+  uint alignment = (unsigned long)&x % alignof(big_object);
   printf("Thread: address modulo alignment is %u\n", alignment);
   if (alignment != 0)
     misaligned = true;
 
-  child();
-
   return NULL;
 }
 
 int main(int argc, char **argv) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
+  #ifdef THREAD_STACK_SIZE
+  pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
+  #endif
 
-  pthread_t t[32];
-  for (int i = 0; i < 32; i++) {
+  pthread_t t[THREAD_COUNT];
+  for (int i = 0; i < THREAD_COUNT; i++)
     pthread_create(&t[i], &attr, Thread, 0);
-  }
+
   pthread_attr_destroy(&attr);
-  for (int i = 0; i < 32; i++) {
+
+  for (int i = 0; i < THREAD_COUNT; i++)
     pthread_join(t[i], 0);
-  }
 
   if (misaligned) {
     printf("Test failed: not perfectly aligned\n");

>From b370e6a08d81f80d1f1f5887423b7e2526c1d40c Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 11 Aug 2025 21:31:03 +0000
Subject: [PATCH 5/7] Hide redundant test output, add more test combinations

---
 .../asan/TestCases/fakestack_alignment.cpp    | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index 05a2f2648fcb2..d1df72b669971 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -1,10 +1,20 @@
+// Regression test 1:
 // This deterministically fails: when the stack size is 1<<16, FakeStack's
 // GetFrame() is out of alignment, because SizeRequiredForFlags(16) == 2K.
-// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=4096 -DTHREAD_COUNT=1 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=4096  -DTHREAD_COUNT=1 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
 
+// Regression test 2:
 // The FakeStack frame is not guaranteed to be aligned, but alignment can
 // happen by chance, so try this on many threads.
-// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=8192 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=8192  -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=16384 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+
+// Extra tests:
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=4096  -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=8192  -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=16384 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=65536 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=4096  -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=8192  -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
 // RUN: %clangxx_asan -fsanitize-address-use-after-return=always -O0 -DALIGNMENT=16384 -DTHREAD_COUNT=32 -DTHREAD_STACK_SIZE=131072 %s -o %t && %run %t 2>&1
 
 // XFAIL: *
@@ -26,10 +36,10 @@ bool misaligned = false;
 void *Thread(void *unused) {
   big_object x;
   uint alignment = (unsigned long)&x % alignof(big_object);
-  printf("Thread: address modulo alignment is %u\n", alignment);
-  if (alignment != 0)
+  if (alignment != 0) {
+    printf("Thread: address modulo alignment is %u\n", alignment);
     misaligned = true;
-
+  }
   return NULL;
 }
 

>From 53b138e4c745121b7f9204e7edf22af396892a20 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 11 Aug 2025 21:34:15 +0000
Subject: [PATCH 6/7] Hide output (it's too much bother making printing the
 first instance only non-racy)

---
 compiler-rt/test/asan/TestCases/fakestack_alignment.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index d1df72b669971..a5eb80ba3b3fb 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -36,10 +36,10 @@ bool misaligned = false;
 void *Thread(void *unused) {
   big_object x;
   uint alignment = (unsigned long)&x % alignof(big_object);
-  if (alignment != 0) {
-    printf("Thread: address modulo alignment is %u\n", alignment);
+
+  if (alignment != 0)
     misaligned = true;
-  }
+
   return NULL;
 }
 

>From 0584edf70a9018fb683731644e9d4ed69ec579bb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 11 Aug 2025 21:49:01 +0000
Subject: [PATCH 7/7] clang-format

---
 compiler-rt/test/asan/TestCases/fakestack_alignment.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
index a5eb80ba3b3fb..4ef341f266c41 100644
--- a/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
+++ b/compiler-rt/test/asan/TestCases/fakestack_alignment.cpp
@@ -46,9 +46,9 @@ void *Thread(void *unused) {
 int main(int argc, char **argv) {
   pthread_attr_t attr;
   pthread_attr_init(&attr);
-  #ifdef THREAD_STACK_SIZE
+#ifdef THREAD_STACK_SIZE
   pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
-  #endif
+#endif
 
   pthread_t t[THREAD_COUNT];
   for (int i = 0; i < THREAD_COUNT; i++)



More information about the llvm-commits mailing list