Skip to content

A bug with --constant-propagator and --dump-c #7041

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

Open
rladydpf1 opened this issue Jul 28, 2022 · 19 comments
Open

A bug with --constant-propagator and --dump-c #7041

rladydpf1 opened this issue Jul 28, 2022 · 19 comments
Assignees

Comments

@rladydpf1
Copy link

rladydpf1 commented Jul 28, 2022

CBMC version: 5.43.0
Operating system: Ubuntu 20.04.4 LTS
Exact command line resulting in the issue:

goto-cc test.c -o test
goto-instrument test --constant-propagator test
goto-instrument test --dump-c test1.c

What happened instead:
test.c :

#include <assert.h>
int ab, bc;
int f(int x) {
    ab = 1 + 1 + 1 + 1;
    bc = ab + x;
    return ab + bc;
}
int main() {
    int a;
    a = -4;
    int b;
    b = nondet();
    a = f(a);
    assert(!(0 <= a && a < 5 && 0 <= b && b < 5));
}

and test1.c:

#include <assert.h>

// f
// file test.c line 5
signed int f(signed int x);
// nondet
// file test.c line 15 function main
signed int nondet(void);

// ab
// file test.c line 3
signed int ab;
// bc
// file test.c line 3
signed int bc;

// f
// file test.c line 5
signed int f(signed int x)
{
  ab = 4;
  bc = 0;
  return ab + bc;
}

// main
// file test.c line 11
signed int main()
{
  signed int a=-4;
  signed int b=nondet();
  a=f(-4);
  /* assertion !(0 <= a && a < 5 && 0 <= b && b < 5) */
  assert(1);
}

The "assert(1);" is invalid.

and another bug case with a recursive function: https://gitlab.com/sosy-lab/benchmarking/sv-benchmarks/-/blob/main/c/recursive-simple/fibo_25-1.c

goto-cc sv-benchmarks/c/recursive-simple/fibo_25-1.c -o fibo
goto-instrument fibo --constant-propagator fibo
goto-instrument fibo --dump-c fibo.c

the fibo.c:

#include <assert.h>
#include <stdlib.h>

// fibo
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 7
signed int fibo(signed int n);
// reach_error
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 4
void reach_error();

// fibo
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 7
signed int fibo(signed int n)
{
  goto __CPROVER_DUMP_L1;
  return 0;

__CPROVER_DUMP_L1:
  ;
  goto __CPROVER_DUMP_L2;
  return 1;

__CPROVER_DUMP_L2:
  ;
  signed int return_value_fibo=fibo(24);
  signed int return_value_fibo$0=fibo(n - 2);
  return return_value_fibo + return_value_fibo$0;
}

// main
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 25
signed int main(void)
{
  signed int x=25;
  signed int result;
  signed int return_value_fibo=fibo(25);
  result = return_value_fibo;
  if(result == 75025)
  {

  ERROR:
    ;
    reach_error();
    abort();
  }

  return 0;
}

// reach_error
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 4
void reach_error()
{
  /* assertion 0 */
  assert(0);
}

"signed int return_value_fibo=fibo(24);" : In this case, you shouldn't have propagate the constant.

@tautschnig
Copy link
Collaborator

My hunch is that we’re missing return-value removal before doing constant propagation.

@martin-cs
Copy link
Collaborator

Strong suggestion @tautschnig , I would not be at all surprised if that is the case.

@rladydpf1 please could you try two options, each instead of using goto-instrument --constant-propagator:
A. goto-analyzer test --simplify test1 --constants
B. goto-analyzer test --simplify test1 --vsd --vsd-value constants

I am pretty sure they handle return-value removal correctly so if A works, it was that. If A fails but B works then it is a problem with the constants domain.

@rladydpf1
Copy link
Author

rladydpf1 commented Jul 30, 2022

goto-analyzer test --simplify test1 --constants
goto-instrument test1 --dump-c test1.c

It does work,
test1.c : (Case A)

signed int f(signed int x)
{
  ab = 4;
  bc = 0;
  return 4;
}

signed int main()
{
  signed int a=-4;
  signed int b;
  nondet();
  b = nondet_signed_int();
  f(-4);
  a = 4;
  /* assertion !(0 <= a && a < 5 && 0 <= b && b < 5) */
  assert(!(b >= 0) || b >= 5);
}

however, fibo_25-1.c has stll the same error.

goto-cc sv-benchmarks/c/recursive-simple/fibo_25-1.c fibo
goto-analyzer test --simplify fibo --constants
goto-instrument fibo --dump-c fibo.c

fibo.c : (Case A)

signed int fibo(signed int n)
{
  signed int return_value_fibo=fibo(24);
  signed int return_value_fibo$0=fibo(n + -2);
  return return_value_fibo + return_value_fibo$0;
}

// main
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 25
signed int main(void)
{
  signed int x=25;
  signed int result;
  signed int return_value_fibo=fibo(25);
  result = return_value_fibo;
  if(result == 75025)
  {

  ERROR:
    ;
    reach_error();
    __CPROVER_assume(0);
  }

  return 0;
}

// reach_error
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 4
void reach_error()
{
  /* assertion 0 */
  assert(0);
}

The case B does work:

goto-cc sv-benchmarks/c/recursive-simple/fibo_25-1.c fibo
goto-analyzer fibo --simplify fibo --vsd --vsd-values constants
goto-instrument fibo --dump-c fibo.c

fibo.c : (Case B)

signed int fibo(signed int n)
{
  if(!(n >= 1))
    return 0;

  else
    if(n == 1)
      return 1;

    else
    {
      signed int return_value_fibo=fibo(n - 1);
      signed int return_value_fibo$0=fibo(n - 2);
      return return_value_fibo + return_value_fibo$0;
    }
}

// main
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 25
signed int main(void)
{
  signed int x=25;
  signed int result;
  signed int return_value_fibo=fibo(25);
  result = return_value_fibo;
  if(result == 75025)
  {

  ERROR:
    ;
    reach_error();
    __CPROVER_assume(0);
  }

  return 0;
}

// reach_error
// file data/cbmc/sv-benchmarks/c/recursive-simple/fibo_25-1.c line 4
void reach_error()
{
  /* assertion 0 */
  assert(0);
}

@martin-cs
Copy link
Collaborator

@rladydpf1 thanks for testing this out. If A works but goto-instrument doesn't then it is probably an issues like @tautschnig suggests. I have an in-progress patch set that deprecates the functionality in goto-instrument in favour of goto-analyze. Would using A or (probably better) B work for you?

As regards the recursive example, there is a bug in how our abstract interpreter handles recursive programs. We are working on a fix. If you have urgent use-cases then it would be good to know as it would increase the priority.

@jimgrundy jimgrundy added aws Bugs or features of importance to AWS CBMC users aws-high soundness Soundness bug? Review and add "aws" if it is, or remove "soundness" if it isn't. labels Aug 10, 2022
@jimgrundy
Copy link
Collaborator

Isn't this a soundness issue? (Adding soundness label).

@jimgrundy
Copy link
Collaborator

Confirmed that this is an issue in the current version 5.63

@martin-cs
Copy link
Collaborator

@jimgrundy It is certainly a "this can trash your program and give you wrong results" bugs.

@rladydpf1 does the workaround work for you? How urgent are the recursive examples?

@thomasspriggs
Copy link
Contributor

I have raised this PR to handle the initial issue with remove returns - #7105

However I notice the doxygen for this particular constant propagator describes it as "A simple, unsound constant propagator." - https://github.com/diffblue/cbmc/blob/develop/src/analyses/constant_propagator.h#L12
Is this an indication that this constant propagator should not be used if "soundness" is of concern, even after the bug with recursion is addressed?

@martin-cs
Copy link
Collaborator

@thomasspriggs Yes. This is why I suggested using goto-analyzer specifically with --vsd --vsd-value constants which should be (fixable to be) sound.

@thomasspriggs
Copy link
Contributor

@thomasspriggs Yes. This is why I suggested using goto-analyzer specifically with --vsd --vsd-value constants which should be (fixable to be) sound.

Ah! Thank you for the explanation. I hadn't previously understood that your suggested alternate command line was using entirely separate code to do the constant propagation. I have a couple of further followup questions -

  1. Is there a reason why we shouldn't add a deprecation / unsoundness warning to goto-instrument --constant-propagator today if there is a plan to replace it?
  2. Would it be reasonable to (temporarily) add a filter to these passes with recursion issues such that functions which are part of recursive call chains are not updated in order to make this sound? Or would that in itself be unsound or likely to be more involved than just fixing the issue with recursion?

@martin-cs
Copy link
Collaborator

My apologies for not being clearer!

  1. TBH I have two half-completed PRs which will simply remove it and give a warning with the new suggested command-line.
  2. The recursion issue is A Pain. As it can affect the values that are returned from / modified by recursive functions it is not clear that workarounds will be less work than fixing it.

@jimgrundy
Copy link
Collaborator

Can we at least drive this as far as giving people a stern warning (and perhaps the recommendation of what to do instead). Then we could drop the "soundness" tag as our users were appropriately warned.

@thomasspriggs
Copy link
Contributor

I have raised a PR solely to add the warning. I haven't included information in the warning about alternatives because (A) Symex already performs its own constant propagation by default and (B) Martin's suggestion of using goto-analyzer test --simplify test1 --vsd --vsd-value constants also needs fixing for the recursive case.

@martin-cs
Copy link
Collaborator

#7120 also resolves this problem by removing the functionality completely.

@martin-cs
Copy link
Collaborator

@thomasspriggs please forgive me if I am telling you things you already know but both the constant propagation and --vsd --vsd-value constants will be broken in some recursive cases because the issue is in common code. VSD should be strictly less broken than the constant propagator.

@thomasspriggs
Copy link
Contributor

@thomasspriggs please forgive me if I am telling you things you already know but both the constant propagation and --vsd --vsd-value constants will be broken in some recursive cases because the issue is in common code. VSD should be strictly less broken than the constant propagator.

That was also my understanding. I am happy to have confirmation that our understandings match.

I have yet to work on the variable sensitivity domain code (or the abstract interpreter). However I am interested in learning, so that I can help maintain it, given that it is merged into the CBMC repository. My intuition is that back edges of loops and recursive functions calls will represent similar challenges, but that one may work while the other does not due to implementation differences.

@martin-cs
Copy link
Collaborator

AI/VSD : I will be doing an onboarding session soon-ish for one of our new recruits, will be in person but have an online "you are welcome to join in", drop me an e-mail if you want to be on the invite list.

Loops/Recursion : yes, at some formal level a loop is just a degenerate case of a recursive function, so, yes they are conceptually the same problem. However at the level that the abstract interpreter is working the differences in how they work and things like "how many back-edges do they have" and "how hard is it to recognise a back edge" matter. The recursion bug is a problem with the algorithm we have and that it can handle (probably most) loops but isn't quite complete in the case of recursion. I have been through all of the obvious fixes. They are all either incomplete or very costly. We fundamentally have to change how the abstractions are computed. I think I know how but it is a non-trivial amount of work, esp. to do in a backwards compatabile (w.r.t. to performance and accuracy) way.

@jimgrundy
Copy link
Collaborator

If you have room for more folks to join in do let us know and maybe some folks might travel from further afield to join.

thomasspriggs added a commit to thomasspriggs/cbmc that referenced this issue Sep 28, 2022
At the time of adding this commit, this simplification is known to
return unsound/erroneous results for input programs featuring recursion.
This warning should be remove once the known issues have been fixed. See
diffblue#7041
thomasspriggs added a commit to thomasspriggs/cbmc that referenced this issue Sep 28, 2022
At the time of adding this commit, this simplification is known to
return unsound/erroneous results for input programs featuring recursion.
This warning should be remove once the known issues have been fixed. See
diffblue#7041
@thomasspriggs
Copy link
Contributor

Can we at least drive this as far as giving people a stern warning (and perhaps the recommendation of what to do instead). Then we could drop the "soundness" tag as our users were appropriately warned.

@jimgrundy The PR adding the soundness warning is now merged.

@TGWDB TGWDB removed the soundness Soundness bug? Review and add "aws" if it is, or remove "soundness" if it isn't. label Oct 6, 2022
@tautschnig tautschnig assigned martin-cs and unassigned tautschnig Oct 8, 2022
@feliperodri feliperodri removed aws Bugs or features of importance to AWS CBMC users aws-medium labels Feb 27, 2023
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

No branches or pull requests

7 participants