]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/doc/analyzer.texi
Update copyright years.
[thirdparty/gcc.git] / gcc / doc / analyzer.texi
1 @c Copyright (C) 2019-2021 Free Software Foundation, Inc.
2 @c This is part of the GCC manual.
3 @c For copying conditions, see the file gcc.texi.
4 @c Contributed by David Malcolm <dmalcolm@redhat.com>.
5
6 @node Static Analyzer
7 @chapter Static Analyzer
8 @cindex analyzer
9 @cindex static analysis
10 @cindex static analyzer
11
12 @menu
13 * Analyzer Internals:: Analyzer Internals
14 * Debugging the Analyzer:: Useful debugging tips
15 @end menu
16
17 @node Analyzer Internals
18 @section Analyzer Internals
19 @cindex analyzer, internals
20 @cindex static analyzer, internals
21
22 @subsection Overview
23
24 The analyzer implementation works on the gimple-SSA representation.
25 (I chose this in the hopes of making it easy to work with LTO to
26 do whole-program analysis).
27
28 The implementation is read-only: it doesn't attempt to change anything,
29 just emit warnings.
30
31 The gimple representation can be seen using @option{-fdump-ipa-analyzer}.
32 @quotation Tip
33 If the analyzer ICEs before this is written out, one workaround is to use
34 @option{--param=analyzer-bb-explosion-factor=0} to force the analyzer
35 to bail out after analyzing the first basic block.
36 @end quotation
37
38 First, we build a @code{supergraph} which combines the callgraph and all
39 of the CFGs into a single directed graph, with both interprocedural and
40 intraprocedural edges. The nodes and edges in the supergraph are called
41 ``supernodes'' and ``superedges'', and often referred to in code as
42 @code{snodes} and @code{sedges}. Basic blocks in the CFGs are split at
43 interprocedural calls, so there can be more than one supernode per
44 basic block. Most statements will be in just one supernode, but a call
45 statement can appear in two supernodes: at the end of one for the call,
46 and again at the start of another for the return.
47
48 The supergraph can be seen using @option{-fdump-analyzer-supergraph}.
49
50 We then build an @code{analysis_plan} which walks the callgraph to
51 determine which calls might be suitable for being summarized (rather
52 than fully explored) and thus in what order to explore the functions.
53
54 Next is the heart of the analyzer: we use a worklist to explore state
55 within the supergraph, building an "exploded graph".
56 Nodes in the exploded graph correspond to <point,@w{ }state> pairs, as in
57 "Precise Interprocedural Dataflow Analysis via Graph Reachability"
58 (Thomas Reps, Susan Horwitz and Mooly Sagiv).
59
60 We reuse nodes for <point, state> pairs we've already seen, and avoid
61 tracking state too closely, so that (hopefully) we rapidly converge
62 on a final exploded graph, and terminate the analysis. We also bail
63 out if the number of exploded <end-of-basic-block, state> nodes gets
64 larger than a particular multiple of the total number of basic blocks
65 (to ensure termination in the face of pathological state-explosion
66 cases, or bugs). We also stop exploring a point once we hit a limit
67 of states for that point.
68
69 We can identify problems directly when processing a <point,@w{ }state>
70 instance. For example, if we're finding the successors of
71
72 @smallexample
73 <point: before-stmt: "free (ptr);",
74 state: @{"ptr": freed@}>
75 @end smallexample
76
77 then we can detect a double-free of "ptr". We can then emit a path
78 to reach the problem by finding the simplest route through the graph.
79
80 Program points in the analysis are much more fine-grained than in the
81 CFG and supergraph, with points (and thus potentially exploded nodes)
82 for various events, including before individual statements.
83 By default the exploded graph merges multiple consecutive statements
84 in a supernode into one exploded edge to minimize the size of the
85 exploded graph. This can be suppressed via
86 @option{-fanalyzer-fine-grained}.
87 The fine-grained approach seems to make things simpler and more debuggable
88 that other approaches I tried, in that each point is responsible for one
89 thing.
90
91 Program points in the analysis also have a "call string" identifying the
92 stack of callsites below them, so that paths in the exploded graph
93 correspond to interprocedurally valid paths: we always return to the
94 correct call site, propagating state information accordingly.
95 We avoid infinite recursion by stopping the analysis if a callsite
96 appears more than @code{analyzer-max-recursion-depth} in a callstring
97 (defaulting to 2).
98
99 @subsection Graphs
100
101 Nodes and edges in the exploded graph are called ``exploded nodes'' and
102 ``exploded edges'' and often referred to in the code as
103 @code{enodes} and @code{eedges} (especially when distinguishing them
104 from the @code{snodes} and @code{sedges} in the supergraph).
105
106 Each graph numbers its nodes, giving unique identifiers - supernodes
107 are referred to throughout dumps in the form @samp{SN': @var{index}} and
108 exploded nodes in the form @samp{EN: @var{index}} (e.g. @samp{SN: 2} and
109 @samp{EN:29}).
110
111 The supergraph can be seen using @option{-fdump-analyzer-supergraph-graph}.
112
113 The exploded graph can be seen using @option{-fdump-analyzer-exploded-graph}
114 and other dump options. Exploded nodes are color-coded in the .dot output
115 based on state-machine states to make it easier to see state changes at
116 a glance.
117
118 @subsection State Tracking
119
120 There's a tension between:
121 @itemize @bullet
122 @item
123 precision of analysis in the straight-line case, vs
124 @item
125 exponential blow-up in the face of control flow.
126 @end itemize
127
128 For example, in general, given this CFG:
129
130 @smallexample
131 A
132 / \
133 B C
134 \ /
135 D
136 / \
137 E F
138 \ /
139 G
140 @end smallexample
141
142 we want to avoid differences in state-tracking in B and C from
143 leading to blow-up. If we don't prevent state blowup, we end up
144 with exponential growth of the exploded graph like this:
145
146 @smallexample
147
148 1:A
149 / \
150 / \
151 / \
152 2:B 3:C
153 | |
154 4:D 5:D (2 exploded nodes for D)
155 / \ / \
156 6:E 7:F 8:E 9:F
157 | | | |
158 10:G 11:G 12:G 13:G (4 exploded nodes for G)
159
160 @end smallexample
161
162 Similar issues arise with loops.
163
164 To prevent this, we follow various approaches:
165
166 @enumerate a
167 @item
168 state pruning: which tries to discard state that won't be relevant
169 later on withing the function.
170 This can be disabled via @option{-fno-analyzer-state-purge}.
171
172 @item
173 state merging. We can try to find the commonality between two
174 program_state instances to make a third, simpler program_state.
175 We have two strategies here:
176
177 @enumerate
178 @item
179 the worklist keeps new nodes for the same program_point together,
180 and tries to merge them before processing, and thus before they have
181 successors. Hence, in the above, the two nodes for D (4 and 5) reach
182 the front of the worklist together, and we create a node for D with
183 the merger of the incoming states.
184
185 @item
186 try merging with the state of existing enodes for the program_point
187 (which may have already been explored). There will be duplication,
188 but only one set of duplication; subsequent duplicates are more likely
189 to hit the cache. In particular, (hopefully) all merger chains are
190 finite, and so we guarantee termination.
191 This is intended to help with loops: we ought to explore the first
192 iteration, and then have a "subsequent iterations" exploration,
193 which uses a state merged from that of the first, to be more abstract.
194 @end enumerate
195
196 We avoid merging pairs of states that have state-machine differences,
197 as these are the kinds of differences that are likely to be most
198 interesting. So, for example, given:
199
200 @smallexample
201 if (condition)
202 ptr = malloc (size);
203 else
204 ptr = local_buf;
205
206 .... do things with 'ptr'
207
208 if (condition)
209 free (ptr);
210
211 ...etc
212 @end smallexample
213
214 then we end up with an exploded graph that looks like this:
215
216 @smallexample
217
218 if (condition)
219 / T \ F
220 --------- ----------
221 / \
222 ptr = malloc (size) ptr = local_buf
223 | |
224 copy of copy of
225 "do things with 'ptr'" "do things with 'ptr'"
226 with ptr: heap-allocated with ptr: stack-allocated
227 | |
228 if (condition) if (condition)
229 | known to be T | known to be F
230 free (ptr); |
231 \ /
232 -----------------------------
233 | ('ptr' is pruned, so states can be merged)
234 etc
235
236 @end smallexample
237
238 where some duplication has occurred, but only for the places where the
239 the different paths are worth exploringly separately.
240
241 Merging can be disabled via @option{-fno-analyzer-state-merge}.
242 @end enumerate
243
244 @subsection Region Model
245
246 Part of the state stored at a @code{exploded_node} is a @code{region_model}.
247 This is an implementation of the region-based ternary model described in
248 @url{http://lcs.ios.ac.cn/~xzx/memmodel.pdf,
249 "A Memory Model for Static Analysis of C Programs"}
250 (Zhongxing Xu, Ted Kremenek, and Jian Zhang).
251
252 A @code{region_model} encapsulates a representation of the state of
253 memory, with a @code{store} recording a binding between @code{region}
254 instances, to @code{svalue} instances. The bindings are organized into
255 clusters, where regions accessible via well-defined pointer arithmetic
256 are in the same cluster. The representation is graph-like because values
257 can be pointers to regions. It also stores a constraint_manager,
258 capturing relationships between the values.
259
260 Because each node in the @code{exploded_graph} has a @code{region_model},
261 and each of the latter is graph-like, the @code{exploded_graph} is in some
262 ways a graph of graphs.
263
264 Here's an example of printing a @code{program_state}, showing the
265 @code{region_model} within it, along with state for the @code{malloc}
266 state machine.
267
268 @smallexample
269 (gdb) call debug (*this)
270 rmodel:
271 stack depth: 1
272 frame (index 0): frame: ‘test’@@1
273 clusters within frame: ‘test’@@1
274 cluster for: ptr_3: &HEAP_ALLOCATED_REGION(12)
275 m_called_unknown_fn: FALSE
276 constraint_manager:
277 equiv classes:
278 constraints:
279 malloc:
280 0x2e89590: &HEAP_ALLOCATED_REGION(12): unchecked ('ptr_3')
281 @end smallexample
282
283 This is the state at the point of returning from @code{calls_malloc} back
284 to @code{test} in the following:
285
286 @smallexample
287 void *
288 calls_malloc (void)
289 @{
290 void *result = malloc (1024);
291 return result;
292 @}
293
294 void test (void)
295 @{
296 void *ptr = calls_malloc ();
297 /* etc. */
298 @}
299 @end smallexample
300
301 Within the store, there is the cluster for @code{ptr_3} within the frame
302 for @code{test}, where the whole cluster is bound to a pointer value,
303 pointing at @code{HEAP_ALLOCATED_REGION(12)}. Additionally, this pointer
304 has the @code{unchecked} state for the @code{malloc} state machine
305 indicating it hasn't yet been checked against NULL since the allocation
306 call.
307
308 @subsection Analyzer Paths
309
310 We need to explain to the user what the problem is, and to persuade them
311 that there really is a problem. Hence having a @code{diagnostic_path}
312 isn't just an incidental detail of the analyzer; it's required.
313
314 Paths ought to be:
315 @itemize @bullet
316 @item
317 interprocedurally-valid
318 @item
319 feasible
320 @end itemize
321
322 Without state-merging, all paths in the exploded graph are feasible
323 (in terms of constraints being satisified).
324 With state-merging, paths in the exploded graph can be infeasible.
325
326 We collate warnings and only emit them for the simplest path
327 e.g. for a bug in a utility function, with lots of routes to calling it,
328 we only emit the simplest path (which could be intraprocedural, if
329 it can be reproduced without a caller). We apply a check that
330 each duplicate warning's shortest path is feasible, rejecting any
331 warnings for which the shortest path is infeasible (which could lead to
332 false negatives). This check can be suppressed (for debugging purposes)
333 using @option{-fno-analyzer-feasibility}.
334
335 We use the shortest feasible @code{exploded_path} through the
336 @code{exploded_graph} (a list of @code{exploded_edge *}) to build a
337 @code{diagnostic_path} (a list of events for the diagnostic subsystem) -
338 specifically a @code{checker_path}.
339
340 Having built the @code{checker_path}, we prune it to try to eliminate
341 events that aren't relevant, to minimize how much the user has to read.
342
343 After pruning, we notify each event in the path of its ID and record the
344 IDs of interesting events, allowing for events to refer to other events
345 in their descriptions. The @code{pending_diagnostic} class has various
346 vfuncs to support emitting more precise descriptions, so that e.g.
347
348 @itemize @bullet
349 @item
350 a deref-of-unchecked-malloc diagnostic might use:
351 @smallexample
352 returning possibly-NULL pointer to 'make_obj' from 'allocator'
353 @end smallexample
354 for a @code{return_event} to make it clearer how the unchecked value moves
355 from callee back to caller
356 @item
357 a double-free diagnostic might use:
358 @smallexample
359 second 'free' here; first 'free' was at (3)
360 @end smallexample
361 and a use-after-free might use
362 @smallexample
363 use after 'free' here; memory was freed at (2)
364 @end smallexample
365 @end itemize
366
367 At this point we can emit the diagnostic.
368
369 @subsection Limitations
370
371 @itemize @bullet
372 @item
373 Only for C so far
374 @item
375 The implementation of call summaries is currently very simplistic.
376 @item
377 Lack of function pointer analysis
378 @item
379 The constraint-handling code assumes reflexivity in some places
380 (that values are equal to themselves), which is not the case for NaN.
381 As a simple workaround, constraints on floating-point values are
382 currently ignored.
383 @item
384 There are various other limitations in the region model (grep for TODO/xfail
385 in the testsuite).
386 @item
387 The constraint_manager's implementation of transitivity is currently too
388 expensive to enable by default and so must be manually enabled via
389 @option{-fanalyzer-transitivity}).
390 @item
391 The checkers are currently hardcoded and don't allow for user extensibility
392 (e.g. adding allocate/release pairs).
393 @item
394 Although the analyzer's test suite has a proof-of-concept test case for
395 LTO, LTO support hasn't had extensive testing. There are various
396 lang-specific things in the analyzer that assume C rather than LTO.
397 For example, SSA names are printed to the user in ``raw'' form, rather
398 than printing the underlying variable name.
399 @end itemize
400
401 Some ideas for other checkers
402 @itemize @bullet
403 @item
404 File-descriptor-based APIs
405 @item
406 Linux kernel internal APIs
407 @item
408 Signal handling
409 @end itemize
410
411 @node Debugging the Analyzer
412 @section Debugging the Analyzer
413 @cindex analyzer, debugging
414 @cindex static analyzer, debugging
415
416 @subsection Special Functions for Debugging the Analyzer
417
418 The analyzer recognizes various special functions by name, for use
419 in debugging the analyzer. Declarations can be seen in the testsuite
420 in @file{analyzer-decls.h}. None of these functions are actually
421 implemented.
422
423 Add:
424 @smallexample
425 __analyzer_break ();
426 @end smallexample
427 to the source being analyzed to trigger a breakpoint in the analyzer when
428 that source is reached. By putting a series of these in the source, it's
429 much easier to effectively step through the program state as it's analyzed.
430
431 The analyzer handles:
432
433 @smallexample
434 __analyzer_describe (0, expr);
435 @end smallexample
436
437 by emitting a warning describing the 2nd argument (which can be of any
438 type), at a verbosity level given by the 1st argument. This is for use when
439 debugging, and may be of use in DejaGnu tests.
440
441 @smallexample
442 __analyzer_dump ();
443 @end smallexample
444
445 will dump the copious information about the analyzer's state each time it
446 reaches the call in its traversal of the source.
447
448 @smallexample
449 __analyzer_dump_path ();
450 @end smallexample
451
452 will emit a placeholder ``note'' diagnostic with a path to that call site,
453 if the analyzer finds a feasible path to it.
454
455 The builtin @code{__analyzer_dump_exploded_nodes} will emit a warning
456 after analysis containing information on all of the exploded nodes at that
457 program point:
458
459 @smallexample
460 __analyzer_dump_exploded_nodes (0);
461 @end smallexample
462
463 will output the number of ``processed'' nodes, and the IDs of
464 both ``processed'' and ``merger'' nodes, such as:
465
466 @smallexample
467 warning: 2 processed enodes: [EN: 56, EN: 58] merger(s): [EN: 54-55, EN: 57, EN: 59]
468 @end smallexample
469
470 With a non-zero argument
471
472 @smallexample
473 __analyzer_dump_exploded_nodes (1);
474 @end smallexample
475
476 it will also dump all of the states within the ``processed'' nodes.
477
478 @smallexample
479 __analyzer_dump_region_model ();
480 @end smallexample
481 will dump the region_model's state to stderr.
482
483 @smallexample
484 __analyzer_eval (expr);
485 @end smallexample
486 will emit a warning with text "TRUE", FALSE" or "UNKNOWN" based on the
487 truthfulness of the argument. This is useful for writing DejaGnu tests.
488
489
490 @subsection Other Debugging Techniques
491
492 The option @option{-fdump-analyzer-json} will dump both the supergraph
493 and the exploded graph in compressed JSON form.
494
495 One approach when tracking down where a particular bogus state is
496 introduced into the @code{exploded_graph} is to add custom code to
497 @code{program_state::validate}.