[compiler-rt] [compiler-rt][nsan] Add support for nan detection (PR #101531)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 7 00:06:23 PDT 2024


https://github.com/cseslowpoke updated https://github.com/llvm/llvm-project/pull/101531

>From 3a70ccbc4a07edc7659aba4ccbdfec06182a3801 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Wed, 31 Jul 2024 19:52:05 +0800
Subject: [PATCH 1/7] [compiler-rt][nsan] Add support for NaN detection

---
 compiler-rt/lib/nsan/nsan.cpp       | 8 ++++++++
 compiler-rt/lib/nsan/nsan_flags.inc | 1 +
 2 files changed, 9 insertions(+)

diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp
index 568a1b3a65575..9c505193daa00 100644
--- a/compiler-rt/lib/nsan/nsan.cpp
+++ b/compiler-rt/lib/nsan/nsan.cpp
@@ -444,6 +444,14 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
   const InternalFT check_value = value;
   const InternalFT check_shadow = Shadow;
 
+  // We only check for NaNs in the value, not the shadow.
+  if (flags().check_nan && isnan(check_value)) {
+    Decorator D;
+    Printf("%s", D.Warning());
+    Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
+    Printf("%s", D.Default());
+  }
+
   // See this article for an interesting discussion of how to compare floats:
   // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
   static constexpr const FT Eps = FTInfo<FT>::kEpsilon;
diff --git a/compiler-rt/lib/nsan/nsan_flags.inc b/compiler-rt/lib/nsan/nsan_flags.inc
index 63c15475f6754..321305d386dbd 100644
--- a/compiler-rt/lib/nsan/nsan_flags.inc
+++ b/compiler-rt/lib/nsan/nsan_flags.inc
@@ -47,3 +47,4 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
           "memory, the number of times nsan resumed from the original value "
           "due to invalid or unknown types.")
 NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
+NSAN_FLAG(bool, check_nan, false, "If true, check the floating-point number is nan")
\ No newline at end of file

>From a43e25ed97b8dc80d86f092e3fc46510d6a76538 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Thu, 1 Aug 2024 19:54:30 +0800
Subject: [PATCH 2/7] [compiler-rt][nsan] Add test for NaN dectection

---
 compiler-rt/test/nsan/nan.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 compiler-rt/test/nsan/nan.cpp

diff --git a/compiler-rt/test/nsan/nan.cpp b/compiler-rt/test/nsan/nan.cpp
new file mode 100644
index 0000000000000..ce38c1abd9f44
--- /dev/null
+++ b/compiler-rt/test/nsan/nan.cpp
@@ -0,0 +1,22 @@
+// RUN: %clangxx_nsan -O0 -g %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true %run %t 2>&1 | FileCheck %s
+
+
+#include<cmath>
+#include<cstdio>
+
+// This function returns a NaN value for triggering the NaN detection.
+__attribute__((noinline))  
+float ReturnNaN() {
+  float ret = 0.0 / 0.0;
+  return ret;
+  // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+}
+
+
+int main() {
+  float val = ReturnNaN();
+  printf("val: %f\n", val);
+  // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  return 0;
+}

>From e6017b53bf27fbbd9ca55a60ff50af78c8986eae Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Fri, 2 Aug 2024 01:40:49 +0800
Subject: [PATCH 3/7] update formatting

---
 compiler-rt/lib/nsan/nsan_flags.inc | 3 ++-
 compiler-rt/test/nsan/nan.cpp       | 9 +++------
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/lib/nsan/nsan_flags.inc b/compiler-rt/lib/nsan/nsan_flags.inc
index 321305d386dbd..2c67c4bb7f779 100644
--- a/compiler-rt/lib/nsan/nsan_flags.inc
+++ b/compiler-rt/lib/nsan/nsan_flags.inc
@@ -47,4 +47,5 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
           "memory, the number of times nsan resumed from the original value "
           "due to invalid or unknown types.")
 NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
-NSAN_FLAG(bool, check_nan, false, "If true, check the floating-point number is nan")
\ No newline at end of file
+NSAN_FLAG(bool, check_nan, false,
+          "If true, check the floating-point number is nan")
\ No newline at end of file
diff --git a/compiler-rt/test/nsan/nan.cpp b/compiler-rt/test/nsan/nan.cpp
index ce38c1abd9f44..a84b51859aaed 100644
--- a/compiler-rt/test/nsan/nan.cpp
+++ b/compiler-rt/test/nsan/nan.cpp
@@ -1,19 +1,16 @@
 // RUN: %clangxx_nsan -O0 -g %s -o %t
 // RUN: NSAN_OPTIONS=check_nan=true %run %t 2>&1 | FileCheck %s
 
-
-#include<cmath>
-#include<cstdio>
+#include <cmath>
+#include <cstdio>
 
 // This function returns a NaN value for triggering the NaN detection.
-__attribute__((noinline))  
-float ReturnNaN() {
+__attribute__((noinline)) float ReturnNaN() {
   float ret = 0.0 / 0.0;
   return ret;
   // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
 }
 
-
 int main() {
   float val = ReturnNaN();
   printf("val: %f\n", val);

>From acfd2c85b8806d378e27f5e6f9b382cccedf4d01 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Sat, 3 Aug 2024 10:38:43 +0800
Subject: [PATCH 4/7] Change flag default and Return early when NaN is found.

---
 compiler-rt/lib/nsan/nsan.cpp       | 3 +++
 compiler-rt/lib/nsan/nsan_flags.inc | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp
index 9c505193daa00..fa99c05f4f590 100644
--- a/compiler-rt/lib/nsan/nsan.cpp
+++ b/compiler-rt/lib/nsan/nsan.cpp
@@ -450,6 +450,9 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
     Printf("%s", D.Warning());
     Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
     Printf("%s", D.Default());
+    stack.Print();
+    // Checking for NaN values is meaningless when dealing with numbers. 
+    return kResumeFromValue;
   }
 
   // See this article for an interesting discussion of how to compare floats:
diff --git a/compiler-rt/lib/nsan/nsan_flags.inc b/compiler-rt/lib/nsan/nsan_flags.inc
index 2c67c4bb7f779..52ca95a084dc4 100644
--- a/compiler-rt/lib/nsan/nsan_flags.inc
+++ b/compiler-rt/lib/nsan/nsan_flags.inc
@@ -47,5 +47,5 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
           "memory, the number of times nsan resumed from the original value "
           "due to invalid or unknown types.")
 NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
-NSAN_FLAG(bool, check_nan, false,
+NSAN_FLAG(bool, check_nan, true,
           "If true, check the floating-point number is nan")
\ No newline at end of file

>From f15bec8fbac68627b1bcf321b38417f472e555f9 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Mon, 5 Aug 2024 09:24:27 +0000
Subject: [PATCH 5/7] Show stack info for NaN check and add softmax test

---
 compiler-rt/lib/nsan/nsan.cpp     | 10 ++++++-
 compiler-rt/test/nsan/softmax.cpp | 45 +++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 compiler-rt/test/nsan/softmax.cpp

diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp
index fa99c05f4f590..d5bdcac5da981 100644
--- a/compiler-rt/lib/nsan/nsan.cpp
+++ b/compiler-rt/lib/nsan/nsan.cpp
@@ -446,12 +446,20 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
 
   // We only check for NaNs in the value, not the shadow.
   if (flags().check_nan && isnan(check_value)) {
+    GET_CALLER_PC_BP;
+    BufferedStackTrace stack;
+    stack.Unwind(pc, bp, nullptr, false);
+    if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {
+      // FIXME: optionally print.
+      return flags().resume_after_suppression ? kResumeFromValue
+                                              : kContinueWithShadow;
+    }
     Decorator D;
     Printf("%s", D.Warning());
     Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
     Printf("%s", D.Default());
     stack.Print();
-    // Checking for NaN values is meaningless when dealing with numbers. 
+    // Performing other tests for NaN values is meaningless when dealing with numbers.
     return kResumeFromValue;
   }
 
diff --git a/compiler-rt/test/nsan/softmax.cpp b/compiler-rt/test/nsan/softmax.cpp
new file mode 100644
index 0000000000000..fe4a2d960020a
--- /dev/null
+++ b/compiler-rt/test/nsan/softmax.cpp
@@ -0,0 +1,45 @@
+// RUN: %clangxx_nsan -O0 -g %s -o %t
+// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+#include<iostream>
+#include<vector>
+#include<algorithm>
+#include<cmath>
+
+__attribute__((noinline)) void softmax(std::vector<double> &values) {
+    double sum_exp = 0.0;
+    for (auto &i: values) {
+      i = std::exp(i);
+      sum_exp += i;
+    }
+    for (auto &i: values) {
+      i /= sum_exp;
+    }
+}
+
+__attribute__((noinline)) void stable_softmax(std::vector<double> values) {
+  double sum_exp = 0.0;
+  double max_values = *std::max_element(values.begin(), values.end());
+  for (auto &i: values) {
+    i = std::exp(i - max_values);
+    sum_exp += i;
+  }
+  for (auto &i:values) {
+    i /= sum_exp;
+  }
+}
+
+int main() {
+  std::vector<double> data = {1000, 1001, 1002};
+  stable_softmax(data);
+  for (auto i:data) {
+    printf("%f ", i);
+  }
+  printf("\n");
+  data = {1000, 1001, 1002};
+  softmax(data);
+  for (auto i:data) {
+    printf("%f", i);
+    // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  }
+  printf("\n");
+}
\ No newline at end of file

>From 22231fec75180a82219c2ff82c6b92fe177a2f37 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Tue, 6 Aug 2024 12:32:29 +0000
Subject: [PATCH 6/7] change nsan test

---
 compiler-rt/test/nsan/softmax.cpp | 36 +++++++++++++++++--------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/compiler-rt/test/nsan/softmax.cpp b/compiler-rt/test/nsan/softmax.cpp
index fe4a2d960020a..36dabcdc07bab 100644
--- a/compiler-rt/test/nsan/softmax.cpp
+++ b/compiler-rt/test/nsan/softmax.cpp
@@ -1,12 +1,20 @@
-// RUN: %clangxx_nsan -O0 -g %s -o %t
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
 // RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
+// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
+// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
+// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1
+
 #include<iostream>
 #include<vector>
 #include<algorithm>
 #include<cmath>
-
-__attribute__((noinline)) void softmax(std::vector<double> &values) {
-    double sum_exp = 0.0;
+// unstable softmax
+template <typename T>
+__attribute__((noinline)) void softmax(std::vector<T> &values) {
+    T sum_exp = 0.0;
     for (auto &i: values) {
       i = std::exp(i);
       sum_exp += i;
@@ -16,9 +24,12 @@ __attribute__((noinline)) void softmax(std::vector<double> &values) {
     }
 }
 
-__attribute__((noinline)) void stable_softmax(std::vector<double> values) {
-  double sum_exp = 0.0;
-  double max_values = *std::max_element(values.begin(), values.end());
+// use max value to avoid overflow
+// \sigma_i exp(x_i) / \sum_j exp(x_j) = \sigma_i exp(x_i - max(x)) / \sum_j exp(x_j - max(x))
+template <typename T>
+__attribute__((noinline)) void stable_softmax(std::vector<T> values) {
+  T sum_exp = 0.0;
+  T max_values = *std::max_element(values.begin(), values.end());
   for (auto &i: values) {
     i = std::exp(i - max_values);
     sum_exp += i;
@@ -30,16 +41,9 @@ __attribute__((noinline)) void stable_softmax(std::vector<double> values) {
 
 int main() {
   std::vector<double> data = {1000, 1001, 1002};
-  stable_softmax(data);
-  for (auto i:data) {
-    printf("%f ", i);
-  }
-  printf("\n");
-  data = {1000, 1001, 1002};
-  softmax(data);
-  for (auto i:data) {
+  SOFTMAX(data);
+  for (auto i: data) {
     printf("%f", i);
     // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
   }
-  printf("\n");
 }
\ No newline at end of file

>From 9215016daae4a095628869a495c0e77027f3b5a0 Mon Sep 17 00:00:00 2001
From: cseslowpoke <cseslowpoke at gmail.com>
Date: Wed, 7 Aug 2024 15:04:37 +0800
Subject: [PATCH 7/7] Change default mode for check-nan and update some test
 defaults

---
 compiler-rt/lib/nsan/nsan_flags.inc | 2 +-
 compiler-rt/test/nsan/nan.cpp       | 2 +-
 compiler-rt/test/nsan/softmax.cpp   | 8 ++++----
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/compiler-rt/lib/nsan/nsan_flags.inc b/compiler-rt/lib/nsan/nsan_flags.inc
index 52ca95a084dc4..2c67c4bb7f779 100644
--- a/compiler-rt/lib/nsan/nsan_flags.inc
+++ b/compiler-rt/lib/nsan/nsan_flags.inc
@@ -47,5 +47,5 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
           "memory, the number of times nsan resumed from the original value "
           "due to invalid or unknown types.")
 NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
-NSAN_FLAG(bool, check_nan, true,
+NSAN_FLAG(bool, check_nan, false,
           "If true, check the floating-point number is nan")
\ No newline at end of file
diff --git a/compiler-rt/test/nsan/nan.cpp b/compiler-rt/test/nsan/nan.cpp
index a84b51859aaed..db94c6e887bbf 100644
--- a/compiler-rt/test/nsan/nan.cpp
+++ b/compiler-rt/test/nsan/nan.cpp
@@ -1,5 +1,5 @@
 // RUN: %clangxx_nsan -O0 -g %s -o %t
-// RUN: NSAN_OPTIONS=check_nan=true %run %t 2>&1 | FileCheck %s
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
 
 #include <cmath>
 #include <cstdio>
diff --git a/compiler-rt/test/nsan/softmax.cpp b/compiler-rt/test/nsan/softmax.cpp
index 36dabcdc07bab..bcc3e3a964103 100644
--- a/compiler-rt/test/nsan/softmax.cpp
+++ b/compiler-rt/test/nsan/softmax.cpp
@@ -1,11 +1,11 @@
 // RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
-// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
-// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
-// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1 
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 
 // RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
-// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t 2>&1
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1
 
 #include<iostream>
 #include<vector>



More information about the llvm-commits mailing list