Skip to content

Commit 0a0a862

Browse files
committed
Value sets spanning the min-max range of its type go to TOP.
1 parent 0b70b2e commit 0a0a862

File tree

8 files changed

+158
-2
lines changed

8 files changed

+158
-2
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
_Bool nondet_bool();
2+
int main()
3+
{
4+
int x = 0;
5+
while(1)
6+
{
7+
if(nondet_bool())
8+
x = x + 1;
9+
assert(x != 1000);
10+
}
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--vsd --one-domain-per-history --three-way-merge --loop-unwind-and-branching 16 --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[main\.assertion\.1\] line 9 assertion x != 1000: UNKNOWN
7+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--vsd --one-domain-per-history --three-way-merge --loop-unwind-and-branching 16 --vsd-values intervals --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[main\.assertion\.1\] line 9 assertion x != 1000: UNKNOWN
7+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--vsd --one-domain-per-history --three-way-merge --loop-unwind-and-branching 16 --vsd-values set-of-constants --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[main\.assertion\.1\] line 9 assertion x != 1000: UNKNOWN
7+
--

regression/goto-analyzer/ternary-operator/test-value-sets.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ main.c
55
^SIGNAL=0$
66
main::1::b1 \(\) -> value-set-begin: TRUE :value-set-end
77
main::1::b2 \(\) -> value-set-begin: FALSE :value-set-end
8-
main::1::b3 \(\) -> value-set-begin: TRUE, FALSE :value-set-end
8+
main::1::b3 \(\) -> TOP @ \[5\]
99
main::1::i \(\) -> value-set-begin: 10 :value-set-end
1010
main::1::j \(\) -> value-set-begin: 20 :value-set-end
1111
main::1::k \(\) -> value-set-begin: 10, 20 :value-set-end

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ static abstract_object_pointert
116116
maybe_extract_single_value(const abstract_object_pointert &maybe_singleton);
117117

118118
static bool are_any_top(const abstract_object_sett &set);
119+
static bool is_set_extreme(const typet &type, const abstract_object_sett &set);
119120

120121
static abstract_object_sett compact_values(const abstract_object_sett &values);
121122
static abstract_object_sett widen_value_set(
@@ -296,7 +297,7 @@ void value_set_abstract_objectt::set_values(
296297
const abstract_object_sett &other_values)
297298
{
298299
PRECONDITION(!other_values.empty());
299-
if(are_any_top(other_values))
300+
if(are_any_top(other_values) || is_set_extreme(type(), other_values))
300301
{
301302
set_top();
302303
}
@@ -391,6 +392,65 @@ static bool are_any_top(const abstract_object_sett &set)
391392
}) != set.end();
392393
}
393394

395+
using set_predicate_fn = std::function<bool(const abstract_value_objectt &)>;
396+
static bool set_contains(const abstract_object_sett &set, set_predicate_fn pred)
397+
{
398+
return std::find_if(
399+
set.begin(),
400+
set.end(),
401+
[&pred](const abstract_object_pointert &obj) {
402+
const auto &value =
403+
std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
404+
return pred(*value);
405+
}) != set.end();
406+
}
407+
408+
static bool set_has_extremes(
409+
const abstract_object_sett &set,
410+
set_predicate_fn lower_fn,
411+
set_predicate_fn upper_fn)
412+
{
413+
bool has_lower = set_contains(set, lower_fn);
414+
if(!has_lower)
415+
return false;
416+
417+
bool has_upper = set_contains(set, upper_fn);
418+
return has_upper;
419+
}
420+
421+
static bool is_set_extreme(const typet &type, const abstract_object_sett &set)
422+
{
423+
if(type.id() == ID_bool)
424+
{
425+
return set_has_extremes(
426+
set,
427+
[](const abstract_value_objectt &value) {
428+
auto c = value.to_constant();
429+
return c.is_false() || (c.id() == ID_min);
430+
},
431+
[](const abstract_value_objectt &value) {
432+
auto c = value.to_constant();
433+
return c.is_true() || (c.id() == ID_max);
434+
});
435+
}
436+
437+
if(type.id() == ID_c_bool)
438+
{
439+
return set_has_extremes(
440+
set,
441+
[](const abstract_value_objectt &value) {
442+
auto c = value.to_constant();
443+
return c.is_zero() || (c.id() == ID_min);
444+
},
445+
[](const abstract_value_objectt &value) {
446+
auto c = value.to_constant();
447+
return c.is_one() || (c.id() == ID_max);
448+
});
449+
}
450+
451+
return false;
452+
}
453+
394454
/////////////////
395455
static abstract_object_sett
396456
non_destructive_compact(const abstract_object_sett &values);

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ SRC += analyses/ai/ai.cpp \
3030
analyses/variable-sensitivity/value_expression_evaluation/assume.cpp \
3131
analyses/variable-sensitivity/value_expression_evaluation/assume_prune.cpp \
3232
analyses/variable-sensitivity/value_expression_evaluation/expression_evaluation.cpp \
33+
analyses/variable-sensitivity/value_set_abstract_object/extremes-go-top.cpp \
3334
analyses/variable-sensitivity/value_set_abstract_object/compacting.cpp \
3435
analyses/variable-sensitivity/value_set_abstract_object/meet.cpp \
3536
analyses/variable-sensitivity/value_set_abstract_object/merge.cpp \
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for value_set_abstract_valuet
4+
5+
Author: Jez Higgins
6+
7+
\*******************************************************************/
8+
9+
#include <analyses/variable-sensitivity/abstract_environment.h>
10+
#include <analyses/variable-sensitivity/abstract_object.h>
11+
#include <analyses/variable-sensitivity/interval_abstract_value.h>
12+
#include <analyses/variable-sensitivity/variable_sensitivity_object_factory.h>
13+
#include <testing-utils/use_catch.h>
14+
15+
#include <analyses/variable-sensitivity/variable_sensitivity_test_helpers.h>
16+
#include <util/arith_tools.h>
17+
#include <util/bitvector_types.h>
18+
19+
SCENARIO(
20+
"value-sets spanning min-max go TOP",
21+
"[core][analyses][variable-sensitivity][value_set_abstract_object][extreme]")
22+
{
23+
auto object_factory = variable_sensitivity_object_factoryt::configured_with(
24+
vsd_configt::intervals());
25+
26+
auto environment = abstract_environmentt{object_factory};
27+
environment.make_top();
28+
auto symbol_table = symbol_tablet{};
29+
auto ns = namespacet{symbol_table};
30+
31+
GIVEN("{FALSE, TRUE} goes TOP")
32+
{
33+
auto boolInterval =
34+
make_value_set({false_exprt(), true_exprt()}, environment, ns);
35+
36+
EXPECT_TOP(boolInterval);
37+
}
38+
GIVEN("{min(bool), max(bool)} goes TOP")
39+
{
40+
auto boolInterval = make_value_set(
41+
{min_exprt(bool_typet()), max_exprt(bool_typet())}, environment, ns);
42+
43+
EXPECT_TOP(boolInterval);
44+
}
45+
GIVEN("{0, 1} c_bool goes TOP")
46+
{
47+
auto c_bool_type = bitvector_typet(ID_c_bool, 8);
48+
auto boolInterval = make_value_set(
49+
{from_integer(0, c_bool_type), from_integer(1, c_bool_type)},
50+
environment,
51+
ns);
52+
53+
EXPECT_TOP(boolInterval);
54+
}
55+
GIVEN("{min(c_bool), max(c_bool)} goes TOP")
56+
{
57+
auto c_bool_type = bitvector_typet(ID_c_bool, 8);
58+
auto boolInterval = make_value_set(
59+
{min_exprt(c_bool_type), max_exprt(c_bool_type)}, environment, ns);
60+
61+
EXPECT_TOP(boolInterval);
62+
}
63+
}

0 commit comments

Comments
 (0)