[compiler-rt] [Coverage] Add testing to validate code coverage for exceptions (PR #133463)

Justin Cady via llvm-commits llvm-commits at lists.llvm.org
Tue May 20 08:29:07 PDT 2025


https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/133463

>From 40c451b28f69a3d56cc40579639b1799a769b92f Mon Sep 17 00:00:00 2001
From: Justin Cady <desk at justincady.com>
Date: Wed, 7 May 2025 09:15:01 -0400
Subject: [PATCH] [Coverage] Add testing to validate code coverage for
 exceptions

While investigating an issue with code coverage reporting around
exceptions it was useful to have a baseline of what works today.

This change adds end-to-end testing to validate code coverage behavior
that is currently working with regards to exception handling.
---
 .../test/profile/Linux/coverage-exception.cpp | 144 ++++++++++++++++++
 1 file changed, 144 insertions(+)
 create mode 100755 compiler-rt/test/profile/Linux/coverage-exception.cpp

diff --git a/compiler-rt/test/profile/Linux/coverage-exception.cpp b/compiler-rt/test/profile/Linux/coverage-exception.cpp
new file mode 100755
index 0000000000000..3f0c907764269
--- /dev/null
+++ b/compiler-rt/test/profile/Linux/coverage-exception.cpp
@@ -0,0 +1,144 @@
+// REQUIRES: lld-available
+// XFAIL: powerpc64-target-arch
+
+// RUN: %clangxx_profgen -std=c++17 -fuse-ld=lld -fcoverage-mapping -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TRY_AND_CATCH_ALL(x)                                                   \
+  try {                                                                        \
+    (x);                                                                       \
+  } catch (...) {                                                              \
+  }
+
+#define TRY_MAYBE_CRASH(x)                                                     \
+  try {                                                                        \
+    if ((x)) {                                                                 \
+      printf("no crash\n");                                                    \
+    } else {                                                                   \
+      abort();                                                                 \
+    }                                                                          \
+  } catch (...) {                                                              \
+  }
+
+#define TRY_AND_CATCH_CRASHES(x)                                               \
+  try {                                                                        \
+    (x);                                                                       \
+  } catch (...) {                                                              \
+    abort();                                                                   \
+  }
+
+static __attribute__((noinline)) int do_throw(bool b) {
+  if (b)
+    throw b;
+  return 1;
+}
+
+// clang-format off
+static
+int test_no_exception() {               // CHECK:  [[@LINE]]| 1|int test_no_exception()
+  try {                                 // CHECK:  [[@LINE]]| 1|  try {
+    do_throw(false);                    // CHECK:  [[@LINE]]| 1|    do_throw(
+  } catch (...) {                       // CHECK:  [[@LINE]]| 1|  } catch (
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  }                                     // CHECK:  [[@LINE]]| 0|  }
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_no_exception_macro() {         // CHECK:  [[@LINE]]| 1|int test_no_exception_macro()
+  TRY_AND_CATCH_ALL(do_throw(false));   // CHECK:  [[@LINE]]| 1|  TRY_AND_CATCH_ALL(
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_exception() {                  // CHECK:  [[@LINE]]| 1|int test_exception()
+  try {                                 // CHECK:  [[@LINE]]| 1|  try {
+    do_throw(true);                     // CHECK:  [[@LINE]]| 1|    do_throw(
+  } catch (...) {                       // CHECK:  [[@LINE]]| 1|  } catch (
+    printf("%s\n", __func__);           // CHECK:  [[@LINE]]| 1|    printf(
+  }                                     // CHECK:  [[@LINE]]| 1|  }
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_exception_macro() {            // CHECK:  [[@LINE]]| 1|int test_exception_macro()
+  TRY_AND_CATCH_ALL(do_throw(true));    // CHECK:  [[@LINE]]| 1|  TRY_AND_CATCH_ALL(
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_exception_macro_nested() {     // CHECK:  [[@LINE]]| 1|int test_exception_macro_nested()
+  try {                                 // CHECK:  [[@LINE]]| 1|  try {
+    TRY_AND_CATCH_ALL(do_throw(true));  // CHECK:  [[@LINE]]| 1|    TRY_AND_CATCH_ALL(
+  } catch (...) {                       // CHECK:  [[@LINE]]| 1|  } catch (
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  }                                     // CHECK:  [[@LINE]]| 0|  }
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_exception_try_crash() {        // CHECK:  [[@LINE]]| 1|int test_exception_try_crash()
+  TRY_MAYBE_CRASH(do_throw(false));     // CHECK:  [[@LINE]]| 1|  TRY_MAYBE_CRASH(
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_exception_crash() {            // CHECK:  [[@LINE]]| 1|int test_exception_crash()
+  TRY_AND_CATCH_CRASHES(do_throw(false)); // CHECK:  [[@LINE]]| 1|  TRY_AND_CATCH_CRASHES(
+  printf("%s\n", __func__);             // CHECK:  [[@LINE]]| 1|  printf(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+static
+int test_conditional(int i) {           // CHECK:  [[@LINE]]| 1|int test_conditional(int i)
+  try {                                 // CHECK:  [[@LINE]]| 1|  try {
+    if (i % 2 == 0) {                   // CHECK:  [[@LINE]]| 1|    if (
+      printf("%s\n", __func__);         // CHECK:  [[@LINE]]| 1|      printf(
+    } else {                            // CHECK:  [[@LINE]]| 1|    } else {
+      do_throw(true);                   // CHECK:  [[@LINE]]| 0|      do_throw(
+    }                                   // CHECK:  [[@LINE]]| 0|    }
+  } catch (...) {                       // CHECK:  [[@LINE]]| 1|  } catch (
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  }                                     // CHECK:  [[@LINE]]| 0|  }
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}
+
+static
+int test_multiple_catch() {             // CHECK:  [[@LINE]]| 1|int test_multiple_catch()
+  try {                                 // CHECK:  [[@LINE]]| 1|  try {
+    do_throw(true);                     // CHECK:  [[@LINE]]| 1|    do_throw(
+  } catch (double) {                    // CHECK:  [[@LINE]]| 1|  } catch (double)
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  } catch (bool) {                      // CHECK:  [[@LINE]]| 1|  } catch (bool)
+    printf("bool\n");                   // CHECK:  [[@LINE]]| 1|    printf(
+  } catch (float) {                     // CHECK:  [[@LINE]]| 1|  } catch (float)
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  } catch (...) {                       // CHECK:  [[@LINE]]| 0|  } catch (
+    abort();                            // CHECK:  [[@LINE]]| 0|    abort(
+  }                                     // CHECK:  [[@LINE]]| 0|  }
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+
+int main() {                            // CHECK:  [[@LINE]]| 1|int main()
+  test_no_exception();                  // CHECK:  [[@LINE]]| 1|  test_no_exception(
+  test_no_exception_macro();            // CHECK:  [[@LINE]]| 1|  test_no_exception_macro(
+  test_exception();                     // CHECK:  [[@LINE]]| 1|  test_exception(
+  test_exception_macro();               // CHECK:  [[@LINE]]| 1|  test_exception_macro(
+  test_exception_macro_nested();        // CHECK:  [[@LINE]]| 1|  test_exception_macro_nested(
+  test_exception_try_crash();           // CHECK:  [[@LINE]]| 1|  test_exception_try_crash(
+  test_exception_crash();               // CHECK:  [[@LINE]]| 1|  test_exception_crash(
+  test_conditional(2);                  // CHECK:  [[@LINE]]| 1|  test_conditional(
+  test_multiple_catch();                // CHECK:  [[@LINE]]| 1|  test_multiple_catch(
+  return 0;                             // CHECK:  [[@LINE]]| 1|  return
+}                                       // CHECK:  [[@LINE]]| 1|}
+// clang-format on



More information about the llvm-commits mailing list