Skip to content

Stop assertion size-of-expr for pointer-checks #4936

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

Closed
wants to merge 2 commits into from

Conversation

xbauch
Copy link
Contributor

@xbauch xbauch commented Jul 22, 2019

Since these can be void-pointers. In this case we simply skip introducing the
address-check altogether. See #4930.

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

@@ -1113,7 +1113,8 @@ void goto_checkt::pointer_validity_check(
const exprt &pointer=expr.pointer();

auto size_of_expr_opt = size_of_expr(expr.type(), ns);
CHECK_RETURN(size_of_expr_opt.has_value());
if(!size_of_expr_opt.has_value())
return; // in the case of `void*`
Copy link
Contributor

@danpoe danpoe Jul 22, 2019

Choose a reason for hiding this comment

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

Shouldn't size_of_expr() also work for void pointers? In that case we should fix size_of_expr() if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But even if we implement size-of for void the result will be 0, right? I'm not sure we should build the address-check in that case.

Copy link
Contributor

@hannes-steffenhagen-diffblue hannes-steffenhagen-diffblue Jul 22, 2019

Choose a reason for hiding this comment

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

sizeof(void) is undefined in C, some compilers set it to 1 just because there's too much code out there that assumes that void* == char*. For example, gcc does this but warns against it with -Wpointer-arith (in the -Wpedantic group):

test.c:1:16: warning: invalid application of ‘sizeof’ to a void type [-Wpointer-arith]
 int x = sizeof(void);

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see. It's surprising that we get a dereference expression of a void pointer 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.

__CPROVER__start {
  char tmp;
  void *arg;
  if(NONDET(__CPROVER_bool))
    arg = NULL;

  else
  {
    arg = (void *)&tmp;
    *((void *)&tmp) = NONDET(void);
  }
  foo(arg);
}

This is what the entry-point looks like.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't address_check below with a zero-sized object still do some good?

Since these can be void-pointers. In this case we simply skip introducing the
address-check altogether.
@xbauch xbauch force-pushed the fix/void-pointer-check branch from 5ce002d to 199b231 Compare July 22, 2019 09:51
@kroening
Copy link
Member

What is the semantics of a valid void * pointer? Would that be true for a zero-sized object?

@xbauch
Copy link
Contributor Author

xbauch commented Jul 22, 2019

What is the semantics of a valid void * pointer? Would that be true for a zero-sized object?

Well if anything it should be legal to allocate memory, cast it to void*, pass to a function, which can then cast back, and access all the elements (within the allocation). That is probably not what we should allow for zero-sized objects.

for the SMT2 queries.
@codecov-io
Copy link

Codecov Report

Merging #4936 into develop will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #4936      +/-   ##
===========================================
+ Coverage    69.26%   69.26%   +<.01%     
===========================================
  Files         1307     1307              
  Lines       108087   108091       +4     
===========================================
+ Hits         74866    74872       +6     
+ Misses       33221    33219       -2
Impacted Files Coverage Δ
src/analyses/goto_check.cpp 78.96% <100%> (ø) ⬆️
src/solvers/smt2/smt2_conv.cpp 60.1% <100%> (+0.07%) ⬆️
src/solvers/flattening/boolbv_typecast.cpp 44.26% <0%> (+0.4%) ⬆️
src/util/allocate_objects.cpp 92.15% <0%> (+1.96%) ⬆️

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 1edf4d9...faf21d0. Read the comment docs.

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.

⚠️
This PR failed Diffblue compatibility checks (cbmc commit: faf21d0).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/120033995
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.

@hannes-steffenhagen-diffblue
Copy link
Contributor

The problem is that there's no "valid" semantics for what a void* points to per se - if it's "valid" it should point to a memory location we're allowed to access, but since there's no such thing as a "void object" in C we can't really tell what's supposed to be there... Now we could do some sort of abstract interpretation thingy or some such to figure out what the pointer is supposed to be dereferenced as by looking at where it's being dereferenced, the problem of course being that void* are often used for closures like this

typedef struct event event;
void register_event_handler(void *closure, void (*handler)(const event*));

so in that case, what the void* is supposed to be pointing to depends on what we set the handler to... There are lots of similar cases where we have instances of several parameters have nontrivial dependencies between each other, that was (for me) a big part of the motivation for goto-harness.

@kroening
Copy link
Member

What is the semantics of a valid void * pointer? Would that be true for a zero-sized object?

Well if anything it should be legal to allocate memory, cast it to void*, pass to a function, which can then cast back, and access all the elements (within the allocation). That is probably not what we should allow for zero-sized objects.

Note that it is valid to allocate zero bytes; so to make the first part of your statement work, the would need to make this pass for the case of a zero-sized object.

@kroening
Copy link
Member

I.e., my proposal is to treat the case of void * as "zero size", but otherwise do the same checks as they are done now. In particular, something like valid_pointer((void *)null) should fail.

@@ -1113,7 +1113,8 @@ void goto_checkt::pointer_validity_check(
const exprt &pointer=expr.pointer();

auto size_of_expr_opt = size_of_expr(expr.type(), ns);
CHECK_RETURN(size_of_expr_opt.has_value());
if(!size_of_expr_opt.has_value())
return; // in the case of `void*`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't address_check below with a zero-sized object still do some good?

else if(src_type.id() == ID_empty)
{
convert_expr(src);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This might actually fix some of the broken-smt-backend tests - would you mind testing that?

@tautschnig
Copy link
Collaborator

Closing as superseded by #5427.

@tautschnig tautschnig closed this Apr 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants