Skip to content

Commit 535dc20

Browse files
committed
variants of r/w_ok
This adds 1) a new predicate rw_ok, which is the conjunction of r_ok and w_ok; 2) variants of r_ok, w_ok and rw_ok that only have one parameter, a pointer. The size of the memory range that is ok to read or write is given implicitly by the size of the subtype of the pointer argument.
1 parent 865d3b6 commit 535dc20

File tree

10 files changed

+99
-35
lines changed

10 files changed

+99
-35
lines changed

doc/cprover-manual/api.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,16 +191,25 @@ option to verify the preconditions of the primitives.
191191
```C
192192
__CPROVER_size_t __CPROVER_OBJECT_SIZE(const void *p);
193193
_Bool __CPROVER_DYNAMIC_OBJECT(const void *p);
194+
void __CPROVER_r_ok(const T *p);
194195
void __CPROVER_r_ok(const void *p, size_t size);
196+
void __CPROVER_w_ok(const T *p);
195197
void __CPROVER_w_ok(const void *p, size_t size);
198+
void __CPROVER_rw_ok(const T *p);
199+
void __CPROVER_rw_ok(const void *p, size_t size);
196200
```
197201

198202
The function **\_\_CPROVER_\_OBJECT\_SIZE** returns the size of the object the
199203
given pointer points to. The function **\_\_CPROVER\_DYNAMIC\_OBJECT** returns
200204
true if the pointer passed as an argument points to a dynamically allocated
201-
object. The function **\_\_CPROVER\_r_ok** returns true if reading the piece of
202-
memory starting at the given pointer with the given size is safe.
203-
**\_\_CPROVER\_w_ok** does the same with writing.
205+
object.
206+
207+
The function **\_\_CPROVER\_r_ok** returns true if reading the piece of
208+
memory starting at the given pointer with the given size is safe.
209+
**\_\_CPROVER\_w_ok** does the same with writing, and **\_\_CPROVER\_rw_ok**
210+
returns true when it is safe to do both. These predicates can be given an
211+
optional size; when the size argument is not given, the size of the subtype
212+
(which must not be **void**) of the pointer type is used.
204213

205214
### Predefined Types and Symbols
206215

regression/cbmc/pointer-primitive-check-01/test.desc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ main.c
1919
\[main.pointer_primitives.14\] line \d+ deallocated dynamic object in OBJECT_SIZE\(\(const void \*\)p4\): SUCCESS
2020
\[main.pointer_primitives.15\] line \d+ dead object in OBJECT_SIZE\(\(const void \*\)p4\): SUCCESS
2121
\[main.pointer_primitives.16\] line \d+ pointer outside object bounds in OBJECT_SIZE\(\(const void \*\)p4\): FAILURE
22-
\[main.pointer_primitives.17\] line \d+ pointer invalid in R_OK\(\(const void \*\)p5, \(__CPROVER_size_t\)1\): FAILURE
23-
\[main.pointer_primitives.18\] line \d+ deallocated dynamic object in R_OK\(\(const void \*\)p5, \(__CPROVER_size_t\)1\): SUCCESS
24-
\[main.pointer_primitives.19\] line \d+ dead object in R_OK\(\(const void \*\)p5, \(__CPROVER_size_t\)1\): SUCCESS
25-
\[main.pointer_primitives.20\] line \d+ pointer outside object bounds in R_OK\(\(const void \*\)p5, \(__CPROVER_size_t\)1\): FAILURE
26-
\[main.pointer_primitives.21\] line \d+ pointer invalid in W_OK\(\(const void \*\)p6, \(__CPROVER_size_t\)1\): FAILURE
27-
\[main.pointer_primitives.22\] line \d+ deallocated dynamic object in W_OK\(\(const void \*\)p6, \(__CPROVER_size_t\)1\): SUCCESS
28-
\[main.pointer_primitives.23\] line \d+ dead object in W_OK\(\(const void \*\)p6, \(__CPROVER_size_t\)1\): SUCCESS
29-
\[main.pointer_primitives.24\] line \d+ pointer outside object bounds in W_OK\(\(const void \*\)p6, \(__CPROVER_size_t\)1\): FAILURE
22+
\[main.pointer_primitives.17\] line \d+ pointer invalid in R_OK\(p5, .*1\): FAILURE
23+
\[main.pointer_primitives.18\] line \d+ deallocated dynamic object in R_OK\(p5, .*1\): SUCCESS
24+
\[main.pointer_primitives.19\] line \d+ dead object in R_OK\(p5, .*1\): SUCCESS
25+
\[main.pointer_primitives.20\] line \d+ pointer outside object bounds in R_OK\(p5, .*1\): FAILURE
26+
\[main.pointer_primitives.21\] line \d+ pointer invalid in W_OK\(p6, \(.*\)1\): FAILURE
27+
\[main.pointer_primitives.22\] line \d+ deallocated dynamic object in W_OK\(p6, .*1\): SUCCESS
28+
\[main.pointer_primitives.23\] line \d+ dead object in W_OK\(p6, .*1\): SUCCESS
29+
\[main.pointer_primitives.24\] line \d+ pointer outside object bounds in W_OK\(p6, .*1\): FAILURE
3030
\[main.pointer_primitives.25\] line \d+ pointer invalid in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): FAILURE
3131
\[main.pointer_primitives.26\] line \d+ deallocated dynamic object in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): SUCCESS
3232
\[main.pointer_primitives.27\] line \d+ dead object in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): SUCCESS

regression/cbmc/pointer-primitive-check-04/test.desc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ main.c
33
--pointer-primitive-check
44
^EXIT=10$
55
^SIGNAL=0$
6-
\[main.pointer_primitives.1\] line \d+ pointer invalid in R_OK\(\(const void \*\)p, \(__CPROVER_size_t\)1\): FAILURE
7-
\[main.pointer_primitives.2\] line \d+ deallocated dynamic object in R_OK\(\(const void \*\)p, \(__CPROVER_size_t\)1\): SUCCESS
8-
\[main.pointer_primitives.3\] line \d+ dead object in R_OK\(\(const void \*\)p, \(__CPROVER_size_t\)1\): SUCCESS
9-
\[main.pointer_primitives.4\] line \d+ pointer outside object bounds in R_OK\(\(const void \*\)p, \(__CPROVER_size_t\)1\): FAILURE
6+
\[main.pointer_primitives.1\] line \d+ pointer invalid in R_OK\(p, .*1\): FAILURE
7+
\[main.pointer_primitives.2\] line \d+ deallocated dynamic object in R_OK\(p, .*1\): SUCCESS
8+
\[main.pointer_primitives.3\] line \d+ dead object in R_OK\(p, .*1\): SUCCESS
9+
\[main.pointer_primitives.4\] line \d+ pointer outside object bounds in R_OK\(p, .*1\): FAILURE
1010
--
1111
^warning: ignoring
1212
--

src/analyses/goto_check.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,9 +1260,10 @@ void goto_checkt::pointer_primitive_check(
12601260
if(expr.source_location().is_built_in())
12611261
return;
12621262

1263-
const exprt pointer = (expr.id() == ID_r_ok || expr.id() == ID_w_ok)
1264-
? to_r_or_w_ok_expr(expr).pointer()
1265-
: to_unary_expr(expr).op();
1263+
const exprt pointer =
1264+
(expr.id() == ID_r_ok || expr.id() == ID_w_ok || expr.id() == ID_rw_ok)
1265+
? to_r_or_w_ok_expr(expr).pointer()
1266+
: to_unary_expr(expr).op();
12661267

12671268
CHECK_RETURN(pointer.type().id() == ID_pointer);
12681269

@@ -1301,7 +1302,8 @@ bool goto_checkt::is_pointer_primitive(const exprt &expr)
13011302
// during typechecking (see c_typecheck_expr.cpp)
13021303
return expr.id() == ID_pointer_object || expr.id() == ID_pointer_offset ||
13031304
expr.id() == ID_object_size || expr.id() == ID_r_ok ||
1304-
expr.id() == ID_w_ok || expr.id() == ID_is_dynamic_object;
1305+
expr.id() == ID_w_ok || expr.id() == ID_rw_ok ||
1306+
expr.id() == ID_is_dynamic_object;
13051307
}
13061308

13071309
goto_checkt::conditionst goto_checkt::get_pointer_dereferenceable_conditions(
@@ -1787,7 +1789,7 @@ void goto_checkt::check(const exprt &expr)
17871789
check_rec(expr, guard);
17881790
}
17891791

1790-
/// expand the r_ok and w_ok predicates
1792+
/// expand the r_ok, w_ok and rw_ok predicates
17911793
optionalt<exprt> goto_checkt::rw_ok_check(exprt expr)
17921794
{
17931795
bool modified = false;
@@ -1802,7 +1804,7 @@ optionalt<exprt> goto_checkt::rw_ok_check(exprt expr)
18021804
}
18031805
}
18041806

1805-
if(expr.id() == ID_r_ok || expr.id() == ID_w_ok)
1807+
if(expr.id() == ID_r_ok || expr.id() == ID_w_ok || expr.id() == ID_rw_ok)
18061808
{
18071809
// these get an address as first argument and a size as second
18081810
DATA_INVARIANT(
@@ -1917,7 +1919,8 @@ void goto_checkt::goto_check(
19171919
check(i.get_condition());
19181920

19191921
if(has_subexpr(i.get_condition(), [](const exprt &expr) {
1920-
return expr.id() == ID_r_ok || expr.id() == ID_w_ok;
1922+
return expr.id() == ID_r_ok || expr.id() == ID_w_ok ||
1923+
expr.id() == ID_rw_ok;
19211924
}))
19221925
{
19231926
auto rw_ok_cond = rw_ok_check(i.get_condition());
@@ -1974,7 +1977,8 @@ void goto_checkt::goto_check(
19741977
invalidate(code_assign.lhs());
19751978

19761979
if(has_subexpr(code_assign.rhs(), [](const exprt &expr) {
1977-
return expr.id() == ID_r_ok || expr.id() == ID_w_ok;
1980+
return expr.id() == ID_r_ok || expr.id() == ID_w_ok ||
1981+
expr.id() == ID_rw_ok;
19781982
}))
19791983
{
19801984
const exprt &rhs = i.get_assign().rhs();
@@ -2033,7 +2037,8 @@ void goto_checkt::goto_check(
20332037
invalidate(i.return_value());
20342038

20352039
if(has_subexpr(i.return_value(), [](const exprt &expr) {
2036-
return expr.id() == ID_r_ok || expr.id() == ID_w_ok;
2040+
return expr.id() == ID_r_ok || expr.id() == ID_w_ok ||
2041+
expr.id() == ID_rw_ok;
20372042
}))
20382043
{
20392044
exprt &return_value = i.return_value();

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,20 +2558,65 @@ exprt c_typecheck_baset::do_special_functions(
25582558
return std::move(malloc_expr);
25592559
}
25602560
else if(
2561-
identifier == CPROVER_PREFIX "r_ok" || identifier == CPROVER_PREFIX "w_ok")
2561+
identifier == CPROVER_PREFIX "r_ok" ||
2562+
identifier == CPROVER_PREFIX "w_ok" || identifier == CPROVER_PREFIX "rw_ok")
25622563
{
2563-
if(expr.arguments().size() != 2)
2564+
if(expr.arguments().size() != 1 && expr.arguments().size() != 2)
25642565
{
25652566
error().source_location = f_op.source_location();
2566-
error() << identifier << " expects two operands" << eom;
2567+
error() << identifier << " expects one or two operands" << eom;
25672568
throw 0;
25682569
}
25692570

25702571
typecheck_function_call_arguments(expr);
25712572

2572-
irep_idt id = identifier == CPROVER_PREFIX "r_ok" ? ID_r_ok : ID_w_ok;
2573+
// the first argument must be a pointer
2574+
const auto &pointer_expr = expr.arguments()[0];
2575+
if(pointer_expr.type().id() != ID_pointer)
2576+
{
2577+
error().source_location = f_op.source_location();
2578+
error() << identifier << " expects a pointer as first argument" << eom;
2579+
throw 0;
2580+
}
2581+
2582+
// The second argument, when given, is a size_t.
2583+
// When not given, use the pointer subtype.
2584+
exprt size_expr;
2585+
2586+
if(expr.arguments().size() == 2)
2587+
{
2588+
implicit_typecast(expr.arguments()[1], size_type());
2589+
size_expr = expr.arguments()[1];
2590+
}
2591+
else
2592+
{
2593+
// Won't do void *
2594+
const auto &subtype = to_pointer_type(pointer_expr.type()).subtype();
2595+
if(subtype.id() == ID_empty)
2596+
{
2597+
error().source_location = f_op.source_location();
2598+
error() << identifier << " expects a size when given a void pointer"
2599+
<< eom;
2600+
throw 0;
2601+
}
2602+
2603+
auto size_expr_opt = size_of_expr(subtype, *this);
2604+
if(!size_expr_opt.has_value())
2605+
{
2606+
error().source_location = f_op.source_location();
2607+
error() << identifier << " was given object pointer without size"
2608+
<< eom;
2609+
throw 0;
2610+
}
2611+
2612+
size_expr = std::move(size_expr_opt.value());
2613+
}
2614+
2615+
irep_idt id = identifier == CPROVER_PREFIX "r_ok"
2616+
? ID_r_ok
2617+
: identifier == CPROVER_PREFIX "w_ok" ? ID_w_ok : ID_rw_ok;
25732618

2574-
r_or_w_ok_exprt ok_expr(id, expr.arguments()[0], expr.arguments()[1]);
2619+
r_or_w_ok_exprt ok_expr(id, pointer_expr, size_expr);
25752620
ok_expr.add_source_location() = source_location;
25762621

25772622
return std::move(ok_expr);

src/ansi-c/cprover_builtin_headers.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ __CPROVER_bool __CPROVER_is_invalid_pointer(const void *);
1010
_Bool __CPROVER_is_zero_string(const void *);
1111
__CPROVER_size_t __CPROVER_zero_string_length(const void *);
1212
__CPROVER_size_t __CPROVER_buffer_size(const void *);
13-
__CPROVER_bool __CPROVER_r_ok(const void *, __CPROVER_size_t);
14-
__CPROVER_bool __CPROVER_w_ok(const void *, __CPROVER_size_t);
13+
__CPROVER_bool __CPROVER_r_ok();
14+
__CPROVER_bool __CPROVER_w_ok();
15+
__CPROVER_bool __CPROVER_rw_ok();
1516

1617
// bitvector analysis
1718
__CPROVER_bool __CPROVER_get_flag(const void *, const char *);

src/ansi-c/expr2c.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3847,6 +3847,7 @@ optionalt<std::string> expr2ct::convert_function(const exprt &src)
38473847
{ID_pointer_offset, "POINTER_OFFSET"},
38483848
{ID_r_ok, "R_OK"},
38493849
{ID_w_ok, "W_OK"},
3850+
{ID_rw_ok, "RW_OK"},
38503851
{ID_width, "WIDTH"},
38513852
};
38523853

src/ansi-c/library/cprover.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ void __CPROVER_postcondition(__CPROVER_bool assertion, const char *description);
3333
_Bool __CPROVER_is_zero_string(const void *);
3434
__CPROVER_size_t __CPROVER_zero_string_length(const void *);
3535
__CPROVER_size_t __CPROVER_buffer_size(const void *);
36-
__CPROVER_bool __CPROVER_r_ok(const void *, __CPROVER_size_t);
37-
__CPROVER_bool __CPROVER_w_ok(const void *, __CPROVER_size_t);
36+
__CPROVER_bool __CPROVER_r_ok();
37+
__CPROVER_bool __CPROVER_w_ok();
38+
__CPROVER_bool __CPROVER_rw_ok();
3839

3940
#if 0
4041
__CPROVER_bool __CPROVER_equal();

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ IREP_ID_TWO(C_qualifier, #qualifier)
687687
IREP_ID_TWO(C_array_ini, #array_ini)
688688
IREP_ID_ONE(r_ok)
689689
IREP_ID_ONE(w_ok)
690+
IREP_ID_ONE(rw_ok)
690691
IREP_ID_ONE(super_class)
691692
IREP_ID_ONE(exceptions_thrown_list)
692693
IREP_ID_TWO(C_java_method_type, #java_method_type)

src/util/pointer_expr.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ class null_pointer_exprt : public constant_exprt
698698
};
699699

700700
/// \brief A base class for a predicate that indicates that an
701-
/// address range is ok to read or write
701+
/// address range is ok to read or write or both
702702
class r_or_w_ok_exprt : public binary_predicate_exprt
703703
{
704704
public:
@@ -720,7 +720,8 @@ class r_or_w_ok_exprt : public binary_predicate_exprt
720720

721721
inline const r_or_w_ok_exprt &to_r_or_w_ok_expr(const exprt &expr)
722722
{
723-
PRECONDITION(expr.id() == ID_r_ok || expr.id() == ID_w_ok);
723+
PRECONDITION(
724+
expr.id() == ID_r_ok || expr.id() == ID_w_ok || expr.id() == ID_rw_ok);
724725
auto &ret = static_cast<const r_or_w_ok_exprt &>(expr);
725726
validate_expr(ret);
726727
return ret;

0 commit comments

Comments
 (0)