Skip to content

Commit 42c6982

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 4132a7d commit 42c6982

File tree

8 files changed

+140
-35
lines changed

8 files changed

+140
-35
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2683,8 +2683,15 @@ exprt c_typecheck_baset::do_special_functions(
26832683

26842684
typecheck_function_call_arguments(expr);
26852685

2686+
symbol_exprt deallocated =
2687+
lookup(CPROVER_PREFIX "deallocated").symbol_expr();
2688+
symbol_exprt dead = lookup(CPROVER_PREFIX "dead_object").symbol_expr();
26862689
exprt pointer_in_range_expr = pointer_in_range_exprt(
2687-
expr.arguments()[0], expr.arguments()[1], expr.arguments()[2]);
2690+
expr.arguments()[0],
2691+
expr.arguments()[1],
2692+
expr.arguments()[2],
2693+
deallocated,
2694+
dead);
26882695
pointer_in_range_expr.add_source_location() = source_location;
26892696

26902697
return pointer_in_range_expr;
@@ -3103,7 +3110,10 @@ exprt c_typecheck_baset::do_special_functions(
31033110
? ID_r_ok
31043111
: identifier == CPROVER_PREFIX "w_ok" ? ID_w_ok : ID_rw_ok;
31053112

3106-
r_or_w_ok_exprt ok_expr(id, pointer_expr, size_expr);
3113+
symbol_exprt deallocated =
3114+
lookup(CPROVER_PREFIX "deallocated").symbol_expr();
3115+
symbol_exprt dead = lookup(CPROVER_PREFIX "dead_object").symbol_expr();
3116+
r_or_w_ok_exprt ok_expr{id, pointer_expr, size_expr, deallocated, dead};
31073117
ok_expr.add_source_location() = source_location;
31083118

31093119
return std::move(ok_expr);

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/cprover/c_safety_checks.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,16 @@ void c_safety_checks_rec(
147147
{
148148
auto size = from_integer(*size_opt, size_type());
149149
auto pointer = to_dereference_expr(expr).pointer();
150+
symbol_exprt deallocated =
151+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
152+
symbol_exprt dead =
153+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
150154
auto condition = r_or_w_ok_exprt(
151-
access_type == access_typet::W ? ID_w_ok : ID_r_ok, pointer, size);
155+
access_type == access_typet::W ? ID_w_ok : ID_r_ok,
156+
pointer,
157+
size,
158+
deallocated,
159+
dead);
152160
condition.add_source_location() = expr.source_location();
153161
auto assertion_source_location = expr.source_location();
154162
assertion_source_location.set_property_class("pointer");
@@ -330,8 +338,13 @@ void c_safety_checks(
330338
const auto &p1 = it->call_arguments()[0];
331339
const auto &p2 = it->call_arguments()[1];
332340
const auto &size = it->call_arguments()[2];
333-
auto condition =
334-
and_exprt(r_ok_exprt(p1, size), r_ok_exprt(p2, size));
341+
symbol_exprt deallocated =
342+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
343+
symbol_exprt dead =
344+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
345+
auto condition = and_exprt(
346+
r_ok_exprt{p1, size, deallocated, dead},
347+
r_ok_exprt{p2, size, deallocated, dead});
335348
auto source_location = it->source_location();
336349
source_location.set_property_class("memcmp");
337350
source_location.set_comment("memcmp regions must be valid");
@@ -348,7 +361,11 @@ void c_safety_checks(
348361
// void *memchr(const void *, int, size_t);
349362
const auto &p = it->call_arguments()[0];
350363
const auto &size = it->call_arguments()[2];
351-
auto condition = r_ok_exprt(p, size);
364+
symbol_exprt deallocated =
365+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
366+
symbol_exprt dead =
367+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
368+
auto condition = r_ok_exprt{p, size, deallocated, dead};
352369
auto source_location = it->source_location();
353370
source_location.set_property_class("memchr");
354371
source_location.set_comment("memchr source must be valid");
@@ -365,7 +382,11 @@ void c_safety_checks(
365382
// void *memset(void *b, int c, size_t len);
366383
const auto &pointer = it->call_arguments()[0];
367384
const auto &size = it->call_arguments()[2];
368-
auto condition = w_ok_exprt(pointer, size);
385+
symbol_exprt deallocated =
386+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
387+
symbol_exprt dead =
388+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
389+
auto condition = w_ok_exprt{pointer, size, deallocated, dead};
369390
auto source_location = it->source_location();
370391
source_location.set_property_class("memset");
371392
source_location.set_comment("memset destination must be valid");
@@ -395,7 +416,11 @@ void c_safety_checks(
395416
{
396417
const auto &pointer = it->call_arguments()[0];
397418
const auto &size = it->call_arguments()[2];
398-
auto condition = w_ok_exprt(pointer, size);
419+
symbol_exprt deallocated =
420+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
421+
symbol_exprt dead =
422+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
423+
auto condition = w_ok_exprt{pointer, size, deallocated, dead};
399424
auto source_location = it->source_location();
400425
source_location.set_property_class("memset");
401426
source_location.set_comment("memset destination must be valid");

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
@@ -699,7 +699,10 @@ void goto_convertt::do_havoc_slice(
699699
// char nondet_contents[argument[1]];
700700
// __CPROVER_array_replace(p, nondet_contents);
701701

702-
r_or_w_ok_exprt ok_expr(ID_w_ok, arguments[0], arguments[1]);
702+
symbol_exprt deallocated =
703+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
704+
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
705+
w_ok_exprt ok_expr{arguments[0], arguments[1], deallocated, dead};
703706
ok_expr.add_source_location() = source_location;
704707
source_locationt annotated_location = source_location;
705708
annotated_location.set("user-provided", false);

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: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -369,16 +369,23 @@ 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+
explicit 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);
@@ -400,6 +407,16 @@ class pointer_in_range_exprt : public ternary_exprt
400407
return op2();
401408
}
402409

410+
const exprt &deallocated_ptr() const
411+
{
412+
return op3();
413+
}
414+
415+
const exprt &dead_ptr() const
416+
{
417+
return operands()[4];
418+
}
419+
403420
// translate into equivalent conjunction
404421
exprt lower() const;
405422
};
@@ -412,14 +429,14 @@ inline bool can_cast_expr<pointer_in_range_exprt>(const exprt &base)
412429

413430
inline void validate_expr(const pointer_in_range_exprt &value)
414431
{
415-
validate_operands(value, 3, "pointer_in_range must have three operands");
432+
validate_operands(value, 5, "pointer_in_range must have five operands");
416433
}
417434

418435
inline const pointer_in_range_exprt &to_pointer_in_range_expr(const exprt &expr)
419436
{
420437
PRECONDITION(expr.id() == ID_pointer_in_range);
421438
DATA_INVARIANT(
422-
expr.operands().size() == 3, "pointer_in_range must have three operands");
439+
expr.operands().size() == 5, "pointer_in_range must have five operands");
423440
return static_cast<const pointer_in_range_exprt &>(expr);
424441
}
425442

@@ -429,7 +446,7 @@ inline pointer_in_range_exprt &to_pointer_in_range_expr(exprt &expr)
429446
{
430447
PRECONDITION(expr.id() == ID_pointer_in_range);
431448
DATA_INVARIANT(
432-
expr.operands().size() == 3, "pointer_in_range must have three operands");
449+
expr.operands().size() == 5, "pointer_in_range must have five operands");
433450
return static_cast<pointer_in_range_exprt &>(expr);
434451
}
435452

@@ -814,11 +831,22 @@ class null_pointer_exprt : public constant_exprt
814831

815832
/// \brief A base class for a predicate that indicates that an
816833
/// address range is ok to read or write or both
817-
class r_or_w_ok_exprt : public binary_predicate_exprt
834+
class r_or_w_ok_exprt : public expr_protectedt
818835
{
819836
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))
837+
explicit r_or_w_ok_exprt(
838+
irep_idt id,
839+
exprt pointer,
840+
exprt size,
841+
exprt is_deallocated,
842+
exprt is_dead)
843+
: expr_protectedt(
844+
id,
845+
bool_typet{},
846+
{std::move(pointer),
847+
std::move(size),
848+
std::move(is_deallocated),
849+
std::move(is_dead)})
822850
{
823851
}
824852

@@ -831,6 +859,16 @@ class r_or_w_ok_exprt : public binary_predicate_exprt
831859
{
832860
return op1();
833861
}
862+
863+
const exprt &deallocated_ptr() const
864+
{
865+
return op2();
866+
}
867+
868+
const exprt &dead_ptr() const
869+
{
870+
return op3();
871+
}
834872
};
835873

836874
template <>
@@ -841,7 +879,7 @@ inline bool can_cast_expr<r_or_w_ok_exprt>(const exprt &base)
841879

842880
inline void validate_expr(const r_or_w_ok_exprt &value)
843881
{
844-
validate_operands(value, 2, "r_or_w_ok must have two operands");
882+
validate_operands(value, 4, "r_or_w_ok must have four operands");
845883
}
846884

847885
inline const r_or_w_ok_exprt &to_r_or_w_ok_expr(const exprt &expr)
@@ -857,8 +895,17 @@ inline const r_or_w_ok_exprt &to_r_or_w_ok_expr(const exprt &expr)
857895
class r_ok_exprt : public r_or_w_ok_exprt
858896
{
859897
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))
898+
explicit r_ok_exprt(
899+
exprt pointer,
900+
exprt size,
901+
exprt is_deallocated,
902+
exprt is_dead)
903+
: r_or_w_ok_exprt(
904+
ID_r_ok,
905+
std::move(pointer),
906+
std::move(size),
907+
std::move(is_deallocated),
908+
std::move(is_dead))
862909
{
863910
}
864911
};
@@ -871,7 +918,7 @@ inline bool can_cast_expr<r_ok_exprt>(const exprt &base)
871918

872919
inline void validate_expr(const r_ok_exprt &value)
873920
{
874-
validate_operands(value, 2, "r_ok must have two operands");
921+
validate_operands(value, 4, "r_ok must have four operands");
875922
}
876923

877924
inline const r_ok_exprt &to_r_ok_expr(const exprt &expr)
@@ -886,8 +933,17 @@ inline const r_ok_exprt &to_r_ok_expr(const exprt &expr)
886933
class w_ok_exprt : public r_or_w_ok_exprt
887934
{
888935
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))
936+
explicit w_ok_exprt(
937+
exprt pointer,
938+
exprt size,
939+
exprt is_deallocated,
940+
exprt is_dead)
941+
: r_or_w_ok_exprt(
942+
ID_w_ok,
943+
std::move(pointer),
944+
std::move(size),
945+
std::move(is_deallocated),
946+
std::move(is_dead))
891947
{
892948
}
893949
};
@@ -900,7 +956,7 @@ inline bool can_cast_expr<w_ok_exprt>(const exprt &base)
900956

901957
inline void validate_expr(const w_ok_exprt &value)
902958
{
903-
validate_operands(value, 2, "w_ok must have two operands");
959+
validate_operands(value, 4, "w_ok must have four operands");
904960
}
905961

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

0 commit comments

Comments
 (0)