[compiler-rt] [asan][test] Check that stack traces are not truncated (PR #221518)

Matt Turner via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 5 21:12:04 PDT 2026


https://github.com/mattst88 created https://github.com/llvm/llvm-project/pull/221518

Add a test that the access, free and malloc traces each name the whole call
chain down to `main`, in order, and that each names its own call site in
`main`. A trace that stops early -- as every trace but the access one does when
the fast unwinder runs on a target that chains no frames -- fails it.

`deep_stack_uaf.cpp` already covers trace depth, but it looks for three
individual frames anywhere in the trace, so it passes on a trace with holes in
it, and it needs C++ name demangling to do that.

Split out of #220231 at reviewer request.


>From 7f092e877df8655f915cebcb3ffe64bee6c6783a Mon Sep 17 00:00:00 2001
From: Matt Turner <mattst88 at gmail.com>
Date: Sat, 5 Sep 2026 22:29:55 -0400
Subject: [PATCH] [asan][test] Check that stack traces are not truncated

Add a test that the access, free and malloc traces each name the whole
call chain down to main, in order, and that each names its own call site
in main. A trace that stops early -- as every trace but the access one
does when the fast unwinder runs on a target that chains no frames --
fails it.

deep_stack_uaf.cpp already covers trace depth, but it looks for three
individual frames anywhere in the trace, so it passes on a trace with
holes in it, and it needs C++ name demangling to do that.

Assisted-by: Claude Code
---
 .../asan/TestCases/complete_stack_trace.c     | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 compiler-rt/test/asan/TestCases/complete_stack_trace.c

diff --git a/compiler-rt/test/asan/TestCases/complete_stack_trace.c b/compiler-rt/test/asan/TestCases/complete_stack_trace.c
new file mode 100644
index 0000000000000..d9f01af6ed217
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/complete_stack_trace.c
@@ -0,0 +1,52 @@
+// Check that a report's stack traces are complete: the access, the free and the
+// malloc traces must each name the whole call chain, not just the innermost
+// frame or two. An unwinder that walks a frame layout the target does not use
+// stops early and still prints a plausible looking report.
+
+// RUN: %clang_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+
+char *p;
+
+__attribute__((noinline)) void alloc_3(void) { p = (char *)malloc(10); }
+__attribute__((noinline)) void alloc_2(void) { alloc_3(); }
+__attribute__((noinline)) void alloc_1(void) { alloc_2(); }
+
+__attribute__((noinline)) void free_3(void) { free(p); }
+__attribute__((noinline)) void free_2(void) { free_3(); }
+__attribute__((noinline)) void free_1(void) { free_2(); }
+
+__attribute__((noinline)) char read_3(void) { return p[5]; }
+__attribute__((noinline)) char read_2(void) { return read_3(); }
+__attribute__((noinline)) char read_1(void) { return read_2(); }
+
+int main() {
+  alloc_1();
+  free_1();
+  return read_1();
+}
+
+// The free and malloc traces start inside the interceptor, whose frame count
+// varies, so only the chain below it is pinned. main's three call sites are on
+// three lines, so each trace has to name its own.
+
+// CHECK: ERROR: AddressSanitizer: heap-use-after-free on address
+// CHECK: READ of size 1 at 0x{{.*}} thread T0
+// CHECK-NEXT: {{ *#0 0x.* in read_3 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#1 0x.* in read_2 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#2 0x.* in read_1 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#3 0x.* in main .*complete_stack_trace.c:}}[[@LINE-12]]
+
+// CHECK: freed by thread T0 here:
+// CHECK: {{ *#[0-9]+ 0x.* in free_3 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in free_2 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in free_1 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in main .*complete_stack_trace.c:}}[[@LINE-19]]
+
+// CHECK: previously allocated by thread T0 here:
+// CHECK: {{ *#[0-9]+ 0x.* in alloc_3 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in alloc_2 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in alloc_1 .*complete_stack_trace.c}}
+// CHECK-NEXT: {{ *#[0-9]+ 0x.* in main .*complete_stack_trace.c:}}[[@LINE-26]]



More information about the llvm-commits mailing list