smack icon indicating copy to clipboard operation
smack copied to clipboard

Is this a bug?

Open chkl opened this issue 6 years ago • 7 comments

Hello, I stumbled upon the following phenomenon: Consider this file interesting-simplified.c:

> cat interesting-simplified.c 
extern void __VERIFIER_error() __attribute__((__noreturn__));
void __VERIFIER_assert(int cond)
{
    if (!cond)
    {
    ERROR:
        __VERIFIER_error();
    }
}
int main()
{
    int i = 0;
    while (i < 100000)
    {
        i = i + 1;
    }
    __VERIFIER_assert(i != 11);
    return 0;
}

Running > CORRAL="mono /tmp/corral/bin/Release/corral.exe" smack -x=svcomp --clang-options=-m32 interesting-simplified.c results in the output:

SMACK program verifier version 1.9.0
SMACK found no errors with unroll bound 1.

Now, when I just change the assertion from i != 11 to i != 10, the output changes to:

SMACK program verifier version 1.9.0
/usr/local/share/smack/lib/smack.c(47,1): This assertion can fail
Execution trace:
    /usr/local/share/smack/lib/smack.c(1782,3): Trace: Thread=1  (CALL $initialize, CALL __SMACK_static_init, RETURN from __SMACK_static_init , CALL __SMACK_init_func_memory_model)
    /usr/local/share/smack/lib/smack.c(1782,3): Trace: Thread=1  ()
    /usr/local/share/smack/lib/smack.c(1787,1): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(13,5): Trace: Thread=1  (RETURN from __SMACK_init_func_memory_model , RETURN from $initialize )
    /database/random5_budgets/interesting-simplified-xfPVOF.c(13,5): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(13,5): Trace: Thread=1  (smack:entry:main = -4134)
    /database/random5_budgets/interesting-simplified-xfPVOF.c(13,5): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(17,5): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(17,5): Trace: Thread=1  (CALL __VERIFIER_assert)
    /database/random5_budgets/interesting-simplified-xfPVOF.c(4,10): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(4,9): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(5,5): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(7,9): Trace: Thread=1  ()
    /database/random5_budgets/interesting-simplified-xfPVOF.c(7,9): Trace: Thread=1  (CALL __VERIFIER_error)
    /usr/local/share/smack/lib/smack.c(47,3): Trace: Thread=1  ()
    /usr/local/share/smack/lib/smack.c(47,3): Trace: Thread=1  (ASSERTION FAILS assert false;
    /database/random5_budgets/interesting-simplified-xfPVOF.c(7,9): Trace: Thread=1  (RETURN from __VERIFIER_error )
    /database/random5_budgets/interesting-simplified-xfPVOF.c(17,5): Trace: Thread=1  (RETURN from __VERIFIER_assert )
    /database/random5_budgets/interesting-simplified-xfPVOF.c(17,5): Trace: Thread=1  (Done)

SMACK found an error.

To my limited understanding, smack uses bounded model checking so I would understand if in both cases it didn't reach the 100000th loop unrolling. What I don't understand is that the result depends on whether the assertion contains a 10 or an 11.

chkl avatar Jun 11 '18 06:06 chkl

There are two related things happening here.

  1. We have this hacky heuristic in SMACK that searches for large constants in SVCOMP benchmarks and replaces them with small numbers to reduce size of benchmarks. In this case, 100000 will be replaced with 10. So while (i < 100000) basically becomes while (i < 10).
  2. On top of that, LLVM does constant propagation, which greatly simplifies this code and gets rid of the loop completely. LLVM knows that i is 10 after the loop terminates, and that is how the assertion is evaluated without SMACK having to unwind the loop (since the loop is not there any more). These two things taken together result in the behavior you observed. What you discovered is a drawback of our simple size-reduction heuristics. I hope this makes sense.

zvonimir avatar Jun 12 '18 17:06 zvonimir

Thank you very much for clarifying this. I've found another "interesting" case since then. How does Smack handle (potentially) infinite loops? Consider this file:

extern void __VERIFIER_error() __attribute__((__noreturn__));
void __VERIFIER_assert(int cond)
{
    if (!cond)
    {
    ERROR:
        __VERIFIER_error();
    }
    return;
}

int main()
{
    int x = 0;
    while (1)
    {
        __VERIFIER_assert(x != 2);
        x++;
    }
    return 0;
}

Smack couldn't find an error for me in this one.

chkl avatar Jun 25 '18 11:06 chkl

When I run SMACK with --unroll=3 it finds this bug. How did you run it?

zvonimir avatar Jun 26 '18 16:06 zvonimir

I called smack using

 > CORRAL="mono /tmp/corral/bin/Release/corral.exe" smack -x=svcomp --clang-options=-m32 interesting.c

You are right, adding --unroll=3 makes smack find the error. Sorry for the confusion.

chkl avatar Jun 26 '18 17:06 chkl

I am sorry to bother. Coming back to my original post: Is there a way to disable the "hacky heuristic"?

chkl avatar Jul 11 '18 14:07 chkl

Let me implement a switch that turns it off. I'll let you know once that is done. This is also related to issue #159.

zvonimir avatar Jul 11 '18 14:07 zvonimir

That'd be great. Thank you very much.

chkl avatar Jul 11 '18 14:07 chkl