[gcc/devel/c++-modules] analyzer: fix ICE when canonicalizing NaN (PR 93451)
Nathan Sidwell
nathan@gcc.gnu.org
Fri Jan 31 17:48:00 GMT 2020
https://gcc.gnu.org/g:8c08c983015e675f555d57a30e15d918abef2b93
commit 8c08c983015e675f555d57a30e15d918abef2b93
Author: David Malcolm <dmalcolm@redhat.com>
Date: Mon Jan 27 16:23:43 2020 -0500
analyzer: fix ICE when canonicalizing NaN (PR 93451)
PR analyzer/93451 reports an ICE when canonicalizing the constants
in a region_model, with a failed qsort_chk when attempting to sort
the constants within the region_model.
The svalues in the model were:
sv0: {poisoned: uninit}
sv1: {type: âÂÂdoubleâÂÂ, âÂÂ0.0âÂÂ}
sv2: {type: âÂÂdoubleâÂÂ, âÂÂ1.0e+0âÂÂ}
sv3: {type: âÂÂdoubleâÂÂ, â NanâÂÂ}
The qsort_chk of the 3 constants fails due to tree_cmp using the
LT_EXPR ordering of the REAL_CSTs, which doesn't work for NaN.
This patch adjusts tree_cmp to impose an arbitrary ordering during
canonicalization for UNORDERED_EXPR cases w/o relying on the LT_EXPR
ordering, fixing the ICE.
gcc/analyzer/ChangeLog:
PR analyzer/93451
* region-model.cc (tree_cmp): For the REAL_CST case, impose an
arbitrary order on NaNs relative to other NaNs and to non-NaNs;
const-correctness tweak.
(ana::selftests::build_real_cst_from_string): New function.
(ana::selftests::append_interesting_constants): New function.
(ana::selftests::test_tree_cmp_on_constants): New test.
(ana::selftests::test_canonicalization_4): New test.
(ana::selftests::analyzer_region_model_cc_tests): Call the new
tests.
gcc/testsuite/ChangeLog:
PR analyzer/93451
* gcc.dg/analyzer/torture/pr93451.c: New test.
Diff:
---
gcc/analyzer/ChangeLog | 13 ++++
gcc/analyzer/region-model.cc | 90 ++++++++++++++++++++++++-
gcc/testsuite/ChangeLog | 5 ++
gcc/testsuite/gcc.dg/analyzer/torture/pr93451.c | 14 ++++
4 files changed, 119 insertions(+), 3 deletions(-)
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 3a2d179..9ba6adc 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,5 +1,18 @@
2020-01-27 David Malcolm <dmalcolm@redhat.com>
+ PR analyzer/93451
+ * region-model.cc (tree_cmp): For the REAL_CST case, impose an
+ arbitrary order on NaNs relative to other NaNs and to non-NaNs;
+ const-correctness tweak.
+ (ana::selftests::build_real_cst_from_string): New function.
+ (ana::selftests::append_interesting_constants): New function.
+ (ana::selftests::test_tree_cmp_on_constants): New test.
+ (ana::selftests::test_canonicalization_4): New test.
+ (ana::selftests::analyzer_region_model_cc_tests): Call the new
+ tests.
+
+2020-01-27 David Malcolm <dmalcolm@redhat.com>
+
PR analyzer/93349
* engine.cc (run_checkers): Save and restore input_location.
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index a986549..62c96a6 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1811,11 +1811,22 @@ tree_cmp (const_tree t1, const_tree t2)
case REAL_CST:
{
- real_value *rv1 = TREE_REAL_CST_PTR (t1);
- real_value *rv2 = TREE_REAL_CST_PTR (t2);
+ const real_value *rv1 = TREE_REAL_CST_PTR (t1);
+ const real_value *rv2 = TREE_REAL_CST_PTR (t2);
+ if (real_compare (UNORDERED_EXPR, rv1, rv2))
+ {
+ /* Impose an arbitrary order on NaNs relative to other NaNs
+ and to non-NaNs. */
+ if (int cmp_isnan = real_isnan (rv1) - real_isnan (rv2))
+ return cmp_isnan;
+ if (int cmp_issignaling_nan
+ = real_issignaling_nan (rv1) - real_issignaling_nan (rv2))
+ return cmp_issignaling_nan;
+ return real_isneg (rv1) - real_isneg (rv2);
+ }
if (real_compare (LT_EXPR, rv1, rv2))
return -1;
- if (real_compare (LT_EXPR, rv2, rv1))
+ if (real_compare (GT_EXPR, rv1, rv2))
return 1;
return 0;
}
@@ -6927,6 +6938,58 @@ namespace ana {
namespace selftest {
+/* Build a constant tree of the given type from STR. */
+
+static tree
+build_real_cst_from_string (tree type, const char *str)
+{
+ REAL_VALUE_TYPE real;
+ real_from_string (&real, str);
+ return build_real (type, real);
+}
+
+/* Append various "interesting" constants to OUT (e.g. NaN). */
+
+static void
+append_interesting_constants (auto_vec<tree> *out)
+{
+ out->safe_push (build_int_cst (integer_type_node, 0));
+ out->safe_push (build_int_cst (integer_type_node, 42));
+ out->safe_push (build_int_cst (unsigned_type_node, 0));
+ out->safe_push (build_int_cst (unsigned_type_node, 42));
+ out->safe_push (build_real_cst_from_string (float_type_node, "QNaN"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "-QNaN"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "SNaN"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "-SNaN"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "0.0"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "-0.0"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "Inf"));
+ out->safe_push (build_real_cst_from_string (float_type_node, "-Inf"));
+}
+
+/* Verify that tree_cmp is a well-behaved comparator for qsort, even
+ if the underlying constants aren't comparable. */
+
+static void
+test_tree_cmp_on_constants ()
+{
+ auto_vec<tree> csts;
+ append_interesting_constants (&csts);
+
+ /* Try sorting every triple. */
+ const unsigned num = csts.length ();
+ for (unsigned i = 0; i < num; i++)
+ for (unsigned j = 0; j < num; j++)
+ for (unsigned k = 0; k < num; k++)
+ {
+ auto_vec<tree> v (3);
+ v.quick_push (csts[i]);
+ v.quick_push (csts[j]);
+ v.quick_push (csts[k]);
+ v.qsort (tree_cmp);
+ }
+}
+
/* Implementation detail of the ASSERT_CONDITION_* macros. */
void
@@ -7577,6 +7640,25 @@ test_canonicalization_3 ()
ASSERT_EQ (model0, model1);
}
+/* Verify that we can canonicalize a model containing NaN and other real
+ constants. */
+
+static void
+test_canonicalization_4 ()
+{
+ auto_vec<tree> csts;
+ append_interesting_constants (&csts);
+
+ region_model model;
+
+ unsigned i;
+ tree cst;
+ FOR_EACH_VEC_ELT (csts, i, cst)
+ model.get_rvalue (cst, NULL);
+
+ model.canonicalize (NULL);
+}
+
/* Assert that if we have two region_model instances
with values VAL_A and VAL_B for EXPR that they are
mergable. Write the merged model to *OUT_MERGED_MODEL,
@@ -7957,6 +8039,7 @@ test_constraint_merging ()
void
analyzer_region_model_cc_tests ()
{
+ test_tree_cmp_on_constants ();
test_dump ();
test_unique_constants ();
test_svalue_equality ();
@@ -7969,6 +8052,7 @@ analyzer_region_model_cc_tests ()
test_canonicalization_1 ();
test_canonicalization_2 ();
test_canonicalization_3 ();
+ test_canonicalization_4 ();
test_state_merging ();
test_constraint_merging ();
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f81caf5..f83f18b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-01-27 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/93451
+ * gcc.dg/analyzer/torture/pr93451.c: New test.
+
2020-01-27 Stam Markianos-Wright <stam.markianos-wright@arm.com>
* gcc.target/arm/armv8_2-fp16-move-1.c: Update following load/store
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/pr93451.c b/gcc/testsuite/gcc.dg/analyzer/torture/pr93451.c
new file mode 100644
index 0000000..5908bc4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/pr93451.c
@@ -0,0 +1,14 @@
+void
+mt (double);
+
+void
+nm (void)
+{
+ double ao = 0.0;
+ long int es = -1;
+
+ mt (ao);
+ ++ao;
+ mt (ao);
+ mt (*(double *) &es);
+}
More information about the Gcc-cvs
mailing list