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.
This commit is contained in:
David Malcolm 2020-01-27 16:23:43 -05:00
parent 85d6090eb8
commit 8c08c98301
4 changed files with 119 additions and 3 deletions

View File

@ -1,3 +1,16 @@
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

View File

@ -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 ();
}

View File

@ -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

View File

@ -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);
}