Skip to content

Commit f3d2aa0

Browse files
committed
invalid_object(pointer) is true for all non-existent objects
Check whether the object part of a pointer is greater or equal the total number of objects, or equals a dynamic object that has not actually been allocated on a given trace.
1 parent b902e0b commit f3d2aa0

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

src/goto-symex/symex_builtin_functions.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,20 @@ void goto_symext::symex_allocate(
194194

195195
exprt rhs;
196196

197+
symbol_exprt value_expr=value_symbol.symbol_expr();
198+
value_expr.add(ID_C_dynamic_guard, state.guard);
199+
197200
if(object_type->id() == ID_array)
198201
{
199202
const auto &array_type = to_array_type(*object_type);
200203
index_exprt index_expr(
201-
value_symbol.symbol_expr(), from_integer(0, index_type()));
204+
value_expr, from_integer(0, index_type()));
202205
rhs = address_of_exprt(index_expr, pointer_type(array_type.subtype()));
203206
}
204207
else
205208
{
206209
rhs=address_of_exprt(
207-
value_symbol.symbol_expr(), pointer_type(value_symbol.type));
210+
value_expr, pointer_type(value_symbol.type));
208211
}
209212

210213
symex_assign(

src/solvers/flattening/bv_pointers.cpp

+86-17
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,25 @@ literalt bv_pointerst::convert_rest(const exprt &expr)
2727
if(operands.size()==1 &&
2828
operands[0].type().id()==ID_pointer)
2929
{
30-
const bvt &bv=convert_bv(operands[0]);
31-
32-
if(!bv.empty())
33-
{
34-
bvt invalid_bv;
35-
encode(pointer_logic.get_invalid_object(), invalid_bv);
36-
37-
bvt equal_invalid_bv;
38-
equal_invalid_bv.resize(object_bits);
30+
// condition can only be evaluated once all (address-taken)
31+
// objects are known, thus postpone
32+
literalt l=prop.new_variable();
3933

40-
for(std::size_t i=0; i<object_bits; i++)
41-
{
42-
equal_invalid_bv[i]=prop.lequal(bv[offset_bits+i],
43-
invalid_bv[offset_bits+i]);
44-
}
34+
postponed_list.push_back(postponedt());
35+
postponed_list.back().op=convert_bv(operands[0]);
36+
postponed_list.back().bv.push_back(l);
37+
postponed_list.back().expr=expr;
4538

46-
return prop.land(equal_invalid_bv);
47-
}
39+
return l;
4840
}
4941
}
5042
else if(expr.id() == ID_is_dynamic_object)
5143
{
5244
if(operands.size()==1 &&
5345
operands[0].type().id()==ID_pointer)
5446
{
55-
// we postpone
47+
// condition can only be evaluated once all (address-taken)
48+
// objects are known, thus postpone
5649
literalt l=prop.new_variable();
5750

5851
postponed_list.push_back(postponedt());
@@ -813,6 +806,82 @@ void bv_pointerst::do_postponed(
813806
prop.l_set_to_true(prop.limplies(l1, l2));
814807
}
815808
}
809+
else if(postponed.expr.id()==ID_invalid_pointer)
810+
{
811+
const pointer_logict::objectst &objects=pointer_logic.objects;
812+
813+
bvt disj;
814+
disj.reserve(objects.size());
815+
816+
bvt saved_bv=postponed.op;
817+
saved_bv.erase(saved_bv.begin(), saved_bv.begin()+offset_bits);
818+
819+
bvt invalid_bv, null_bv;
820+
encode(pointer_logic.get_invalid_object(), invalid_bv);
821+
invalid_bv.erase(invalid_bv.begin(), invalid_bv.begin()+offset_bits);
822+
encode(pointer_logic.get_null_object(), null_bv);
823+
null_bv.erase(null_bv.begin(), null_bv.begin()+offset_bits);
824+
825+
disj.push_back(bv_utils.equal(saved_bv, invalid_bv));
826+
disj.push_back(bv_utils.equal(saved_bv, null_bv));
827+
828+
// the pointer is invalid if its object part compares equal to
829+
// any of the object parts of dynamic objects that have *not*
830+
// been allocated (as their path condition, stored in
831+
// ID_C_dynamic_guard, evaluates to false)
832+
std::size_t number=0;
833+
834+
for(pointer_logict::objectst::const_iterator
835+
it=objects.begin();
836+
it!=objects.end();
837+
++it, ++number)
838+
{
839+
const exprt &expr=*it;
840+
841+
if(!pointer_logic.is_dynamic_object(expr) ||
842+
!is_ssa_expr(expr))
843+
continue;
844+
845+
// only compare object part
846+
bvt bv;
847+
encode(number, bv);
848+
849+
bv.erase(bv.begin(), bv.begin()+offset_bits);
850+
POSTCONDITION(bv.size()==saved_bv.size());
851+
852+
literalt l1=bv_utils.equal(bv, saved_bv);
853+
854+
const ssa_exprt &ssa=to_ssa_expr(expr);
855+
856+
const exprt &guard=
857+
static_cast<const exprt&>(
858+
ssa.get_original_expr().find(ID_C_dynamic_guard));
859+
860+
if(guard.is_nil())
861+
continue;
862+
863+
const bvt &guard_bv=convert_bv(guard);
864+
DATA_INVARIANT(guard_bv.size()==1, "guard expected to be Boolean");
865+
literalt l_guard=guard_bv[0];
866+
867+
disj.push_back(prop.land(!l_guard, l1));
868+
}
869+
870+
// compare object part to max object number
871+
bvt bv;
872+
encode(number, bv);
873+
874+
bv.erase(bv.begin(), bv.begin()+offset_bits);
875+
POSTCONDITION(bv.size()==saved_bv.size());
876+
877+
disj.push_back(
878+
bv_utils.rel(
879+
saved_bv, ID_ge, bv, bv_utilst::representationt::UNSIGNED));
880+
881+
PRECONDITION(postponed.bv.size()==1);
882+
literalt l=postponed.bv.front();
883+
prop.l_set_to(prop.lequal(prop.lor(disj), l), true);
884+
}
816885
else
817886
UNREACHABLE;
818887
}

src/util/irep_ids.def

+5
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,11 @@ IREP_ID_ONE(statement_list_instructions)
841841
IREP_ID_ONE(max)
842842
IREP_ID_ONE(min)
843843
IREP_ID_ONE(constant_interval)
844+
// dynamic objects get created during symbolic execution, but need
845+
// not ever exist on any feasible path; use ID_C_dynamic_guard to
846+
// store the path condition corresponding to the creation of a
847+
// dynamic object
848+
IREP_ID_TWO(C_dynamic_guard, #dynamic_guard)
844849

845850
// Projects depending on this code base that wish to extend the list of
846851
// available ids should provide a file local_irep_ids.def in their source tree

0 commit comments

Comments
 (0)