Skip to content

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

Merged
merged 4 commits into from
Jun 29, 2020

Conversation

xbauch
Copy link
Contributor

@xbauch xbauch commented Jan 7, 2020

And append an assert(false) property to every malloc call.

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@xbauch
Copy link
Contributor Author

xbauch commented Jan 7, 2020

This may fix #4605.

Copy link
Contributor

@allredj allredj left a 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-io
Copy link

codecov-io commented Jan 7, 2020

Codecov Report

Merging #5212 into develop will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #5212   +/-   ##
========================================
  Coverage    68.19%   68.19%           
========================================
  Files         1176     1176           
  Lines        97516    97520    +4     
========================================
+ Hits         66501    66504    +3     
- Misses       31015    31016    +1     
Flag Coverage Δ
#cproversmt2 42.73% <100.00%> (+<0.01%) ⬆️
#regression 65.37% <100.00%> (+<0.01%) ⬆️
#unit 32.24% <100.00%> (+<0.01%) ⬆️
Impacted Files Coverage Δ
src/cbmc/cbmc_parse_options.cpp 76.99% <ø> (ø)
src/cbmc/cbmc_parse_options.h 100.00% <ø> (ø)
src/util/config.h 72.72% <ø> (ø)
src/ansi-c/ansi_c_internal_additions.cpp 94.36% <100.00%> (+0.16%) ⬆️
src/util/config.cpp 56.81% <100.00%> (+0.15%) ⬆️
src/util/graph.h 80.26% <0.00%> (-0.44%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7405bfb...d49cfdd. Read the comment docs.

@peterschrammel peterschrammel changed the title Add malloc-may-fail option to goto-checker Add malloc-may-fail option to goto-check Jan 7, 2020
Copy link
Collaborator

@martin-cs martin-cs left a 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.

@xbauch
Copy link
Contributor Author

xbauch commented Jan 13, 2020

Why not just change the model of what malloc does?

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.

@martin-cs
Copy link
Collaborator

martin-cs commented Jan 13, 2020 via email

@xbauch xbauch force-pushed the feature/malloc-may-fail branch 2 times, most recently from d97765e to 06ead45 Compare January 24, 2020 16:29
// 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");

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;

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@xbauch xbauch force-pushed the feature/malloc-may-fail branch from 06ead45 to 993b47b Compare January 24, 2020 17:04
@xbauch xbauch marked this pull request as ready for review January 24, 2020 20:31
@xbauch xbauch force-pushed the feature/malloc-may-fail branch 3 times, most recently from 4b6ce6d to 059cbc9 Compare January 28, 2020 08:05
@@ -11,13 +11,13 @@ typedef union
typedef struct
{
int Count;
Union List[1];
Union List[0];
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Collaborator

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?

Copy link
Contributor Author

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;
}

@@ -48,6 +48,7 @@ class optionst;
"(document-subgoals)(outfile):(test-preprocessor)" \
"D:I:(c89)(c99)(c11)(cpp98)(cpp03)(cpp11)" \
"(object-bits):" \
"(malloc-may-fail)" \
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ambivalent.

@@ -1093,6 +1093,11 @@ bool configt::set(const cmdlinet &cmdline)
bv_encoding.is_object_bits_default = false;
}

if(cmdline.isset("malloc-may-fail"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ ?

Suggested change
if(cmdline.isset("malloc-may-fail"))
ansi_c.malloc_may_fail = cmdline.isset("malloc-may-fail");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@xbauch xbauch force-pushed the feature/malloc-may-fail branch 3 times, most recently from b8f6035 to 043f0e0 Compare January 29, 2020 14:20
^\[main.assertion.\d+\] line \d+ assertion p: FAILURE$
^VERIFICATION FAILED$
--
^warning: ignoring
Copy link
Contributor

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

Copy link
Collaborator

@tautschnig tautschnig left a 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.

Comment on lines 118 to 125
if(__CPROVER_malloc_may_fail && __VERIFIER_nondet___CPROVER_bool())
return (void *)0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 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.
  2. The non-determinism also needs to be introduced in calloc.
  3. realloc now needs to handle the case of a failing malloc.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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];
Copy link
Collaborator

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?

@@ -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)
Copy link
Collaborator

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 ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Squashed.

@xbauch xbauch force-pushed the feature/malloc-may-fail branch from 6ea384f to f999d2f Compare February 5, 2020 10:50
@xbauch xbauch force-pushed the feature/malloc-may-fail branch from f999d2f to 241b666 Compare February 6, 2020 08:33
@martin-cs
Copy link
Collaborator

There seems to be some duplication w.r.t. #5210 which is preferred?

@chrisr-diffblue
Copy link
Contributor

@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.

Copy link
Contributor

@chrisr-diffblue chrisr-diffblue left a 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 ;-)

@@ -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"
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@xbauch xbauch force-pushed the feature/malloc-may-fail branch 3 times, most recently from 03cff3d to fec2e3a Compare February 27, 2020 13:36
@xbauch xbauch force-pushed the feature/malloc-may-fail branch 2 times, most recently from fec2e3a to 0f2f62f Compare February 28, 2020 09:21
Copy link
Contributor

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,

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.

Copy link
Collaborator

@martin-cs martin-cs left a 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.
@danpoe danpoe force-pushed the feature/malloc-may-fail branch from bc7894a to d49cfdd Compare June 29, 2020 16:10
@danpoe danpoe merged commit 037e860 into diffblue:develop Jun 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.