Add malloc-may-fail option to goto-check#5212
Conversation
|
This may fix #4605. |
allredj
left a comment
There was a problem hiding this comment.
✔️
Passed Diffblue compatibility checks (cbmc commit: effdd30).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/143378007
Codecov Report
@@ Coverage Diff @@
## develop #5212 +/- ##
========================================
Coverage 68.19% 68.19%
========================================
Files 1176 1176
Lines 97516 97520 +4
========================================
+ Hits 66501 66504 +3
- Misses 31015 31016 +1
Continue to review full report at Codecov.
|
martin-cs
left a comment
There was a problem hiding this comment.
Why not just change the model of what malloc does? That seems to keep all of the functionality in one place?
https://github.com/diffblue/cbmc/blob/develop/src/ansi-c/library/stdlib.c#L113
Maybe it is time to change https://github.com/diffblue/cbmc/blob/develop/src/ansi-c/library/stdlib.c#L115 specifically.
I think the reasoning here is to avoid "false-positive" alarms with every |
|
I think the reasoning here is to avoid "false-positive" alarms with
every `malloc` call by default, and only to be correctly reporting
the potential of malloc to fail if requested.
Then have a global as part of the model that allows it to be turned on
/ off / linked to a symbolic value during analysis. It doesn't have to
be, and shouldn't be, hard-coded to one way or the other.
|
d97765e to
06ead45
Compare
src/ansi-c/library/stdlib.c
Outdated
| // make sure it's not recorded as deallocated | ||
| __CPROVER_deallocated=(malloc_res==__CPROVER_deallocated)?0:__CPROVER_deallocated; | ||
| __CPROVER_assert( | ||
| __CPROVER_malloc_may_fail == (__CPROVER_bool)0, "malloc may fail"); |
There was a problem hiding this comment.
? Why is there an assert that this is false? I thought this would be more like if (__CPROVER_malloc_may_fail && __VERIFIER_nondet___CPROVER_bool()) return NULL;
There was a problem hiding this comment.
Because conditionally returning NULL breaks too many things down the line in CBMC.
There was a problem hiding this comment.
I take it back. Returning NULL seems to work here just fine.
06ead45 to
993b47b
Compare
4b6ce6d to
059cbc9
Compare
| { | ||
| int Count; | ||
| Union List[1]; | ||
| Union List[0]; |
There was a problem hiding this comment.
❓ Why does this change? The change should go in a separate commit with a why
There was a problem hiding this comment.
This was undefined behaviour (and the changed in malloc exposed that CBMC does not really support that). It now has separate commit with explanation.
There was a problem hiding this comment.
I find it rather surprising that the changes in this PR expose the lack of support for this C90-hack. What exactly was going wrong here?
There was a problem hiding this comment.
Why this particular PR exposes the problem is a bit more complicated. But the problem itself can be easily reproduced, e.g. (CMBC reports the assertion as failing):
#include <malloc.h>
#include <assert.h>
struct Foo
{
int i;
char data[1];
};
int main()
{
struct Foo* foo = malloc(sizeof(struct Foo) + sizeof(char));
foo->data[1]='b'; // set data[1]
assert(foo->data[1]=='b'); // check data[1] -- should succeed
return 0;
}
src/cbmc/cbmc_parse_options.h
Outdated
| "(document-subgoals)(outfile):(test-preprocessor)" \ | ||
| "D:I:(c89)(c99)(c11)(cpp98)(cpp03)(cpp11)" \ | ||
| "(object-bits):" \ | ||
| "(malloc-may-fail)" \ |
There was a problem hiding this comment.
❔ should this option be available in other C based tools, like goto-analyzer, or does that not really make sense?
src/util/config.cpp
Outdated
| bv_encoding.is_object_bits_default = false; | ||
| } | ||
|
|
||
| if(cmdline.isset("malloc-may-fail")) |
There was a problem hiding this comment.
⛏️ ?
| if(cmdline.isset("malloc-may-fail")) | |
| ansi_c.malloc_may_fail = cmdline.isset("malloc-may-fail"); |
b8f6035 to
043f0e0
Compare
| ^\[main.assertion.\d+\] line \d+ assertion p: FAILURE$ | ||
| ^VERIFICATION FAILED$ | ||
| -- | ||
| ^warning: ignoring |
There was a problem hiding this comment.
⛏️ in future, we've found it helpful in test-gen to include a description explaining the purpose of the test below the line. for all tests. It helps when a test fails to understand why does it even exist. E.g
--
^warning: ignoring
--
Test that if --malloc-may-fail is enabled, that assert can return a null pointer
tautschnig
left a comment
There was a problem hiding this comment.
The changes to extend support to calloc, realloc need to happen before this can be merged. The modified regression test I'd not insist as much on, but still I'd like to see clarification.
src/ansi-c/library/stdlib.c
Outdated
| if(__CPROVER_malloc_may_fail && __VERIFIER_nondet___CPROVER_bool()) | ||
| return (void *)0; |
There was a problem hiding this comment.
- It may be more consistent to just declare a local, uninitialised variable of type
__CPROVER_boolto avoid the side-effect of a function call. - The non-determinism also needs to be introduced in
calloc. reallocnow needs to handle the case of a failingmalloc.
There was a problem hiding this comment.
Add 1. No can do: using uninitialised variables doesn't even compile with the current flag set. I can initialise it to nondet_bool.
| { | ||
| int Count; | ||
| Union List[1]; | ||
| Union List[0]; |
There was a problem hiding this comment.
I find it rather surprising that the changes in this PR expose the lack of support for this C90-hack. What exactly was going wrong here?
src/cbmc/cbmc_parse_options.cpp
Outdated
| "\n" | ||
| "Backend options:\n" | ||
| " --object-bits n number of bits used for object addresses\n" | ||
| // NOLINTNEXTLINE(whitespace/line_length) |
There was a problem hiding this comment.
The commit message says "will be squashed" so presumably that should happen ;-)
6ea384f to
f999d2f
Compare
f999d2f to
241b666
Compare
|
There seems to be some duplication w.r.t. #5210 which is preferred? |
|
@martin-cs I believe the difference between this PR and #5210 is around the behaviour they are modelling. #5210 is modelling the very specific case of what happens if the user code attempts to alloc a chunk of memory that is larger than CBMC can represent. Where as this PR is modelling the case where "the system" (e.g. OS) cannot satisfy a malloc request because of insufficient memory availability. This is a non-deterministic situation, so this PR models the situation where malloc may non-deterministically fail. |
chrisr-diffblue
left a comment
There was a problem hiding this comment.
Looks pretty good, but would also be super nice if you could extend the user docs at the same time ;-)
src/cbmc/cbmc_parse_options.cpp
Outdated
| "Backend options:\n" | ||
| " --object-bits n number of bits used for object addresses\n" | ||
| // NOLINTNEXTLINE(whitespace/line_length) | ||
| " --malloc-may-fail allow malloc calls to return a null pointer\n" |
There was a problem hiding this comment.
Similar to #5210, should this help message move up into the "Program instrumentation options" section?
There was a problem hiding this comment.
Moved to the instrumentation section + the documentation was also added.
03cff3d to
fec2e3a
Compare
fec2e3a to
0f2f62f
Compare
hannes-steffenhagen-diffblue
left a comment
There was a problem hiding this comment.
This should have an implementation for realloc as well, also I don’t think we should mix up the cases where malloc fails due to some nondeterministic condition and when it fails because we reach cprover internal limits.
|
|
||
| __CPROVER_bool should_malloc_fail = __VERIFIER_nondet___CPROVER_bool(); | ||
| __CPROVER_assert( | ||
| !__CPROVER_malloc_may_fail || !should_malloc_fail, |
There was a problem hiding this comment.
I don’t think it makes a lot of sense to have the assertion here in this form, this will always fail the way it is written.
martin-cs
left a comment
There was a problem hiding this comment.
I like this approach a lot more than the previous one.
and hard-code appropriate check inside our `stdlib.c`. Plus some documentation and test.
using the same code as for malloc.
More assignments due to the `__CPROVER_malloc_may_fail` instantiations.
adding one more for the malloc failing.
bc7894a to
d49cfdd
Compare
And append an
assert(false)property to everymalloccall.