Skip to content

Commit 056be83

Browse files
committed
Value set: lift offset from numeric constants to expressions
We can safely track arbitrary expressions as pointer offsets rather than limit ourselves to just constant offsets (and then treating all other expressions as "unknown").
1 parent 7fc006e commit 056be83

File tree

4 files changed

+92
-92
lines changed

4 files changed

+92
-92
lines changed

src/goto-symex/goto_symex_state.cpp

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ Author: Daniel Kroening, [email protected]
2727
#include "simplify_expr_with_value_set.h"
2828
#include "symex_target_equation.h"
2929

30-
static void get_l1_name(exprt &expr);
31-
3230
goto_symex_statet::goto_symex_statet(
3331
const symex_targett::sourcet &_source,
3432
std::size_t max_field_sensitive_array_size,
@@ -129,20 +127,7 @@ renamedt<ssa_exprt, L2> goto_symex_statet::assignment(
129127
else
130128
propagation.erase_if_exists(l1_identifier);
131129

132-
{
133-
// update value sets
134-
exprt l1_rhs(rhs);
135-
get_l1_name(l1_rhs);
136-
137-
const ssa_exprt l1_lhs = remove_level_2(lhs);
138-
if(run_validation_checks)
139-
{
140-
DATA_INVARIANT(!check_renaming_l1(l1_lhs), "lhs renaming failed on l1");
141-
DATA_INVARIANT(!check_renaming_l1(l1_rhs), "rhs renaming failed on l1");
142-
}
143-
144-
value_set.assign(l1_lhs, l1_rhs, ns, rhs_is_simplified, is_shared);
145-
}
130+
value_set.assign(lhs, rhs, ns, rhs_is_simplified, is_shared);
146131

147132
#ifdef DEBUG
148133
std::cout << "Assigning " << l1_identifier << '\n';
@@ -789,17 +774,6 @@ void goto_symex_statet::rename(
789774
l1_type_entry.first->second=type;
790775
}
791776

792-
static void get_l1_name(exprt &expr)
793-
{
794-
// do not reset the type !
795-
796-
if(is_ssa_expr(expr))
797-
to_ssa_expr(expr).remove_level_2();
798-
else
799-
Forall_operands(it, expr)
800-
get_l1_name(*it);
801-
}
802-
803777
/// Dumps the current state of symex, printing the function name and location
804778
/// number for each stack frame in the currently active thread.
805779
/// This is for use from the debugger or in debug code; please don't delete it

src/goto-symex/shadow_memory_util.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ normalize(const object_descriptor_exprt &expr, const namespacet &ns)
982982
{
983983
return expr;
984984
}
985-
if(expr.offset().id() == ID_unknown)
985+
if(!expr.offset().is_constant())
986986
{
987987
return expr;
988988
}

src/pointer-analysis/value_set.cpp

Lines changed: 85 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ Author: Daniel Kroening, [email protected]
2323
#include <util/prefix.h>
2424
#include <util/range.h>
2525
#include <util/simplify_expr.h>
26+
#include <util/ssa_expr.h>
2627
#include <util/std_code.h>
2728
#include <util/symbol.h>
2829
#include <util/xml.h>
2930

3031
#ifdef DEBUG
31-
#include <iostream>
32-
#include <util/format_expr.h>
33-
#include <util/format_type.h>
32+
# include <iostream>
3433
#endif
3534

3635
#include "add_failed_symbols.h"
@@ -184,7 +183,7 @@ void value_sett::output(std::ostream &out, const std::string &indent) const
184183
stream << "<" << format(o) << ", ";
185184

186185
if(o_it->second)
187-
stream << *o_it->second;
186+
stream << format(*o_it->second);
188187
else
189188
stream << '*';
190189

@@ -261,7 +260,7 @@ exprt value_sett::to_expr(const object_map_dt::value_type &it) const
261260
od.object()=object;
262261

263262
if(it.second)
264-
od.offset() = from_integer(*it.second, c_index_type());
263+
od.offset() = *it.second;
265264

266265
od.type()=od.object().type();
267266

@@ -352,17 +351,34 @@ bool value_sett::eval_pointer_offset(
352351
it=object_map.begin();
353352
it!=object_map.end();
354353
it++)
355-
if(!it->second)
354+
{
355+
if(!it->second || !it->second->is_constant())
356356
return false;
357357
else
358358
{
359+
// This branch should not be reached as any constant offset will have
360+
// been used before already. The following code will trigger
361+
// `eval_pointer_offset`, yet we wouldn't end up in this branch:
362+
// struct S { int a; char b; };
363+
//
364+
// int main()
365+
// {
366+
// struct S s;
367+
// int offset;
368+
// __CPROVER_assume(offset >= 0 && offset <= 1 && offset % 2 == 0);
369+
// int *p = (char*)&s + offset;
370+
// int x = *p;
371+
// __CPROVER_assert(s.a == x, "");
372+
// }
373+
UNREACHABLE;
359374
const exprt &object=object_numbering[it->first];
360375
auto ptr_offset = compute_pointer_offset(object, ns);
361376

362377
if(!ptr_offset.has_value())
363378
return false;
364379

365-
*ptr_offset += *it->second;
380+
*ptr_offset +=
381+
numeric_cast_v<mp_integer>(to_constant_expr(*it->second));
366382

367383
if(mod && *ptr_offset != previous_offset)
368384
return false;
@@ -371,6 +387,7 @@ bool value_sett::eval_pointer_offset(
371387
previous_offset = *ptr_offset;
372388
mod=true;
373389
}
390+
}
374391

375392
if(mod)
376393
expr.swap(new_expr);
@@ -556,8 +573,11 @@ void value_sett::get_value_set_rec(
556573
}
557574
else if(expr.id()==ID_symbol)
558575
{
559-
auto entry_index = get_index_of_symbol(
560-
to_symbol_expr(expr).get_identifier(), expr.type(), suffix, ns);
576+
const symbol_exprt expr_l1 = is_ssa_expr(expr)
577+
? remove_level_2(to_ssa_expr(expr))
578+
: to_symbol_expr(expr);
579+
auto entry_index =
580+
get_index_of_symbol(expr_l1.get_identifier(), expr.type(), suffix, ns);
561581

562582
if(entry_index.has_value())
563583
make_union(dest, find_entry(*entry_index)->object_map);
@@ -623,7 +643,7 @@ void value_sett::get_value_set_rec(
623643
insert(
624644
dest,
625645
exprt(ID_null_object, to_pointer_type(expr.type()).base_type()),
626-
mp_integer{0});
646+
from_integer(0, c_index_type()));
627647
}
628648
else if(
629649
expr.type().id() == ID_unsignedbv || expr.type().id() == ID_signedbv)
@@ -655,7 +675,10 @@ void value_sett::get_value_set_rec(
655675

656676
if(op.is_zero())
657677
{
658-
insert(dest, exprt(ID_null_object, empty_typet{}), mp_integer{0});
678+
insert(
679+
dest,
680+
exprt(ID_null_object, empty_typet{}),
681+
from_integer(0, c_index_type()));
659682
}
660683
else
661684
{
@@ -697,15 +720,14 @@ void value_sett::get_value_set_rec(
697720
expr.id_string() + " expected to have at least two operands");
698721

699722
object_mapt pointer_expr_set;
700-
std::optional<mp_integer> i;
723+
std::optional<exprt> additional_offset;
701724

702725
// special case for plus/minus and exactly one pointer
703726
std::optional<exprt> ptr_operand;
704727
if(
705728
expr.type().id() == ID_pointer &&
706729
(expr.id() == ID_plus || expr.id() == ID_minus))
707730
{
708-
bool non_const_offset = false;
709731
for(const auto &op : expr.operands())
710732
{
711733
if(op.type().id() == ID_pointer)
@@ -718,24 +740,20 @@ void value_sett::get_value_set_rec(
718740

719741
ptr_operand = op;
720742
}
721-
else if(!non_const_offset)
743+
else
722744
{
723-
auto offset = numeric_cast<mp_integer>(op);
724-
if(!offset.has_value())
725-
{
726-
i.reset();
727-
non_const_offset = true;
728-
}
745+
if(!additional_offset.has_value())
746+
additional_offset = op;
729747
else
730748
{
731-
if(!i.has_value())
732-
i = mp_integer{0};
733-
i = *i + *offset;
749+
additional_offset = plus_exprt{
750+
*additional_offset,
751+
typecast_exprt::conditional_cast(op, additional_offset->type())};
734752
}
735753
}
736754
}
737755

738-
if(ptr_operand.has_value() && i.has_value())
756+
if(ptr_operand.has_value() && additional_offset.has_value())
739757
{
740758
typet pointer_base_type =
741759
to_pointer_type(ptr_operand->type()).base_type();
@@ -746,18 +764,22 @@ void value_sett::get_value_set_rec(
746764

747765
if(!size.has_value() || (*size) == 0)
748766
{
749-
i.reset();
767+
additional_offset.reset();
750768
}
751769
else
752770
{
753-
*i *= *size;
771+
additional_offset = mult_exprt{
772+
*additional_offset, from_integer(*size, additional_offset->type())};
754773

755774
if(expr.id()==ID_minus)
756775
{
757776
DATA_INVARIANT(
758777
to_minus_expr(expr).lhs() == *ptr_operand,
759778
"unexpected subtraction of pointer from integer");
760-
i->negate();
779+
DATA_INVARIANT(
780+
additional_offset->type().id() != ID_unsignedbv,
781+
"offset type must support negation");
782+
additional_offset = unary_minus_exprt{*additional_offset};
761783
}
762784
}
763785
}
@@ -791,8 +813,15 @@ void value_sett::get_value_set_rec(
791813
offsett offset = it->second;
792814

793815
// adjust by offset
794-
if(offset && i.has_value())
795-
*offset += *i;
816+
if(offset && additional_offset.has_value())
817+
{
818+
offset = simplify_expr(
819+
plus_exprt{
820+
*offset,
821+
typecast_exprt::conditional_cast(
822+
*additional_offset, offset->type())},
823+
ns);
824+
}
796825
else
797826
offset.reset();
798827

@@ -873,7 +902,7 @@ void value_sett::get_value_set_rec(
873902
dynamic_object.set_instance(location_number);
874903
dynamic_object.valid()=true_exprt();
875904

876-
insert(dest, dynamic_object, mp_integer{0});
905+
insert(dest, dynamic_object, from_integer(0, c_index_type()));
877906
}
878907
else if(statement==ID_cpp_new ||
879908
statement==ID_cpp_new_array)
@@ -888,7 +917,7 @@ void value_sett::get_value_set_rec(
888917
dynamic_object.set_instance(location_number);
889918
dynamic_object.valid()=true_exprt();
890919

891-
insert(dest, dynamic_object, mp_integer{0});
920+
insert(dest, dynamic_object, from_integer(0, c_index_type()));
892921
}
893922
else
894923
insert(dest, exprt(ID_unknown, original_type));
@@ -1335,12 +1364,17 @@ void value_sett::get_reference_set_rec(
13351364
expr.id()==ID_string_constant ||
13361365
expr.id()==ID_array)
13371366
{
1367+
exprt l1_expr =
1368+
is_ssa_expr(expr) ? remove_level_2(to_ssa_expr(expr)) : expr;
1369+
13381370
if(
13391371
expr.type().id() == ID_array &&
13401372
to_array_type(expr.type()).element_type().id() == ID_array)
1341-
insert(dest, expr);
1373+
{
1374+
insert(dest, l1_expr);
1375+
}
13421376
else
1343-
insert(dest, expr, mp_integer{0});
1377+
insert(dest, l1_expr, from_integer(0, c_index_type()));
13441378

13451379
return;
13461380
}
@@ -1366,7 +1400,7 @@ void value_sett::get_reference_set_rec(
13661400
{
13671401
const index_exprt &index_expr=to_index_expr(expr);
13681402
const exprt &array=index_expr.array();
1369-
const exprt &offset=index_expr.index();
1403+
const exprt &index = index_expr.index();
13701404

13711405
DATA_INVARIANT(
13721406
array.type().id() == ID_array, "index takes array-typed operand");
@@ -1394,22 +1428,24 @@ void value_sett::get_reference_set_rec(
13941428
from_integer(0, c_index_type()));
13951429

13961430
offsett o = a_it->second;
1397-
const auto i = numeric_cast<mp_integer>(offset);
13981431

1399-
if(offset.is_zero())
1400-
{
1401-
}
1402-
else if(i.has_value() && o)
1432+
if(!index.is_zero() && o.has_value())
14031433
{
14041434
auto size = pointer_offset_size(array_type.element_type(), ns);
14051435

14061436
if(!size.has_value() || *size == 0)
14071437
o.reset();
14081438
else
1409-
*o = *i * (*size);
1439+
{
1440+
o = simplify_expr(
1441+
plus_exprt{
1442+
*o,
1443+
typecast_exprt::conditional_cast(
1444+
mult_exprt{index, from_integer(*size, index.type())},
1445+
o->type())},
1446+
ns);
1447+
}
14101448
}
1411-
else
1412-
o.reset();
14131449

14141450
insert(dest, deref_index_expr, o);
14151451
}
@@ -1659,7 +1695,9 @@ void value_sett::assign_rec(
16591695

16601696
if(lhs.id()==ID_symbol)
16611697
{
1662-
const irep_idt &identifier=to_symbol_expr(lhs).get_identifier();
1698+
const symbol_exprt lhs_l1 =
1699+
is_ssa_expr(lhs) ? remove_level_2(to_ssa_expr(lhs)) : to_symbol_expr(lhs);
1700+
const irep_idt &identifier = lhs_l1.get_identifier();
16631701

16641702
update_entry(
16651703
entryt{identifier, suffix}, lhs.type(), values_rhs, add_to_sets);
@@ -1858,8 +1896,11 @@ void value_sett::apply_code_rec(
18581896
(symbol_type.id() == ID_array &&
18591897
to_array_type(symbol_type).element_type().id() == ID_pointer))
18601898
{
1899+
const symbol_exprt symbol_l1 = is_ssa_expr(symbol)
1900+
? remove_level_2(to_ssa_expr(symbol))
1901+
: to_symbol_expr(symbol);
18611902
// assign the address of the failed object
1862-
if(auto failed = get_failed_symbol(symbol, ns))
1903+
if(auto failed = get_failed_symbol(symbol_l1, ns))
18631904
{
18641905
address_of_exprt address_of_expr(*failed, to_pointer_type(symbol_type));
18651906
assign(symbol, address_of_expr, ns, false, false);

0 commit comments

Comments
 (0)