Skip to content

Commit a3f383b

Browse files
committed
__CPROVER_r/w_ok does not require null or a valid pointer
The definition of __CPROVER_r/w_ok (in goto_check.cpp) does include the case of an invalid pointer, and thus, there is no need to check that the pointer given to these predicates is valid.
1 parent fd10a22 commit a3f383b

File tree

6 files changed

+23
-61
lines changed

6 files changed

+23
-61
lines changed

doc/architectural/memory-primitives.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,25 +169,28 @@ to pointers that point to within a memory object.
169169
170170
## Checking if a memory segment has at least a given size
171171
172-
The following two primitives can be used to check whether there is a memory
173-
segment starting at the given pointer and extending for at least the given
174-
number of bytes:
172+
The following three primitives can be used to check whether there is a
173+
memory segment starting at the given pointer and extending for at least the
174+
given number of bytes:
175175
176176
- `_Bool __CPROVER_r_ok(const void *p, size_t size)`
177177
- `_Bool __CPROVER_w_ok(const void *p, size_t size)`
178+
- `_Bool __CPROVER_rw_ok(const void *p, size_t size)`
178179
179-
At present, both primitives are equivalent as all memory in CBMC is considered
180+
At present, all three primitives are equivalent as all memory in CBMC is considered
180181
both readable and writeable. If `p` is the null pointer, the primitives return
181182
false. If `p` is valid, the primitives return true if the memory segment
182183
starting at the pointer has at least the given size, and false otherwise. If `p`
183-
is neither null nor valid, the semantics is unspecified. It is valid to apply
184-
the primitive to pointers that point to within a memory object. For example:
184+
is neither null nor valid, the predicate returns false.
185+
186+
It is valid to apply the primitive to pointers that have a nonzero offset.
187+
For example:
185188
186189
```C
187190
char *p = malloc(10);
188-
assert(__CPROVER_r_ok(p, 10)); // valid
191+
assert(__CPROVER_r_ok(p, 10)); // passes
189192
p += 5;
190-
assert(__CPROVER_r_ok(p, 3)); // valid
193+
assert(__CPROVER_r_ok(p, 3)); // passes
191194
assert(__CPROVER_r_ok(p, 10)); // fails
192195
```
193196

@@ -204,8 +207,6 @@ primitives are either null or valid:
204207
- `__CPROVER_same_object`
205208
- `__CPROVER_OBJECT_SIZE`
206209
- `__CPROVER_DYNAMIC_OBJECT`
207-
- `__CPROVER_r_ok`
208-
- `__CPROVER_w_ok`
209210

210211
While the first three primitives have well-defined semantics even on invalid
211212
pointers, using them on invalid pointers is usually unintended in user programs.

regression/cbmc/pointer-primitive-check-01/main.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,5 @@ void main()
1818
__CPROVER_OBJECT_SIZE(p4);
1919

2020
char *p5;
21-
__CPROVER_r_ok(p5, 1);
22-
23-
char *p6;
24-
__CPROVER_w_ok(p6, 1);
25-
26-
char *p7;
27-
__CPROVER_DYNAMIC_OBJECT(p7);
21+
__CPROVER_DYNAMIC_OBJECT(p5);
2822
}

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,10 @@ 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\(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
30-
\[main.pointer_primitives.25\] line \d+ pointer invalid in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): FAILURE
31-
\[main.pointer_primitives.26\] line \d+ deallocated dynamic object in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): SUCCESS
32-
\[main.pointer_primitives.27\] line \d+ dead object in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): SUCCESS
33-
\[main.pointer_primitives.28\] line \d+ pointer outside object bounds in IS_DYNAMIC_OBJECT\(\(const void \*\)p7\): FAILURE
22+
\[main.pointer_primitives.17\] line \d+ pointer invalid in IS_DYNAMIC_OBJECT\(\(const void \*\)p5\): FAILURE
23+
\[main.pointer_primitives.18\] line \d+ deallocated dynamic object in IS_DYNAMIC_OBJECT\(\(const void \*\)p5\): SUCCESS
24+
\[main.pointer_primitives.19\] line \d+ dead object in IS_DYNAMIC_OBJECT\(\(const void \*\)p5\): SUCCESS
25+
\[main.pointer_primitives.20\] line \d+ pointer outside object bounds in IS_DYNAMIC_OBJECT\(\(const void \*\)p5\): FAILURE
3426
--
3527
^warning: ignoring
3628
--

regression/cbmc/pointer-primitive-check-04/main.c

Lines changed: 0 additions & 6 deletions
This file was deleted.

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

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/analyses/goto_check.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,12 @@ class goto_checkt
201201
/// \param guard: the condition under which the operation happens
202202
void pointer_primitive_check(const exprt &expr, const guardt &guard);
203203

204-
/// Returns true if the given expression is a pointer primitive such as
205-
/// __CPROVER_r_ok()
204+
/// Returns true if the given expression is a pointer primitive
205+
/// that requires a pointer primitive check
206206
///
207207
/// \param expr expression
208208
/// \return true if the given expression is a pointer primitive
209-
bool is_pointer_primitive(const exprt &expr);
209+
bool requires_pointer_primitive_check(const exprt &expr);
210210

211211
optionalt<goto_checkt::conditiont>
212212
get_pointer_is_null_condition(const exprt &address, const exprt &size);
@@ -1282,10 +1282,7 @@ void goto_checkt::pointer_primitive_check(
12821282
if(expr.source_location().is_built_in())
12831283
return;
12841284

1285-
const exprt pointer =
1286-
(expr.id() == ID_r_ok || expr.id() == ID_w_ok || expr.id() == ID_rw_ok)
1287-
? to_r_or_w_ok_expr(expr).pointer()
1288-
: to_unary_expr(expr).op();
1285+
const exprt pointer = to_unary_expr(expr).op();
12891286

12901287
CHECK_RETURN(pointer.type().id() == ID_pointer);
12911288

@@ -1317,15 +1314,13 @@ void goto_checkt::pointer_primitive_check(
13171314
}
13181315
}
13191316

1320-
bool goto_checkt::is_pointer_primitive(const exprt &expr)
1317+
bool goto_checkt::requires_pointer_primitive_check(const exprt &expr)
13211318
{
13221319
// we don't need to include the __CPROVER_same_object primitive here as it
13231320
// is replaced by lower level primitives in the special function handling
13241321
// during typechecking (see c_typecheck_expr.cpp)
13251322
return expr.id() == ID_pointer_object || expr.id() == ID_pointer_offset ||
1326-
expr.id() == ID_object_size || expr.id() == ID_r_ok ||
1327-
expr.id() == ID_w_ok || expr.id() == ID_rw_ok ||
1328-
expr.id() == ID_is_dynamic_object;
1323+
expr.id() == ID_object_size || expr.id() == ID_is_dynamic_object;
13291324
}
13301325

13311326
goto_checkt::conditionst goto_checkt::get_pointer_dereferenceable_conditions(
@@ -1795,7 +1790,7 @@ void goto_checkt::check_rec(const exprt &expr, guardt &guard)
17951790
{
17961791
pointer_validity_check(to_dereference_expr(expr), expr, guard);
17971792
}
1798-
else if(is_pointer_primitive(expr))
1793+
else if(requires_pointer_primitive_check(expr))
17991794
{
18001795
pointer_primitive_check(expr, guard);
18011796
}

0 commit comments

Comments
 (0)