Skip to content

Commit 1ba2ee6

Browse files
committed
r/w/rw_ok and pointer_in_range depend on deallocated and dead_object
The evaluation of these expressions depends on the specific values of __CPROVER_deallocated and __CPROVER_dead_object at the time the expression is used. Therefore, include these as additional operands to retain the properties expected of an expression (as opposed to a statement/function call).
1 parent 02c7a36 commit 1ba2ee6

File tree

7 files changed

+183
-27
lines changed

7 files changed

+183
-27
lines changed

src/ansi-c/goto_check_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2013,7 +2013,7 @@ optionalt<exprt> goto_check_ct::expand_pointer_checks(exprt expr)
20132013
{
20142014
// these get an address as first argument and a size as second
20152015
DATA_INVARIANT(
2016-
expr.operands().size() == 2, "r/w_ok must have two operands");
2016+
expr.operands().size() == 4, "r/w_ok must have four operands");
20172017

20182018
const auto conditions = get_pointer_dereferenceable_conditions(
20192019
to_r_or_w_ok_expr(expr).pointer(), to_r_or_w_ok_expr(expr).size());

src/goto-instrument/contracts/instrument_spec_assigns.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,9 +635,13 @@ exprt instrument_spec_assignst::target_validity_expr(
635635
// (or is NULL if we allow it explicitly).
636636
// This assertion will be falsified whenever `start_address` is invalid or
637637
// not of the right size (or is NULL if we do not allow it explicitly).
638-
auto result =
639-
or_exprt{not_exprt{car.condition()},
640-
w_ok_exprt{car.target_start_address(), car.target_size()}};
638+
symbol_exprt deallocated =
639+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
640+
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
641+
auto result = or_exprt{
642+
not_exprt{car.condition()},
643+
w_ok_exprt{
644+
car.target_start_address(), car.target_size(), deallocated, dead}};
641645

642646
if(allow_null_target)
643647
result.add_to_operands(null_object(car.target_start_address()));

src/goto-instrument/contracts/utils.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ exprt all_dereferences_are_valid(const exprt &expr, const namespacet &ns)
9191
const auto size_of_expr_opt = size_of_expr(expr.type(), ns);
9292
CHECK_RETURN(size_of_expr_opt.has_value());
9393

94-
validity_checks.push_back(r_ok_exprt{deref->pointer(), *size_of_expr_opt});
94+
symbol_exprt deallocated =
95+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
96+
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
97+
validity_checks.push_back(
98+
r_ok_exprt{deref->pointer(), *size_of_expr_opt, deallocated, dead});
9599
}
96100

97101
for(const auto &op : expr.operands())

src/goto-programs/builtin_functions.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,10 @@ void goto_convertt::do_havoc_slice(
696696
// char nondet_contents[argument[1]];
697697
// __CPROVER_array_replace(p, nondet_contents);
698698

699-
r_or_w_ok_exprt ok_expr(ID_w_ok, arguments[0], arguments[1]);
699+
symbol_exprt deallocated =
700+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
701+
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
702+
w_ok_exprt ok_expr{arguments[0], arguments[1], deallocated, dead};
700703
ok_expr.add_source_location() = source_location;
701704
source_locationt annotated_location = source_location;
702705
annotated_location.set("user-provided", false);

src/goto-programs/goto_clean_expr.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "goto_convert_class.h"
1313

14+
#include <util/cprover_prefix.h>
1415
#include <util/expr_util.h>
1516
#include <util/fresh_symbol.h>
1617
#include <util/pointer_expr.h>
@@ -73,6 +74,22 @@ bool goto_convertt::needs_cleaning(const exprt &expr)
7374
return true;
7475
}
7576

77+
if(auto r_or_w_ok = expr_try_dynamic_cast<r_or_w_ok_exprt>(expr))
78+
{
79+
if(r_or_w_ok->deallocated_ptr().is_nil())
80+
return true;
81+
if(r_or_w_ok->dead_ptr().is_nil())
82+
return true;
83+
}
84+
else if(
85+
auto pointer_in_range = expr_try_dynamic_cast<pointer_in_range_exprt>(expr))
86+
{
87+
if(pointer_in_range->deallocated_ptr().is_nil())
88+
return true;
89+
if(pointer_in_range->dead_ptr().is_nil())
90+
return true;
91+
}
92+
7693
// We can't flatten quantified expressions by introducing new literals for
7794
// conditional expressions. This is because the body of the quantified
7895
// may refer to bound variables, which are not visible outside the scope
@@ -436,6 +453,33 @@ void goto_convertt::clean_expr(
436453
expr.operands().size() == 1, "ID_compound_literal has a single operand");
437454
expr = to_unary_expr(expr).op();
438455
}
456+
else if(auto r_or_w_ok = expr_try_dynamic_cast<r_or_w_ok_exprt>(expr))
457+
{
458+
if(r_or_w_ok->deallocated_ptr().is_nil())
459+
{
460+
r_or_w_ok->deallocated_ptr() =
461+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
462+
}
463+
if(r_or_w_ok->dead_ptr().is_nil())
464+
{
465+
r_or_w_ok->dead_ptr() =
466+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
467+
}
468+
}
469+
else if(
470+
auto pointer_in_range = expr_try_dynamic_cast<pointer_in_range_exprt>(expr))
471+
{
472+
if(pointer_in_range->deallocated_ptr().is_nil())
473+
{
474+
pointer_in_range->deallocated_ptr() =
475+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
476+
}
477+
if(pointer_in_range->dead_ptr().is_nil())
478+
{
479+
pointer_in_range->dead_ptr() =
480+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
481+
}
482+
}
439483
}
440484

441485
void goto_convertt::clean_expr_address_of(

src/util/pointer_expr.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ exprt pointer_in_range_exprt::lower() const
233233
{same_object(op0(), op1()),
234234
same_object(op1(), op2()),
235235
r_ok_exprt(
236-
op0(), minus_exprt(pointer_offset(op2()), pointer_offset(op0()))),
236+
op0(),
237+
minus_exprt(pointer_offset(op2()), pointer_offset(op0())),
238+
deallocated_ptr(),
239+
dead_ptr()),
237240
binary_relation_exprt(pointer_offset(op0()), ID_le, pointer_offset(op1())),
238241
binary_relation_exprt(
239242
pointer_offset(op1()), ID_le, pointer_offset(op2()))});

src/util/pointer_expr.h

Lines changed: 118 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -369,22 +369,39 @@ inline is_dynamic_object_exprt &to_is_dynamic_object_expr(exprt &expr)
369369
/// pointer_in_range(a, b, c) evaluates to true iff
370370
/// same_object(a, b, c) ∧ r_ok(a, offset(c)-offset(a)) ∧ a<=b ∧ b<=c
371371
/// Note that the last inequality is weak, i.e., b may be equal to c.
372-
class pointer_in_range_exprt : public ternary_exprt
372+
class pointer_in_range_exprt : public expr_protectedt
373373
{
374374
public:
375-
explicit pointer_in_range_exprt(exprt a, exprt b, exprt c)
376-
: ternary_exprt(
375+
pointer_in_range_exprt(
376+
exprt a,
377+
exprt b,
378+
exprt c,
379+
exprt is_deallocated,
380+
exprt is_dead)
381+
: expr_protectedt(
377382
ID_pointer_in_range,
378-
std::move(a),
379-
std::move(b),
380-
std::move(c),
381-
bool_typet())
383+
bool_typet{},
384+
{std::move(a),
385+
std::move(b),
386+
std::move(c),
387+
std::move(is_deallocated),
388+
std::move(is_dead)})
382389
{
383390
PRECONDITION(op0().type().id() == ID_pointer);
384391
PRECONDITION(op1().type().id() == ID_pointer);
385392
PRECONDITION(op2().type().id() == ID_pointer);
386393
}
387394

395+
pointer_in_range_exprt(exprt a, exprt b, exprt c)
396+
: pointer_in_range_exprt(
397+
std::move(a),
398+
std::move(b),
399+
std::move(c),
400+
nil_exprt{},
401+
nil_exprt{})
402+
{
403+
}
404+
388405
const exprt &lower_bound() const
389406
{
390407
return op0();
@@ -400,6 +417,26 @@ class pointer_in_range_exprt : public ternary_exprt
400417
return op2();
401418
}
402419

420+
const exprt &deallocated_ptr() const
421+
{
422+
return op3();
423+
}
424+
425+
exprt &deallocated_ptr()
426+
{
427+
return op3();
428+
}
429+
430+
const exprt &dead_ptr() const
431+
{
432+
return operands()[4];
433+
}
434+
435+
exprt &dead_ptr()
436+
{
437+
return operands()[4];
438+
}
439+
403440
// translate into equivalent conjunction
404441
exprt lower() const;
405442
};
@@ -412,14 +449,14 @@ inline bool can_cast_expr<pointer_in_range_exprt>(const exprt &base)
412449

413450
inline void validate_expr(const pointer_in_range_exprt &value)
414451
{
415-
validate_operands(value, 3, "pointer_in_range must have three operands");
452+
validate_operands(value, 5, "pointer_in_range must have five operands");
416453
}
417454

418455
inline const pointer_in_range_exprt &to_pointer_in_range_expr(const exprt &expr)
419456
{
420457
PRECONDITION(expr.id() == ID_pointer_in_range);
421458
DATA_INVARIANT(
422-
expr.operands().size() == 3, "pointer_in_range must have three operands");
459+
expr.operands().size() == 5, "pointer_in_range must have five operands");
423460
return static_cast<const pointer_in_range_exprt &>(expr);
424461
}
425462

@@ -429,7 +466,7 @@ inline pointer_in_range_exprt &to_pointer_in_range_expr(exprt &expr)
429466
{
430467
PRECONDITION(expr.id() == ID_pointer_in_range);
431468
DATA_INVARIANT(
432-
expr.operands().size() == 3, "pointer_in_range must have three operands");
469+
expr.operands().size() == 5, "pointer_in_range must have five operands");
433470
return static_cast<pointer_in_range_exprt &>(expr);
434471
}
435472

@@ -814,11 +851,32 @@ class null_pointer_exprt : public constant_exprt
814851

815852
/// \brief A base class for a predicate that indicates that an
816853
/// address range is ok to read or write or both
817-
class r_or_w_ok_exprt : public binary_predicate_exprt
854+
class r_or_w_ok_exprt : public expr_protectedt
818855
{
819856
public:
820-
explicit r_or_w_ok_exprt(irep_idt id, exprt pointer, exprt size)
821-
: binary_predicate_exprt(std::move(pointer), id, std::move(size))
857+
r_or_w_ok_exprt(
858+
irep_idt id,
859+
exprt pointer,
860+
exprt size,
861+
exprt is_deallocated,
862+
exprt is_dead)
863+
: expr_protectedt(
864+
id,
865+
bool_typet{},
866+
{std::move(pointer),
867+
std::move(size),
868+
std::move(is_deallocated),
869+
std::move(is_dead)})
870+
{
871+
}
872+
873+
r_or_w_ok_exprt(irep_idt id, exprt pointer, exprt size)
874+
: r_or_w_ok_exprt(
875+
id,
876+
std::move(pointer),
877+
std::move(size),
878+
nil_exprt{},
879+
nil_exprt{})
822880
{
823881
}
824882

@@ -831,6 +889,26 @@ class r_or_w_ok_exprt : public binary_predicate_exprt
831889
{
832890
return op1();
833891
}
892+
893+
const exprt &deallocated_ptr() const
894+
{
895+
return op2();
896+
}
897+
898+
exprt &deallocated_ptr()
899+
{
900+
return op2();
901+
}
902+
903+
const exprt &dead_ptr() const
904+
{
905+
return op3();
906+
}
907+
908+
exprt &dead_ptr()
909+
{
910+
return op3();
911+
}
834912
};
835913

836914
template <>
@@ -841,7 +919,7 @@ inline bool can_cast_expr<r_or_w_ok_exprt>(const exprt &base)
841919

842920
inline void validate_expr(const r_or_w_ok_exprt &value)
843921
{
844-
validate_operands(value, 2, "r_or_w_ok must have two operands");
922+
validate_operands(value, 4, "r_or_w_ok must have four operands");
845923
}
846924

847925
inline const r_or_w_ok_exprt &to_r_or_w_ok_expr(const exprt &expr)
@@ -857,8 +935,18 @@ inline const r_or_w_ok_exprt &to_r_or_w_ok_expr(const exprt &expr)
857935
class r_ok_exprt : public r_or_w_ok_exprt
858936
{
859937
public:
860-
explicit r_ok_exprt(exprt pointer, exprt size)
861-
: r_or_w_ok_exprt(ID_r_ok, std::move(pointer), std::move(size))
938+
r_ok_exprt(exprt pointer, exprt size, exprt is_deallocated, exprt is_dead)
939+
: r_or_w_ok_exprt(
940+
ID_r_ok,
941+
std::move(pointer),
942+
std::move(size),
943+
std::move(is_deallocated),
944+
std::move(is_dead))
945+
{
946+
}
947+
948+
r_ok_exprt(exprt pointer, exprt size)
949+
: r_ok_exprt(std::move(pointer), std::move(size), nil_exprt{}, nil_exprt{})
862950
{
863951
}
864952
};
@@ -871,7 +959,7 @@ inline bool can_cast_expr<r_ok_exprt>(const exprt &base)
871959

872960
inline void validate_expr(const r_ok_exprt &value)
873961
{
874-
validate_operands(value, 2, "r_ok must have two operands");
962+
validate_operands(value, 4, "r_ok must have four operands");
875963
}
876964

877965
inline const r_ok_exprt &to_r_ok_expr(const exprt &expr)
@@ -886,8 +974,18 @@ inline const r_ok_exprt &to_r_ok_expr(const exprt &expr)
886974
class w_ok_exprt : public r_or_w_ok_exprt
887975
{
888976
public:
889-
explicit w_ok_exprt(exprt pointer, exprt size)
890-
: r_or_w_ok_exprt(ID_w_ok, std::move(pointer), std::move(size))
977+
w_ok_exprt(exprt pointer, exprt size, exprt is_deallocated, exprt is_dead)
978+
: r_or_w_ok_exprt(
979+
ID_w_ok,
980+
std::move(pointer),
981+
std::move(size),
982+
std::move(is_deallocated),
983+
std::move(is_dead))
984+
{
985+
}
986+
987+
w_ok_exprt(exprt pointer, exprt size)
988+
: w_ok_exprt(std::move(pointer), std::move(size), nil_exprt{}, nil_exprt{})
891989
{
892990
}
893991
};
@@ -900,7 +998,7 @@ inline bool can_cast_expr<w_ok_exprt>(const exprt &base)
900998

901999
inline void validate_expr(const w_ok_exprt &value)
9021000
{
903-
validate_operands(value, 2, "w_ok must have two operands");
1001+
validate_operands(value, 4, "w_ok must have four operands");
9041002
}
9051003

9061004
inline const w_ok_exprt &to_w_ok_expr(const exprt &expr)

0 commit comments

Comments
 (0)