Skip to content

Commit a7d4c3d

Browse files
authored
Merge pull request #6209 from jezhiggins/vsd-bool-intervals-go-top
VSD - bool intervals go top
2 parents b69a629 + 0a0a862 commit a7d4c3d

File tree

12 files changed

+257
-4
lines changed

12 files changed

+257
-4
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-intervals.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 \(\) -> \[1, 1\] @ \[2\]
77
main::1::b2 \(\) -> \[0, 0\] @ \[3\]
8-
main::1::b3 \(\) -> \[0, 1\] @ \[5\]
8+
main::1::b3 \(\) -> TOP @ \[5\]
99
main::1::i \(\) -> \[A, A\] @ \[7\]
1010
main::1::j \(\) -> \[14, 14\] @ \[9\]
1111
main::1::k \(\) -> \[A, 14\] @ \[11\]

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/interval_abstract_value.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,25 @@ interval_abstract_valuet::interval_abstract_valuet(
244244
{
245245
}
246246

247+
bool new_interval_is_top(const constant_interval_exprt &e)
248+
{
249+
if(e.is_top())
250+
return true;
251+
252+
if(e.get_lower().is_false() && e.get_upper().is_true())
253+
return true;
254+
if(
255+
e.type().id() == ID_c_bool && e.get_lower().is_zero() &&
256+
e.get_upper().is_one())
257+
return true;
258+
259+
return false;
260+
}
261+
247262
interval_abstract_valuet::interval_abstract_valuet(
248263
const constant_interval_exprt &e)
249-
: abstract_value_objectt(e.type(), e.is_top(), e.is_bottom()), interval(e)
264+
: abstract_value_objectt(e.type(), new_interval_is_top(e), e.is_bottom()),
265+
interval(e)
250266
{
251267
}
252268

@@ -290,6 +306,11 @@ exprt interval_abstract_valuet::to_constant() const
290306
#endif
291307
}
292308

309+
void interval_abstract_valuet::set_top_internal()
310+
{
311+
interval = constant_interval_exprt(type());
312+
}
313+
293314
size_t interval_abstract_valuet::internal_hash() const
294315
{
295316
return std::hash<std::string>{}(interval.pretty());

src/analyses/variable-sensitivity/interval_abstract_value.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ class interval_abstract_valuet : public abstract_value_objectt
9696

9797
private:
9898
constant_interval_exprt interval;
99+
100+
void set_top_internal() override;
99101
};
100102

101103
#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_INTERVAL_ABSTRACT_VALUE_H

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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ SRC += analyses/ai/ai.cpp \
2121
analyses/variable-sensitivity/full_array_abstract_object/merge.cpp \
2222
analyses/variable-sensitivity/eval.cpp \
2323
analyses/variable-sensitivity/eval-member-access.cpp \
24+
analyses/variable-sensitivity/interval_abstract_value/extremes-go-top.cpp \
2425
analyses/variable-sensitivity/interval_abstract_value/meet.cpp \
2526
analyses/variable-sensitivity/interval_abstract_value/merge.cpp \
2627
analyses/variable-sensitivity/interval_abstract_value/widening_merge.cpp \
@@ -29,6 +30,7 @@ SRC += analyses/ai/ai.cpp \
2930
analyses/variable-sensitivity/value_expression_evaluation/assume.cpp \
3031
analyses/variable-sensitivity/value_expression_evaluation/assume_prune.cpp \
3132
analyses/variable-sensitivity/value_expression_evaluation/expression_evaluation.cpp \
33+
analyses/variable-sensitivity/value_set_abstract_object/extremes-go-top.cpp \
3234
analyses/variable-sensitivity/value_set_abstract_object/compacting.cpp \
3335
analyses/variable-sensitivity/value_set_abstract_object/meet.cpp \
3436
analyses/variable-sensitivity/value_set_abstract_object/merge.cpp \
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for interval_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+
static void
20+
verify_extreme_interval(typet type, abstract_environmentt &env, namespacet &ns)
21+
{
22+
auto interval = make_interval(min_exprt(type), max_exprt(type), env, ns);
23+
24+
EXPECT_TOP(interval);
25+
}
26+
27+
SCENARIO(
28+
"extreme intervals go TOP",
29+
"[core][analyses][variable-sensitivity][interval_abstract_value][extreme]")
30+
{
31+
auto object_factory = variable_sensitivity_object_factoryt::configured_with(
32+
vsd_configt::intervals());
33+
34+
auto environment = abstract_environmentt{object_factory};
35+
environment.make_top();
36+
auto symbol_table = symbol_tablet{};
37+
auto ns = namespacet{symbol_table};
38+
39+
GIVEN("[min-max] signed goes TOP")
40+
{
41+
verify_extreme_interval(signedbv_typet(32), environment, ns);
42+
}
43+
GIVEN("[min-max] unsigned goes TOP")
44+
{
45+
verify_extreme_interval(unsignedbv_typet(32), environment, ns);
46+
}
47+
GIVEN("[min-max] bool goes TOP")
48+
{
49+
verify_extreme_interval(bool_typet(), environment, ns);
50+
}
51+
GIVEN("[min-max] c_bool goes TOP")
52+
{
53+
verify_extreme_interval(bitvector_typet(ID_c_bool, 8), environment, ns);
54+
}
55+
GIVEN("[FALSE, TRUE] goes TOP")
56+
{
57+
auto boolInterval =
58+
make_interval(false_exprt(), true_exprt(), environment, ns);
59+
60+
EXPECT_TOP(boolInterval);
61+
}
62+
GIVEN("[0, 1] c_bool goes TOP")
63+
{
64+
auto c_bool_type = bitvector_typet(ID_c_bool, 8);
65+
auto boolInterval = make_interval(
66+
from_integer(0, c_bool_type),
67+
from_integer(1, c_bool_type),
68+
environment,
69+
ns);
70+
71+
EXPECT_TOP(boolInterval);
72+
}
73+
}
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)