-
Notifications
You must be signed in to change notification settings - Fork 274
Add malloc-may-fail option to goto-check #5212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This may fix #4605. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
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.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because conditionally returning NULL
breaks too many things down the line in CBMC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take it back. Returning NULL
seems to work here just fine.
06ead45
to
993b47b
Compare
4b6ce6d
to
059cbc9
Compare
@@ -11,13 +11,13 @@ typedef union | |||
typedef struct | |||
{ | |||
int Count; | |||
Union List[1]; | |||
Union List[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Why does this change? The change should go in a separate commit with a why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -48,6 +48,7 @@ class optionst; | |||
"(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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❔ should this option be available in other C based tools, like goto-analyzer, or does that not really make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ambivalent.
src/util/config.cpp
Outdated
@@ -1093,6 +1093,11 @@ bool configt::set(const cmdlinet &cmdline) | |||
bv_encoding.is_object_bits_default = false; | |||
} | |||
|
|||
if(cmdline.isset("malloc-may-fail")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ ?
if(cmdline.isset("malloc-may-fail")) | |
ansi_c.malloc_may_fail = cmdline.isset("malloc-may-fail"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
b8f6035
to
043f0e0
Compare
^\[main.assertion.\d+\] line \d+ assertion p: FAILURE$ | ||
^VERIFICATION FAILED$ | ||
-- | ||
^warning: ignoring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It may be more consistent to just declare a local, uninitialised variable of type
__CPROVER_bool
to avoid the side-effect of a function call. - The non-determinism also needs to be introduced in
calloc
. realloc
now needs to handle the case of a failingmalloc
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add 1. No can do: using uninitialised variables doesn't even compile with the current flag set. I can initialise it to nondet_bool
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2,3 are done.
@@ -11,13 +11,13 @@ typedef union | |||
typedef struct | |||
{ | |||
int Count; | |||
Union List[1]; | |||
Union List[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -1041,6 +1041,7 @@ void cbmc_parse_optionst::help() | |||
"\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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit message says "will be squashed" so presumably that should happen ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squashed.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -1041,6 +1041,8 @@ void cbmc_parse_optionst::help() | |||
"\n" | |||
"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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to #5210, should this help message move up into the "Program instrumentation options" section?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the instrumentation section + the documentation was also added.
03cff3d
to
fec2e3a
Compare
fec2e3a
to
0f2f62f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 everymalloc
call.