the penultimate challenge: bug report construction in the ...the penultimate challenge: bug report...
TRANSCRIPT
The Penultimate Challenge:Bug report construction in the Clang Static Analyzer
Kristóf [email protected]
Eötvös Loránd University, BudapestEricsson Hungary
2019. oct. 22.
2/38
Clear, precise bug reports are important
One of the main selling points of Clang back in the dayNot only wording, it requires a good infrastructureTools without it are miserable to use
3/38
Agenda
Path-sensitive analysis in the Clang Static AnalyzerCurrent state of bug report constructionDifficulties, current state of research, future work
4/38
Path-sensitive analysis in the Clang Static Analyzer
The Clang Static Analyzer
It employs a variety of techniques to analyze C, C++, ObjectiveC, ObjectiveC++code:
AST matchingCFG based analysesSymbolic execution
5/38
Exploring paths of execution
Traverse the control flow graph (CFG) of a functionOn branches, explore a path on which the condition is true, and one on whichits falseHow does this work interprocedurally?
6/38
Exploring paths of execution
Traverse the control flow graph (CFG) of a functionOn branches, explore a path on which the condition is true, and one on whichits falseHow does this work interprocedurally? Inlining!
6/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
7/38
[B5 (ENTRY)][B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag == 1;x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag == 1;x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag == 1;x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)][B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)][B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
flag == 0;x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
flag == 0;x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
flag == 0;x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)][B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)][B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
flag ∈ (−∞, ∞);x == nullptr;
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞);x == nullptr;dereference of x!
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
8/38
The ExplodedGraph
Contains everything the analyzer learned during symbolic executionAll explored paths of executionEvery symbolic value in every program state
9/38
[B5 (ENTRY)][B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)][B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)][B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)][B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)][B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)][B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)][B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)][B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)][B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptr
10/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)][B0 (EXIT)]
main:
[B1]flag = coin();
[B2 (ENTRY)]
[B0 (EXIT)]
foo:
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptrflag = 0
x = nullptr
10/38
There is always more to talk about...
Branches in the ExplodedGraph may happen far more often
Representation of values, regions: symbolsExplodedGraphs are usually very-very large, and contain tremendous amountof information
11/38
There is always more to talk about...
Branches in the ExplodedGraph may happen far more oftenRepresentation of values, regions: symbols
ExplodedGraphs are usually very-very large, and contain tremendous amountof information
11/38
There is always more to talk about...
Branches in the ExplodedGraph may happen far more oftenRepresentation of values, regions: symbolsExplodedGraphs are usually very-very large, and contain tremendous amountof information
11/38
Bug report construction
Processing of the ExplodedGraph
Bugs are represented with error nodesThe graph may contain several of them
The goal is to explain the path to these nodesFor each node, construct the shortest path from the root to the error nodeThis is called a bug path
12/38
Processing of the ExplodedGraph
Bugs are represented with error nodesThe graph may contain several of themThe goal is to explain the path to these nodes
For each node, construct the shortest path from the root to the error nodeThis is called a bug path
12/38
Processing of the ExplodedGraph
Bugs are represented with error nodesThe graph may contain several of themThe goal is to explain the path to these nodesFor each node, construct the shortest path from the root to the error nodeThis is called a bug path
12/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptrflag = 0
x = nullptr
13/38
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
(after the call to foo)flag ∈ (−∞, ∞)
x = (heap allocated object)*x = undefined
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag ∈ (−∞, 0) ∪ (0, ∞)x = (heap allocated object)
dereference of x!*x = 5
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = (heap allocated object)
*x = undefined
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 0x = nullptrflag = 0
x = nullptr
13/38
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
14/38
The ideal bug report
The goal is to generate a bug report from the bug path that iscomplete: contains every information necessary to understand how the bugoccuredminimal: contains no unnecessary information
15/38
Techniques used by the analyzer
2 techniques:
BugReporterVisitorsInterestingness propagation
Visit the nodes of the bugpath from the error node to the root
16/38
Techniques used by the analyzer
2 techniques:BugReporterVisitorsInterestingness propagation
Visit the nodes of the bugpath from the error node to the root
16/38
Techniques used by the analyzer
2 techniques:BugReporterVisitorsInterestingness propagation
Visit the nodes of the bugpath from the error node to the root
16/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
17/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<warning msg>
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<warning msg>
17/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 4>
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 4>
17/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 3>
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 3>
17/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 2>flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 2>17/38
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 1>
flag = 1x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
<diagnostic msg 1>
17/38
BugReporterVisitors
An arbitrary number of visitors can be registered
Their visitNode() is called on each node visitVisitors may create diagnostic messages about the node they are currentlyvisitingDespite the misleading name, they are more like callbacks than visitors
18/38
BugReporterVisitors
An arbitrary number of visitors can be registeredTheir visitNode() is called on each node visit
Visitors may create diagnostic messages about the node they are currentlyvisitingDespite the misleading name, they are more like callbacks than visitors
18/38
BugReporterVisitors
An arbitrary number of visitors can be registeredTheir visitNode() is called on each node visitVisitors may create diagnostic messages about the node they are currentlyvisiting
Despite the misleading name, they are more like callbacks than visitors
18/38
BugReporterVisitors
An arbitrary number of visitors can be registeredTheir visitNode() is called on each node visitVisitors may create diagnostic messages about the node they are currentlyvisitingDespite the misleading name, they are more like callbacks than visitors
18/38
Visitors
ConditionBRVisitor: Describes conditions of if branches, loops, conditionaloperators etc.
FindLastStoreBRVisitor: Finds the last store to a given variableTrackControlDependencyCondBRVisitor
19/38
Visitors
ConditionBRVisitor: Describes conditions of if branches, loops, conditionaloperators etc.FindLastStoreBRVisitor: Finds the last store to a given variable
TrackControlDependencyCondBRVisitor
19/38
Visitors
ConditionBRVisitor: Describes conditions of if branches, loops, conditionaloperators etc.FindLastStoreBRVisitor: Finds the last store to a given variableTrackControlDependencyCondBRVisitor
19/38
TrackControlDependencyCondBRVisitor
Most recent addition, available in Clang 10.0.0GSoC’19 project mentored by Artem Dergachev, Gábor Horváth and ÁdámBaloghhttps://szelethus.github.io/gsoc2019/
Calculates control dependencies to points of interestTells the analyzer to explain the conditions of control dependency blocks
20/38
TrackControlDependencyCondBRVisitor
Most recent addition, available in Clang 10.0.0GSoC’19 project mentored by Artem Dergachev, Gábor Horváth and ÁdámBaloghhttps://szelethus.github.io/gsoc2019/Calculates control dependencies to points of interest
Tells the analyzer to explain the conditions of control dependency blocks
20/38
TrackControlDependencyCondBRVisitor
Most recent addition, available in Clang 10.0.0GSoC’19 project mentored by Artem Dergachev, Gábor Horváth and ÁdámBaloghhttps://szelethus.github.io/gsoc2019/Calculates control dependencies to points of interestTells the analyzer to explain the conditions of control dependency blocks
20/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)][B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)][B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
21/38
Interestingness propagation
During analysis, some symbolic regions or values may have been marked as”interesting”.
During bug report construction, propagate interestingness to entities thatinteract with an interesting entityNodes in the bug path that do not desribe an interesting entity are pruned
22/38
Interestingness propagation
During analysis, some symbolic regions or values may have been marked as”interesting”.During bug report construction, propagate interestingness to entities thatinteract with an interesting entity
Nodes in the bug path that do not desribe an interesting entity are pruned
22/38
Interestingness propagation
During analysis, some symbolic regions or values may have been marked as”interesting”.During bug report construction, propagate interestingness to entities thatinteract with an interesting entityNodes in the bug path that do not desribe an interesting entity are pruned
22/38
Combining Visitors and Interestingness
Expression value tracking!
Mark the expression as interestingRegister visitors to describe events related to it
FindLastStoreBRVisitorTrackControlDependencyCondBRVisitorReturnVisitorUndefOrNullArgVisitoretc...
TrackControlDependencyCondBRVisitor does that as well
23/38
Combining Visitors and Interestingness
Expression value tracking!Mark the expression as interesting
Register visitors to describe events related to itFindLastStoreBRVisitorTrackControlDependencyCondBRVisitorReturnVisitorUndefOrNullArgVisitoretc...
TrackControlDependencyCondBRVisitor does that as well
23/38
Combining Visitors and Interestingness
Expression value tracking!Mark the expression as interestingRegister visitors to describe events related to it
FindLastStoreBRVisitorTrackControlDependencyCondBRVisitorReturnVisitorUndefOrNullArgVisitoretc...
TrackControlDependencyCondBRVisitor does that as well
23/38
Combining Visitors and Interestingness
Expression value tracking!Mark the expression as interestingRegister visitors to describe events related to it
FindLastStoreBRVisitorTrackControlDependencyCondBRVisitorReturnVisitorUndefOrNullArgVisitoretc...
TrackControlDependencyCondBRVisitor does that as well
23/38
flag = 1x = nullptrflag = 1
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
(after the call to foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
24/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Stage 1: Visitor notes
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x}
The checker tracks x’s value
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x}
The checker tracks x’s value
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x}
ConditionBRVisitor: As-suming ’flag’ is not equal to0
note: Assuming flag is true
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x}
ConditionBRVisitor: As-suming ’flag’ is not equal to0
note: Assuming flag is true
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
TrackControlDependencyCond-BRVisitor tracks flag
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
TrackControlDependencyCond-BRVisitor tracks flag
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
FindLastStoreBRVisitor:Value assigned to ’flag’
note: flag is assigned a value
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
FindLastStoreBRVisitor:Value assigned to ’flag’
note: flag is assigned a value
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
ConditionBRVisitor: As-suming ’flag’ is 0
note: Assuming flag is false
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
ConditionBRVisitor: As-suming ’flag’ is 0
note: Assuming flag is false
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
FindLastStoreBRVisitor isalready satisfied, no notes
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
FindLastStoreBRVisitor isalready satisfied, no notes
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is falseflag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
FindLastStoreBRVisitor:’x’ initialized to null pointervalue
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
Tracked variables: {x, flag} note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
FindLastStoreBRVisitor:’x’ initialized to null pointervalue
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
Stage 2: Non-visitor notes
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
The warning message is sup-plied by the checker
warning: Nullptr dereference
note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
The warning message is sup-plied by the checker
warning: Nullptr dereference
note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
Returning from ’foo’
note: Returning from foo
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
Returning from ’foo’
note: Returning from foo
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
Entering call from ’main’
note: Entered function from main
note: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
Entering call from ’main’
note: Entered function from main
note: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
Calling ’foo’
note: Calling foonote: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
Calling ’foo’
note: Calling foonote: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
Returning from ’foo’ note: Returning from foo
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
Returning from ’foo’ note: Returning from foo
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from fooEntering call from ’main’
note: Entered function from main
note: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from fooEntering call from ’main’
note: Entered function from main
note: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
Calling ’foo’
note: Calling foonote: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
Calling ’foo’
note: Calling foonote: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
note: Calling foonote: x initialized to nullptr
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
note: Calling foonote: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
note: Calling foonote: x initialized to nullptr
Stage 3: Pruning
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: Returning from foo
note: Entered function from main
note: Calling foonote: x initialized to nullptr
25/38
flag = 1x = nullptr
(calling foo)(calling foo)
(entering foo)flag = 1
x = nullptr
(entering foo)flag = 1
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag = 0x = nullptrflag = 0
x = nullptr
(calling foo)(calling foo)
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
(entering foo)flag ∈ (−∞, 0) ∪ (0, ∞)
x = nullptr
flag ∈ (−∞, ∞)x = nullptr
flag ∈ (−∞, ∞)x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
(returning from foo)flag ∈ (−∞, ∞)
x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!
flag ∈ (−∞, 0) ∪ (0, ∞)x = nullptr
dereference of x!warning: Nullptr dereference
note: Assuming flag is true
note: Returning from foo
note: flag is assigned a value
note: Entered function from main
note: Calling foonote: Assuming flag is false
note: x initialized to nullptr
25/38
26/38
27/38
28/38
Present problems, research
Very hard to solve problems
Relevant information isn’t found in the bug path
Ad absurdum, not even in the ExplodedGraph
29/38
Very hard to solve problems
Relevant information isn’t found in the bug pathAd absurdum, not even in the ExplodedGraph
29/38
30/38
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
31/38
0102030405060708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
31/38
0102030405060708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 printf("Nothing to see here!");14 foo();1516 if (flag)17 *x = 5;18 }
31/38
Reaching definitions analysis
An algorithm to find a set of last stores (definitions) to a variableRegard all definitions to a variable as a point of interesthttps://reviews.llvm.org/D64991
32/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
[B5 (ENTRY)][B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
[B5 (ENTRY)][B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B3]x = new int;
[B2]foo();
if (flag)
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
[B5 (ENTRY)]
[B4]int *x = 0;flag = 1;foo();
if (flag)
[B3]x = new int;
[B2]foo();
if (flag)
[B1]*x = 5[B1]*x = 5
[B0 (EXIT)]
main:
01 int flag;02 bool coin();0304 void foo() {05 flag = coin();06 }0708 int main() {09 int *x = 0;10 flag = 1;11 foo();12 if (flag)13 x = new int;14 foo();1516 if (flag)17 *x = 5;18 }
foo:
[B2 (ENTRY)]
[B1]flag = coin();
[B0 (EXIT)]
33/38
Problems with reaching definitions
Originally concieved for instructionsIncredibly complex to implement for C, C++, etc...Doesn’t argue about aliasingOnly works in a given CFG...
Using visitors, its possible to make this algorithm semi-interprocedural
34/38
Problems with reaching definitions
Originally concieved for instructionsIncredibly complex to implement for C, C++, etc...Doesn’t argue about aliasingOnly works in a given CFG...Using visitors, its possible to make this algorithm semi-interprocedural
34/38
Conclusion
Conclusion
Clear and precise bug reports are important
The analyzer users callbacks (or visitors) and interestingness propagation toconstruct path-sensitive bug reportsProblems that require arguing outside the bugpath, especially theExplodedGraph are insanely difficultThe analyzer gets better by the minute
35/38
Conclusion
Clear and precise bug reports are importantThe analyzer users callbacks (or visitors) and interestingness propagation toconstruct path-sensitive bug reports
Problems that require arguing outside the bugpath, especially theExplodedGraph are insanely difficultThe analyzer gets better by the minute
35/38
Conclusion
Clear and precise bug reports are importantThe analyzer users callbacks (or visitors) and interestingness propagation toconstruct path-sensitive bug reportsProblems that require arguing outside the bugpath, especially theExplodedGraph are insanely difficult
The analyzer gets better by the minute
35/38
Conclusion
Clear and precise bug reports are importantThe analyzer users callbacks (or visitors) and interestingness propagation toconstruct path-sensitive bug reportsProblems that require arguing outside the bugpath, especially theExplodedGraph are insanely difficultThe analyzer gets better by the minute
35/38
36/38
37/38
Questions?