What is Static Analysis?

advertisement
Static Analysis, part 2
Claire Le Goues
2015 (c) C. Le Goues
1
Learning goals
• Really understand control- and data-flow
analysis.
• Receive a high-level introduction to more
formal proving tools.
• Develop evidence-based recommendations
for how to deploy analysis tools in your
project or organization.
• Explain how abstraction applies to dynamic
analysis (lightning-fast!).
2015 (c) C. Le Goues
2
Two fundamental concepts
• Abstraction
– Elide details of a specific implementation.
– Capture semantically relevant details;
ignore the rest.
• Programs as data
– Programs are just trees/graphs!
– …and CS has lots of ways to analyze
trees/graphs
2015 (c) C. Le Goues
3
What is Static Analysis?
Don’t track everything!
(That’s normal
interpretation)
Systematic examination of an abstraction
of program state space
Ensure everything is checked
in the same way
2015 (c) C. Le Goues
4
Compare to testing, inspection
• Why might it be hard to test/inspect for:
– Array bounds errors?
– Forgetting to re-enable interrupts?
– Race conditions?
2015 (c) C. Le Goues
5
Compare to testing, inspection
• Array Bounds, Interrupts
– Testing
• Errors typically on uncommon paths or uncommon input
• Difficult to exercise these paths
– Inspection
• Non-local and thus easy to miss
– Array allocation vs. index expression
– Disable interrupts vs. return statement
• Finding Race Conditions
– Testing
• Cannot force all interleavings
– Inspection
• Too many interleavings to consider
• Check rules like “lock protects x” instead
– But checking is non-local and thus easy to miss a case
2015 (c) C. Le Goues
6
Defects Static Analysis can Catch
• Defects that result from inconsistently following
simple, mechanical design rules.
–
–
–
–
Security: Buffer overruns, improperly validated input.
Memory safety: Null dereference, uninitialized data.
Resource leaks: Memory, OS resources.
API Protocols: Device drivers; real time libraries; GUI
frameworks.
– Exceptions: Arithmetic/library/user-defined
– Encapsulation: Accessing internal data, calling private
functions.
– Data races: Two threads access the same data without
synchronization
Key: check compliance to simple, mechanical design rules
2015 (c) C. Le Goues
7
The Bad News: Rice's Theorem
"Any nontrivial property about the
language recognized by a Turing
machine is undecidable.“
Henry Gordon Rice, 1953
Every static analysis is necessarily incomplete or unsound or
undecidable (or multiple of these)
2015 (c) C. Le Goues
8
Results combined
Sound Analysis
All Defects
Unsound
and
Incomplete
Analysis
Complete
Analysis
2015 (c) C. Le Goues
9
Results
Sound Analysis
Complete Analysis
What is a violation here?
Approximation of
behaviors
Actual
program
behaviors
Actual
program
behaviors
Approximation of
behaviors
What is a violation here?
2015 (c) C. Le Goues
10
Continuum of formality
•
•
•
•
•
Pattern identification (FindBugs, Lint)
Type checking
Dataflow analysis
Model checking
Formal reasoning
– Hoare logic
– Automated theorem prover
2015 (c) C. Le Goues
11
Abstract Syntax Trees
int result = 1;
int i = 2;
while (i < n) {
result *= i;
i++;
}
return result;
Program
=
result
while
…
1
<
block
i
n
…
That is what your IDE and compiler are doing
2015 (c) C. Le Goues
12
1. /* from Linux 2.3.99 drivers/block/raid5.c */
2. static struct buffer_head *
3. get_free_buffer(struct stripe_head * sh,
4.
int b_size) {
5. struct buffer_head *bh;
6. unsigned long flags;
7. save_flags(flags);
8. cli(); // disables interrupts
9. if ((bh = sh->buffer_pool) == NULL)
10.
return NULL;
11. sh->buffer_pool = bh -> b_next;
12. bh->b_size = b_size;
13. restore_flags(flags); // re-enables interrupts
14. return bh;
15.}
With thanks to Jonathan Aldrich; example from Engler et
al., Checking system rules Using System-Specific,
Programmer-Written Compiler Extensions, OSDI ‘000
2015 (c) C. Le Goues
13
1. sm check_interrupts {
2. // variables; used in patterns
3. decl { unsigned } flags;
4. // patterns specify enable/disable functions
enable  err(double enable)
5. pat enable = { sti() ; }
6.
| { restore_flags(flags); } ;
7. pat disable = { cli() ; }
is_enabled
8. //states; first state is initial
9. is_enabled : disable  is_disabled
disable
enable
10.
| enable  { err(“double enable”); }
11.;
disable  err(double disable)
12. is_disabled : enable  is_enabled
13.
| disable  { err(“double disable”); }
14.//special pattern that matches when
is_disabled
15.// end of path is reached in this state
16.
| $end_of_path$ 
17.
{ err(“exiting with inter disabled!”); }
18.;
With thanks to Jonathan Aldrich; example from Engler et
end path  err(exiting with inter disabled)
19.}
al., Checking system rules Using System-Specific,
Programmer-Written Compiler Extensions, OSDI ‘000
2015 (c) C. Le Goues
14
Abstraction
(entry)
1. void foo() {
2.
…
3.
cli();
4.
if (a) {
5.
restore_flags();
6.
}
7. }
3. cli();
4. if (rv > 0)
5. restore_flags();
(exit)
2015 (c) C. Le Goues
15
Dataflow Analysis Example
• Consider the following program:
x = 10;
y = x;
z = 0;
while (y > -1) {
x = x / y;
y = y - 1;
z = 5;
}
• Use zero analysis to determine if x is ever 0
2015 (c) C. Le Goues
16
Applying Zero Analysis
x = 10
y = x
x = 10;
y = x;
z = 0;
while (y > -1) {
x = x / y;
y = y - 1;
z = 5;
}
z = 0
y > -1
x = x /
y
y = y 1
z = 5
(exit)
2015 (c) C. Le Goues
17
Applying Zero Analysis
x = 10
x:NZ
y = x
x:NZ, y:NZ
z = 0
x:NZ, y:NZ, z:Z
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:MZ
x:NZ, y:NZ, z:Z
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:MZ
x:NZ, y:NZ, z:Z
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:Z
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:MZ
x:NZ, y:MZ, z:NZ
x:NZ, y:MZ, z:NZ
x:NZ, y:MZ, z:NZ
y > -1
x = x /
y
y = y 1
z = 5
(exit)
2015 (c) C. Le Goues
18
Termination
• Analysis values will not change, no matter how many
times loop executes
– Proof: our analysis is deterministic
• We run through the loop with the current analysis values, none of
them change. Therefore, no matter how many times we run the
loop, the results will remain the same
– Therefore, we have computed the dataflow analysis results
for any number of loop iterations
Example final result: x:NZ, y:MZ, z:MZ
2015 (c) C. Le Goues
19
Abstraction at Work
• Number of possible states gigantic
– n 32 bit variables results in 232*n states
• 2(32*3) = 296
– With loops, states can change indefinitely
• Zero Analysis narrows the state space
– Zero or not zero
– 2(2*3) = 26
– When this limited space is explored, then we
are done
• Extrapolate over all loop iterations
2015 (c) C. Le Goues
20
Exercise time!
1. int foo() {
2.
Integer x = new Integer(6);
3.
Integer y = bar();
4.
int z;
5.
if (y != null)
6.
z = x.intVal() + y.intVal();
7.
else {
8.
z = x.intVal();
9.
y = x;
10.
x = null;
11.
}
12.
return z + x.intVal();
13. }
2015 (c) C. Le Goues
Are there any
possible null pointer
exceptions in this
code?
21
In graph form…
Integer x = new Integer(6);
Integer y = bar();
1.int foo() {
2.
Integer x = new Integer(6);
int z;
3.
Integer y = bar();
4.
int z;
5.
if (y != null)
if (y != null)
6.
z = x.intVal() + y.intVal();
7.
} else {
8.
z = x.intVal();
z = x.intVal();
9.
y = x;
z = x.intVal() +
y = x;
10.
x = null;
y.intVal();
x = null;
11.
}
12.
return z + x.intVal();
13.}
return z + x.intVal();
2015 (c) C. Le Goues
22
Null pointer analysis
• Track each variable in the program at all program
points.
• Abstraction:
– Program counter
– 3 states for each variable: null, not-null, and maybe-null.
• Then check if, at each dereference, the analysis has
identified whether the dereferenced variable is or
might be null.
2015 (c) C. Le Goues
23
Integer x = new Integer(6);
In graph form…
x  not-null
Integer y = bar();
1.int foo() {
x  not-null, y  maybe-null
2.
Integer x = new Integer(6);
3.
Integer y = bar();
int z;
4.
int z;
if (y != null)
5.
if (y != null)
6.
z = x.intVal() + y.intVal();
7.
} else {
x  not-null, y maybe-null
x

not-null,
y

maybe-null
8.
z = x.intVal();
z = x.intVal();
9.
y = x;
z = x.intVal() +
y = x;
10.
x = null;
y.intVal();
x = null;
11.
}
x  not-null, y  maybe-null
x  null, y  maybe-null
12.
return z + x.intVal();
13.}
Error: may have null pointer on line 12,
because x may be null!
x  maybe-null, y  maybe-null
return z + x.intVal();
2015 (c) C. Le Goues
24
Continuum of formality
•
•
•
•
•
Pattern identification (FindBugs, Lint)
Type checking
Dataflow analysis
Model checking
Formal reasoning
– Hoare logic
– Automated theorem prover
2015 (c) C. Le Goues
25
Model Checking
• Build model of a program and exhaustively
evaluate that model against a specification
– Check properties hold
• Produce counter examples
• Common form of model checking uses
temporal logic formula to describe
properties
• Especially good for finding concurrency
issues
• Subject of Thursday’s lecture!
2015 (c) C. Le Goues
26
Tools: SPIN Model Checker
• Simple Promela INterpreter
• Well established and freely available model
checker
– Model processes
– Verify linear temporal logic properties
active proctype Hello() {
printf(“Hello World\n”);
}
• We’ll spend considerable time with SPIN later
http://spinroot.com/
2015 (c) C. Le Goues
27
Tools: Microsoft SLAM
• Statically check Microsoft Windows drivers
– Drivers are difficult to test
• Uses Counter Example-Guided Abstraction Refinement
(CEGAR)
– Based on model checking
– Refines over-approximations to minimize false positives
CEGEAR process implemented in SLAM
http://research.microsoft.com/en-us/projects/slam/
2015 (c) C. Le Goues
28
Formal Reasoning: Hoare Logic
• Set of tools for reasoning about the
correctness of a computer program
– Uses pre and post conditions
• The Hoare triple: {P} S {Q}
– P and Q are predicates
– S is the program
– If we start in a state where P is true and
execute S, then S will terminate in a state
where Q is true
2015 (c) C. Le Goues
29
Hoare Triples
• {x=y} x := x + 3 { x = y + 3 }
• {x > -1} x := x * 2 + 3 { x > 1}
• { true} x := 5 { x=5}
2015 (c) C. Le Goues
30
Hoare Logic
• Hoare logic defines inference rules for program constructs
– Assignment
– Conditionals
• { P } if x > 0 then y := z else y := -z { y > 5 }
– Loops
• {P} while B do S {Q}
• Using these rules, we can reason about program
correctness if we can come up with pre- and postconditions.
• Common technology in safety-critical systems
programming, such as code written in SPARK ADA, avionics
systems, etc.
2015 (c) C. Le Goues
31
Tools: ESC/Java
• Extended Static Checking for Java
– Uses the Simplify theorem prover to evaluate
each routine in a program
– Embedded assertions/annotations
• Checker readable comments
• Based on the Java Modeling Language (JML)
/*@ requires i > 0 */
public void div(int i, int j) {
return j/i;
}
C. Flanagan, K.R.M. Leino, M. Lillibridge, G. Nelson, J. B. Saxe and R. Stata. Extended static
checking for Java
2015 (c) C. Le Goues
32
Annotation Benefits
• Annotations express design intent
– How you intended to achieve a particular
quality attribute
• e.g. never writing more than N elements to this
array
• As you add more annotations, you find
more errors
– Some annotations already built in to Java
libraries
2015 (c) C. Le Goues
33
Upshot: analysis as approximation
• Analysis must approximate in practice
– False positives: may report errors where there are really none
– False negatives: may not report errors that really exist
– All analysis tools have either false negatives or false positives
• Approximation strategy
– Find a pattern P for correct code
• which is feasible to check (analysis terminates quickly),
• covers most correct code in practice (low false positives),
• which implies no errors (no false negatives)
• Analysis can be pretty good in practice
– Many tools have low false positive/negative rates
– A sound tool has no false negatives
• Never misses an error in a category that it checks
2015 (c) C. Le Goues
34
Pseudo-summary: analysis is
attribute-Specific
• Analysis is specific to:
– A quality attribute (e.g., race condition, buffer overflow,
use after free)
– A pattern for verifying that attribute (e.g., protect each
shared piece of data with a lock, Presburger arithmetic
decision procedure for array indexes, only one variable
points to each memory location)
• Analysis is inappropriate for some attributes.
• For every technique, think about: what’s being
abstracted, what data is being lost, where the error
can come from!
• And maybe: how we can make it better?
2015 (c) C. Le Goues
35
Why do Static Analysis
2015 (c) C. Le Goues
36
Quality assurance at Microsoft
• Original process: manual code inspection
– Effective when system and team are small
– Too many paths to consider as system grew
• Early 1990s: add massive system and unit testing
– Tests took weeks to run
• Diversity of platforms and configurations
• Sheer volume of tests
– Inefficient detection of common patterns, security holes
• Non-local, intermittent, uncommon path bugs
Was treading water in Windows Vista development
• Early 2000s: add static analysis
2015 (c) C. Le Goues
37
Impact at Microsoft
• Thousands of bugs caught monthly
• Significant observed quality improvements
– e.g. buffer overruns latent in codebases
• Widespread developer acceptance
– Check-in gates
– Writing specifications
2015 (c) C. Le Goues
38
Ebay: Prior Evaluations
• Individual teams tried tools
– On snapshots
– No tool customization
– Overall negative results
– Developers were not impressed: many minor
issues (2 checkers reported half the issues, all
irrelevant for Ebay)
• Would this change when integrated into
process? i.e. incremental checking
• Which bugs to look at?
Jaspan, Ciera, I. Chen, and Anoop Sharma. "Understanding the value of program analysis tools." Companion
to the 22nd ACM SIGPLAN conference on Object-oriented programming systems and applications companion.
ACM, 2007.
2015 (c) C. Le Goues
39
Ebay: Goals
• Find defects earlier in the lifecycle
– Allow quality engineers to focus on different issues
• Find defects that are difficult to find through other
QA techniques
– security, performance, concurrency
• As early as feasible: Run on developer machines and
in nightly builds
• No resources to build own tool
– But few people for dedicated team (customization,
policies, creating project-specific analyses etc) possible
• Continuous evaluation
2015 (c) C. Le Goues
40
Ebay: Customization
• Customization dropped false positives from
50% to 10%
• Separate checkers evaluated separately
– By number of issues
– By severity as judged by developers; iteratively
with several groups
• Some low-priority checkers (e.g., dead store
to local) was assigned high priority –
performance impact important for Ebay
2015 (c) C. Le Goues
41
Ebay: Enforcement policy
• High priority: All these issues must be fixed (e.g.
null pointer exceptions)
– Potentially very costly given the huge existing code
base
• Medium priority: May not be added to the code
base. Old issues won't be fixed unless
refactored anyway (e.g., high cyclomatic
complexity)
• Low priority: At most X issues may be added
between releases (usually stylistic)
• Tossed: Turned off entirely
2015 (c) C. Le Goues
42
Ebay: Cost estimation
• Free tool
• 2 developers full time for customization
and extension
• A typical tester at ebay finds 10
bugs/week, 10% high priority
• Sample bugs found with Findbugs for a
comparison
2015 (c) C. Le Goues
43
Aside: Cost/benefit analysis
• Cost/Benefit tradeoff
– Benefit: How valuable is the bug?
• How much does it cost if not found?
• How expensive to find using testing/inspection?
– Cost: How much did the analysis cost?
• Effort spent running analysis, interpreting results – includes false
positives
• Effort spent finding remaining bugs (for unsound analysis)
• Rule of thumb
– For critical bugs that testing/inspection can’t find, a sound
analysis is worth it, as long as false positive rate is acceptable.
– For other bugs, maximize engineer productivity
2015 (c) C. Le Goues
44
Ebay: Combining tools
• Program analysis coverage
– Performance – High importance
– Security – High
– Global quality – High
– Local quality – medium
– API/framework compliance – medium
– Concurrency – low
– Style and readability – low
• Select appropriate tools and detectors
2015 (c) C. Le Goues
45
Ebay: Enforcement
• Enforcement at dev/QA handoff:
• Developers run FindBugs on desktop
• QA runs FindBugs on receipt of code,
posts results, require high-priority fixes.
2015 (c) C. Le Goues
46
Ebay: Continuous evaluation
• Gather data on detected bugs and false
positives
• Present to developers, make case for tool
2015 (c) C. Le Goues
47
Incremental introduction
• Begin with early adopters in small team
• Use these as champions in organization
• Support team: answer questions, help
with tool.
2015 (c) C. Le Goues
48
Empirical results
• Nortel study [Zheng et al. 2006]
– 3 C/C++ projects
– 3 million LOC total
– Early generation static analysis tools
• Conclusions
– Cost per fault of static analysis 61-72% compared to
inspections
– Effectively finds assignment, checking faults
– Can be used to find potential security vulnerabilities
2015 (c) C. Le Goues
49
More empirical results
• InfoSys study [Chaturvedi
2005]
– 5 projects
– Average 700 function
points each
– Compare inspection with
and without static analysis
• Conclusions
– Higher productivity
– Fewer defects
2015 (c) C. Le Goues
50
Question time!
HOW IS TEST SUITE COVERAGE
COMPUTED?
2015 (c) C. Le Goues
51
Dynamic analysis
• Learn about a program’s properties by
executing it.
• How can we learn about properties that
are more interesting than “did this test
pass”? (e.g., memory use).
• Short answer: examine program state
throughout execution by gathering
additional information.
2015 (c) C. Le Goues
52
Common dynamic analysis
•
•
•
•
•
•
Coverage
Performance
Memory usage
Security properties
Concurrency errors
Invariant detection
2015 (c) C. Le Goues
53
Collecting execution info
• Instrument at compile time
– e.g., Aspects, logging
• Run on a specialized VM, like valgrind
• Instrument or monitor at runtime
– Also requires a special VM
– E.g., VisualVM (hooks into JVM using debug
symbols to profile/monitor)
2015 (c) C. Le Goues
54
Quick note
• Some of those require a static preprocessing step, such as inserting logging
statements!
• It’s still a dynamic analysis, because you
run the program, collect the info, and
learn from that information.
2015 (c) C. Le Goues
55
Parts of a dynamic analysis.
1.
2.
3.
4.
5.
Property of interest.
Information related to property of interest.
Mechanism for collecting that information
from a program execution.
Test input data.
Mechanism for learning about the
property of interest from the information
you collected.
2015 (c) C. Le Goues
56
Abstraction
• How is abstraction relevant to static
analysis, again?
• Dynamic analysis also requires
abstraction.
• You’re still focusing on a particular
program property or type of information.
• Abstracting parts of a trace of exeuction
rather than the entire state space.
2015 (c) C. Le Goues
57
Challenges: Very input dependent
• Good if you have alots of tests! (system tests
are also best)
• Are those tests indicative of common
behavior?
– Is that what you want?
• Can also use logs from live sessions
(sometimes).
• Or specific inputs that replicate specific
defect scenarios (like memory leaks).
2015 (c) C. Le Goues
58
Challenges: Heisenbuggy behavior
• Instrumentation and monitoring can change
the behavior of a program.
– E.g., slowdown, overhead
• Important question 1: can/should you deploy
it live? Or just for debugging something
specific?
• Important question 2: will the monitoring
meaningfully change the program behavior
with respect ot the property you care about?
2015 (c) C. Le Goues
59
Too much data
• Logging events in large and/or longrunning programs (even for just one
property!) can result in HUGE amounts of
data.
• How do you process it?
– Common strategy: sampling.
2015 (c) C. Le Goues
60
Benefits over static analysis
• Precise data for a specific run.
• No false positives or negatives on a given
run.
• No confusion about which path was taken;
it’s clear where an error happened.
• Can (often) use on live code.
– Very common for security and data gathering.
2015 (c) C. Le Goues
61
Comparison
Static analysis
• Analyze code without
executing it.
• Systematically follow an
abstraction.
• Find bugs/enforce
specifications/prove
correctness.
• Often
correctness/security
related.
Dynamic analysis
• Analyze specific executions.
• Instrument program, or use
a special interpreter.
• Abstract parts of the trace.
• Find bugs/enforce stronger
specifications/debugging/pr
ofiling.
• Often
memory/performance/conc
urrency/security related.
2015 (c) C. Le Goues
62
Learning goals
• Really understand control- and data-flow
analysis.
• Receive a high-level introduction to more
formal proving tools.
• Develop evidence-based recommendations
for how to deploy analysis tools in your
project or organization.
• Explain the parts of and how abstraction
applies to dynamic analysis (lightning-fast!).
2015 (c) C. Le Goues
63
Download