Commit e978955d by David Malcolm

analyzer: fix ICE in __builtin_isnan (PR 93356)

PR analyzer/93356 reports an ICE handling __builtin_isnan due to a
failing assertion:
  674     gcc_assert (lhs_ec_id != rhs_ec_id);
with op=UNORDERED_EXPR.
when attempting to add an UNORDERED_EXPR constraint.

This is an overzealous assertion, but underlying it are various forms of
sloppiness regarding NaN within the analyzer:

  (a) the assumption in the constraint_manager that equivalence classes
  are reflexive (X == X), which isn't the case for NaN.

  (b) Hardcoding the "honor_nans" param to false when calling
  invert_tree_comparison throughout the analyzer.

  (c) Ignoring ORDERED_EXPR, UNORDERED_EXPR, and the UN-prefixed
  comparison codes.

I wrote a patch for this which tracks the NaN-ness of floating-point
values and uses this to address all of the above.

However, to minimize changes in gcc 10 stage 4, here's a simpler patch
which rejects attempts to query or add constraints on floating-point
values, instead treating any floating-point comparison as "unknown", and
silently dropping the constraints at edges.

gcc/analyzer/ChangeLog:
	PR analyzer/93356
	* region-model.cc (region_model::eval_condition): In both
	overloads, bail out immediately on floating-point types.
	(region_model::eval_condition_without_cm): Likewise.
	(region_model::add_constraint): Likewise.

gcc/testsuite/ChangeLog:
	PR analyzer/93356
	* gcc.dg/analyzer/conditionals-notrans.c (test_float_selfcmp):
	Add.
	* gcc.dg/analyzer/conditionals-trans.c: Mark floating point
	comparison test as failing.
	(test_float_selfcmp): Add.
	* gcc.dg/analyzer/data-model-1.c: Mark floating point comparison
	tests as failing.
	* gcc.dg/analyzer/torture/pr93356.c: New test.

gcc/ChangeLog:
	PR analyzer/93356
	* doc/analyzer.texi (Limitations): Note that constraints on
	floating-point values are currently ignored.
parent f9eb0973
2020-01-30 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93356
* doc/analyzer.texi (Limitations): Note that constraints on
floating-point values are currently ignored.
2020-01-30 Jakub Jelinek <jakub@redhat.com> 2020-01-30 Jakub Jelinek <jakub@redhat.com>
PR lto/93384 PR lto/93384
......
2020-01-30 David Malcolm <dmalcolm@redhat.com> 2020-01-30 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93356
* region-model.cc (region_model::eval_condition): In both
overloads, bail out immediately on floating-point types.
(region_model::eval_condition_without_cm): Likewise.
(region_model::add_constraint): Likewise.
2020-01-30 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93450 PR analyzer/93450
* program-state.cc (sm_state_map::set_state): For the overload * program-state.cc (sm_state_map::set_state): For the overload
taking an svalue_id, bail out if the set_state on the ec does taking an svalue_id, bail out if the set_state on the ec does
......
...@@ -5144,6 +5144,15 @@ region_model::eval_condition (svalue_id lhs_sid, ...@@ -5144,6 +5144,15 @@ region_model::eval_condition (svalue_id lhs_sid,
enum tree_code op, enum tree_code op,
svalue_id rhs_sid) const svalue_id rhs_sid) const
{ {
svalue *lhs = get_svalue (lhs_sid);
svalue *rhs = get_svalue (rhs_sid);
/* For now, make no attempt to capture constraints on floating-point
values. */
if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
|| (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
return tristate::unknown ();
tristate ts = eval_condition_without_cm (lhs_sid, op, rhs_sid); tristate ts = eval_condition_without_cm (lhs_sid, op, rhs_sid);
if (ts.is_known ()) if (ts.is_known ())
...@@ -5173,6 +5182,12 @@ region_model::eval_condition_without_cm (svalue_id lhs_sid, ...@@ -5173,6 +5182,12 @@ region_model::eval_condition_without_cm (svalue_id lhs_sid,
/* See what we know based on the values. */ /* See what we know based on the values. */
if (lhs && rhs) if (lhs && rhs)
{ {
/* For now, make no attempt to capture constraints on floating-point
values. */
if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
|| (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
return tristate::unknown ();
if (lhs == rhs) if (lhs == rhs)
{ {
/* If we have the same svalue, then we have equality /* If we have the same svalue, then we have equality
...@@ -5252,6 +5267,11 @@ bool ...@@ -5252,6 +5267,11 @@ bool
region_model::add_constraint (tree lhs, enum tree_code op, tree rhs, region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
region_model_context *ctxt) region_model_context *ctxt)
{ {
/* For now, make no attempt to capture constraints on floating-point
values. */
if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
return true;
svalue_id lhs_sid = get_rvalue (lhs, ctxt); svalue_id lhs_sid = get_rvalue (lhs, ctxt);
svalue_id rhs_sid = get_rvalue (rhs, ctxt); svalue_id rhs_sid = get_rvalue (rhs, ctxt);
...@@ -5385,6 +5405,11 @@ region_model::eval_condition (tree lhs, ...@@ -5385,6 +5405,11 @@ region_model::eval_condition (tree lhs,
tree rhs, tree rhs,
region_model_context *ctxt) region_model_context *ctxt)
{ {
/* For now, make no attempt to model constraints on floating-point
values. */
if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
return tristate::unknown ();
return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt)); return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
} }
......
...@@ -390,6 +390,8 @@ Lack of function pointer analysis ...@@ -390,6 +390,8 @@ Lack of function pointer analysis
@item @item
The constraint-handling code assumes reflexivity in some places The constraint-handling code assumes reflexivity in some places
(that values are equal to themselves), which is not the case for NaN. (that values are equal to themselves), which is not the case for NaN.
As a simple workaround, constraints on floating-point values are
currently ignored.
@item @item
The region model code creates lots of little mutable objects at each The region model code creates lots of little mutable objects at each
@code{region_model} (and thus per @code{exploded_node}) rather than @code{region_model} (and thus per @code{exploded_node}) rather than
......
2020-01-30 Jeff Law <law@redhat.com 2020-01-30 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93356
* gcc.dg/analyzer/conditionals-notrans.c (test_float_selfcmp):
Add.
* gcc.dg/analyzer/conditionals-trans.c: Mark floating point
comparison test as failing.
(test_float_selfcmp): Add.
* gcc.dg/analyzer/data-model-1.c: Mark floating point comparison
tests as failing.
* gcc.dg/analyzer/torture/pr93356.c: New test.
2020-01-30 Jeff Law <law@redhat.com>
PR c/88660 PR c/88660
* gcc.dg/pr88660.c: New test * gcc.dg/pr88660.c: New test
......
...@@ -157,3 +157,9 @@ void test_range_float_ge_le (float f) ...@@ -157,3 +157,9 @@ void test_range_float_ge_le (float f)
__analyzer_eval (f == 4); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */ __analyzer_eval (f == 4); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
/* { dg-bogus "UNKNOWN" "status quo" { xfail *-*-* } .-1 } */ /* { dg-bogus "UNKNOWN" "status quo" { xfail *-*-* } .-1 } */
} }
void test_float_selfcmp (float f)
{
__analyzer_eval (f == f); /* { dg-warning "UNKNOWN" } */
__analyzer_eval (f != f); /* { dg-warning "UNKNOWN" } */
}
...@@ -140,5 +140,12 @@ void test_range_float_ge_le (float f) ...@@ -140,5 +140,12 @@ void test_range_float_ge_le (float f)
{ {
if (f >= 4) if (f >= 4)
if (f <= 4) if (f <= 4)
__analyzer_eval (f == 4); /* { dg-warning "TRUE" } */ __analyzer_eval (f == 4); /* { dg-warning "TRUE" "PR 93356" { xfail *-*-* } } */
/* { dg-warning "UNKNOWN" "disabled float comparisons" { target *-*-* } .-1 } */
}
void test_float_selfcmp (float f)
{
__analyzer_eval (f == f); /* { dg-warning "UNKNOWN" } */
__analyzer_eval (f != f); /* { dg-warning "UNKNOWN" } */
} }
...@@ -209,14 +209,16 @@ void test_13 (struct outer *o) ...@@ -209,14 +209,16 @@ void test_13 (struct outer *o)
{ {
__analyzer_eval (o->mid.in.f == 0.f); /* { dg-warning "UNKNOWN" } */ __analyzer_eval (o->mid.in.f == 0.f); /* { dg-warning "UNKNOWN" } */
o->mid.in.f = 0.f; o->mid.in.f = 0.f;
__analyzer_eval (o->mid.in.f == 0.f); /* { dg-warning "TRUE" } */ __analyzer_eval (o->mid.in.f == 0.f); /* { dg-warning "TRUE" "PR 93356" { xfail *-*-* } } */
/* { dg-warning "UNKNOWN" "disabled float comparisons" { target *-*-* } .-1 } */
} }
void test_14 (struct outer o) void test_14 (struct outer o)
{ {
__analyzer_eval (o.mid.in.f == 0.f); /* { dg-warning "UNKNOWN" } */ __analyzer_eval (o.mid.in.f == 0.f); /* { dg-warning "UNKNOWN" } */
o.mid.in.f = 0.f; o.mid.in.f = 0.f;
__analyzer_eval (o.mid.in.f == 0.f); /* { dg-warning "TRUE" } */ __analyzer_eval (o.mid.in.f == 0.f); /* { dg-warning "TRUE" "PR 93356" { xfail *-*-* } } */
/* { dg-warning "UNKNOWN" "disabled float comparisons" { target *-*-* } .-1 } */
} }
void test_15 (const char *str) void test_15 (const char *str)
...@@ -947,7 +949,8 @@ void test_42 (void) ...@@ -947,7 +949,8 @@ void test_42 (void)
float f; float f;
i = 42; i = 42;
f = i; f = i;
__analyzer_eval (f == 42.0); /* { dg-warning "TRUE" } */ __analyzer_eval (f == 42.0); /* { dg-warning "TRUE" "PR 93356" { xfail *-*-* } } */
/* { dg-warning "UNKNOWN" "disabled float comparisons" { target *-*-* } .-1 } */
} }
void test_43 (void) void test_43 (void)
......
void
test (double d)
{
if (__builtin_isnan (d))
return;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment