key idea
For a given program, it is hoped that a set of test cases can be automatically generated with high efficiency, and the test cases satisfy certain properties.
main principle
The input to the execution of a certain code region is obtained by analyzing the program. When the target code is reached, the analyzer can obtain the corresponding path constraints, and then obtain the specific value that triggers the target code through the constraint solver. And when analyzing programs, symbolic values are used as input (rather than concrete values).
execution framework
example
void foo(int a, int b){
int x = 1, y = 0;
if(a != 0){
y = 3+x;
if(b == 0)
x = 2*(a+b);
}
assert(x-y != 0);
}
Suppose you want to check whether the assert( x - y != 0 ) in this code is useful, that is, you need to judge xy ?= 0, so the path constraint at this time is x - y == 0
- a == 0 case, because a == 0, so x - y == 0 is not true, so it is UNSAT
- a != 0 case, x = 1, y = 3 + 1 = 4.
2.1 When b != 0, a != 0, b != 0, x = 1, y = 4, so x - y == 0 does not hold, so it is UNSAT.
2.2 When b == 0, x = 2a, y = 4, so x - y = 2a - 4, when a=2 is equal to 0, so it is SAT, the model is [a = 2, b = 0]
Then run the model [a = 2, b = 0] in the source program, and find that x - y == 0 indeed.