Skip to content

Commit af3967f

Browse files
authored
Merge pull request #6838 from tautschnig/cleanup/malloc-0
Document and use malloc(0) behaviour
2 parents fee1d3e + a9a82c7 commit af3967f

File tree

3 files changed

+58
-28
lines changed

3 files changed

+58
-28
lines changed

doc/cprover-manual/memory-primitives.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,63 @@ point into another memory object (such as could happen when running on a real
9090
machine). To verify that pointers stay within the bounds of their pointees, the
9191
CBMC option `--pointer-overflow-check` can be used.
9292

93+
### Malloc modelling
94+
95+
CBMC ships a model of `malloc` that seeks to emulate the behaviour of the C
96+
standard library. This model is configurable to suit the assumptions the
97+
software under scrutiny may be making. One common assumption, matched by CBMC's
98+
default configuration, is that dynamic memory allocation always succeeds and
99+
`malloc` never returns a `NULL` pointer. Code making such an assumption will
100+
look as follows:
101+
102+
```C
103+
int *p = malloc(sizeof(int));
104+
*p = 42; // unconditional dereference, no check for p being NULL
105+
```
106+
107+
This extends to the case of `malloc(0)`, and CBMC returns a valid pointer to an
108+
object. The size of that object is zero, implying that any attempt to read from
109+
or write to this object will result in an out-of-bounds access. The ensuing
110+
undefined behaviour can be detected by running CBMC with `--pointer-check`.
111+
112+
In an actual execution, however, memory allocation may fail for a number of
113+
reasons and `malloc` would return a NULL pointer. CBMC's model can, therefore,
114+
also be configured to fail allocating memory when the requested allocation size
115+
is larger than representable under CBMC's object-offset model (as described in
116+
[Memory and pointers in CBMC](#memory-and-pointers-in-cbmc)), or even
117+
non-deterministically fail (for any size). Any such failure can either result in
118+
calls to `malloc` returning `NULL`, or reporting such a call as a failed
119+
property. The following command line options facilitate the above failure
120+
configurations:
121+
122+
|Flag | Check |
123+
|------------------------|---------------------------------------------------|
124+
| `--malloc-fail-null` | return NULL when emulating an allocation failure |
125+
| `--malloc-may-fail` | non-deterministically fail to allocate |
126+
127+
Note that the use of `--malloc-may-fail` also requires `--malloc-fail-null`. The
128+
following code example demonstrates the effect of these options:
129+
130+
```C
131+
int error = 0;
132+
int *p = malloc(sizeof(int));
133+
if(p != NULL)
134+
*p = 42;
135+
else
136+
error = 1;
137+
```
138+
139+
Under CBMC's default model of `malloc`, the `else` branch is unreachable.
140+
When running CBMC with `--malloc-fail-null --malloc-may-fail`, `p` would
141+
non-deterministically be set to `NULL`, making all branches in the above code
142+
reachable.
143+
144+
These malloc failure options need to be set when the C library model is added to
145+
the program. Typically this is upon invoking CBMC, but if the user has chosen to
146+
do so via \ref goto-instrument (using `goto-instrument --add-library`), then the
147+
malloc failure mode needs to be specified with that `goto-instrument`
148+
invocation, i.e., as an option to `goto-instrument`.
149+
93150
## Uninitialized pointers
94151

95152
In verification tools, uninitialized variables are typically treated as having a

doc/cprover-manual/properties.md

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -394,30 +394,3 @@ example, replacing functions or setting global variables with the `__CPROVER`
394394
prefix might make analysis impossible. To avoid doing this by accident, negative
395395
lookahead can be used. For example, `(?!__).*` matches all names not starting
396396
with `__`.
397-
398-
### Malloc failure mode
399-
400-
|Flag | Check |
401-
|------------------------|-------------------------------------------------|
402-
| `--malloc-fail-null` | in case malloc fails return NULL |
403-
| `--malloc-fail-assert` | in case malloc fails report as failed property |
404-
| `--malloc-may-fail` | malloc may non-deterministically fail |
405-
406-
Calling `malloc` may fail for a number of reasons and the function may return a
407-
NULL pointer. The users can choose if and how they want the `malloc`-related
408-
failures to occur. The option `--malloc-fail-null` results in `malloc` returning
409-
the NULL pointer when failing. The option `--malloc-fail-assert` places
410-
additional properties inside `malloc` that are checked and if failing the
411-
verification is terminated (by `assume(false)`). One such property is that the
412-
allocated size is not too large, i.e. internally representable. When neither of
413-
those two options are used, CBMC will assume that `malloc` does not fail.
414-
415-
Malloc may also fail for external reasons which are not modelled by CProver. If
416-
you want to replicate this behaviour use the option `--malloc-may-fail` in
417-
conjunction with one of the above modes of failure.
418-
419-
These malloc failure options need to be set when the C library model is added to
420-
the program. Typically this is upon invoking CBMC, but if the user has chosen to
421-
do so via `goto-instrument --add-library`, then the malloc failure mode needs to
422-
be specified with that `goto-instrument` invocation, i.e., as an option to
423-
`goto-instrument`.

src/ansi-c/library/stdlib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ void *realloc(void *ptr, __CPROVER_size_t malloc_size)
503503
if(malloc_size==0)
504504
{
505505
free(ptr);
506-
return malloc(1);
506+
return malloc(0);
507507
}
508508

509509
// this shouldn't move if the new size isn't bigger

0 commit comments

Comments
 (0)