No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

491 líneas
21KB

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  2. <html>
  3. <!-- Copyright (C) 1988-2020 Free Software Foundation, Inc.
  4. Permission is granted to copy, distribute and/or modify this document
  5. under the terms of the GNU Free Documentation License, Version 1.3 or
  6. any later version published by the Free Software Foundation; with the
  7. Invariant Sections being "Funding Free Software", the Front-Cover
  8. Texts being (a) (see below), and with the Back-Cover Texts being (b)
  9. (see below). A copy of the license is included in the section entitled
  10. "GNU Free Documentation License".
  11. (a) The FSF's Front-Cover Text is:
  12. A GNU Manual
  13. (b) The FSF's Back-Cover Text is:
  14. You have freedom to copy and modify this GNU Manual, like GNU
  15. software. Copies published by the Free Software Foundation raise
  16. funds for GNU development. -->
  17. <!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
  18. <head>
  19. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  20. <title>Analyzer Internals (GNU Compiler Collection (GCC) Internals)</title>
  21. <meta name="description" content="Analyzer Internals (GNU Compiler Collection (GCC) Internals)">
  22. <meta name="keywords" content="Analyzer Internals (GNU Compiler Collection (GCC) Internals)">
  23. <meta name="resource-type" content="document">
  24. <meta name="distribution" content="global">
  25. <meta name="Generator" content="makeinfo">
  26. <link href="index.html#Top" rel="start" title="Top">
  27. <link href="Option-Index.html#Option-Index" rel="index" title="Option Index">
  28. <link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
  29. <link href="Static-Analyzer.html#Static-Analyzer" rel="up" title="Static Analyzer">
  30. <link href="Debugging-the-Analyzer.html#Debugging-the-Analyzer" rel="next" title="Debugging the Analyzer">
  31. <link href="Static-Analyzer.html#Static-Analyzer" rel="prev" title="Static Analyzer">
  32. <style type="text/css">
  33. <!--
  34. a.summary-letter {text-decoration: none}
  35. blockquote.indentedblock {margin-right: 0em}
  36. blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
  37. blockquote.smallquotation {font-size: smaller}
  38. div.display {margin-left: 3.2em}
  39. div.example {margin-left: 3.2em}
  40. div.lisp {margin-left: 3.2em}
  41. div.smalldisplay {margin-left: 3.2em}
  42. div.smallexample {margin-left: 3.2em}
  43. div.smalllisp {margin-left: 3.2em}
  44. kbd {font-style: oblique}
  45. pre.display {font-family: inherit}
  46. pre.format {font-family: inherit}
  47. pre.menu-comment {font-family: serif}
  48. pre.menu-preformatted {font-family: serif}
  49. pre.smalldisplay {font-family: inherit; font-size: smaller}
  50. pre.smallexample {font-size: smaller}
  51. pre.smallformat {font-family: inherit; font-size: smaller}
  52. pre.smalllisp {font-size: smaller}
  53. span.nolinebreak {white-space: nowrap}
  54. span.roman {font-family: initial; font-weight: normal}
  55. span.sansserif {font-family: sans-serif; font-weight: normal}
  56. ul.no-bullet {list-style: none}
  57. -->
  58. </style>
  59. </head>
  60. <body lang="en">
  61. <a name="Analyzer-Internals"></a>
  62. <div class="header">
  63. <p>
  64. Next: <a href="Debugging-the-Analyzer.html#Debugging-the-Analyzer" accesskey="n" rel="next">Debugging the Analyzer</a>, Up: <a href="Static-Analyzer.html#Static-Analyzer" accesskey="u" rel="up">Static Analyzer</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Option-Index.html#Option-Index" title="Index" rel="index">Index</a>]</p>
  65. </div>
  66. <hr>
  67. <a name="Analyzer-Internals-1"></a>
  68. <h3 class="section">27.1 Analyzer Internals</h3>
  69. <a name="index-analyzer_002c-internals"></a>
  70. <a name="index-static-analyzer_002c-internals"></a>
  71. <a name="Overview-2"></a>
  72. <h4 class="subsection">27.1.1 Overview</h4>
  73. <p>The analyzer implementation works on the gimple-SSA representation.
  74. (I chose this in the hopes of making it easy to work with LTO to
  75. do whole-program analysis).
  76. </p>
  77. <p>The implementation is read-only: it doesn&rsquo;t attempt to change anything,
  78. just emit warnings.
  79. </p>
  80. <p>The gimple representation can be seen using <samp>-fdump-ipa-analyzer</samp>.
  81. </p>
  82. <p>First, we build a <code>supergraph</code> which combines the callgraph and all
  83. of the CFGs into a single directed graph, with both interprocedural and
  84. intraprocedural edges. The nodes and edges in the supergraph are called
  85. &ldquo;supernodes&rdquo; and &ldquo;superedges&rdquo;, and often referred to in code as
  86. <code>snodes</code> and <code>sedges</code>. Basic blocks in the CFGs are split at
  87. interprocedural calls, so there can be more than one supernode per
  88. basic block. Most statements will be in just one supernode, but a call
  89. statement can appear in two supernodes: at the end of one for the call,
  90. and again at the start of another for the return.
  91. </p>
  92. <p>The supergraph can be seen using <samp>-fdump-analyzer-supergraph</samp>.
  93. </p>
  94. <p>We then build an <code>analysis_plan</code> which walks the callgraph to
  95. determine which calls might be suitable for being summarized (rather
  96. than fully explored) and thus in what order to explore the functions.
  97. </p>
  98. <p>Next is the heart of the analyzer: we use a worklist to explore state
  99. within the supergraph, building an &quot;exploded graph&quot;.
  100. Nodes in the exploded graph correspond to &lt;point,&nbsp;<!-- /@w -->state&gt; pairs, as in
  101. &quot;Precise Interprocedural Dataflow Analysis via Graph Reachability&quot;
  102. (Thomas Reps, Susan Horwitz and Mooly Sagiv).
  103. </p>
  104. <p>We reuse nodes for &lt;point, state&gt; pairs we&rsquo;ve already seen, and avoid
  105. tracking state too closely, so that (hopefully) we rapidly converge
  106. on a final exploded graph, and terminate the analysis. We also bail
  107. out if the number of exploded &lt;end-of-basic-block, state&gt; nodes gets
  108. larger than a particular multiple of the total number of basic blocks
  109. (to ensure termination in the face of pathological state-explosion
  110. cases, or bugs). We also stop exploring a point once we hit a limit
  111. of states for that point.
  112. </p>
  113. <p>We can identify problems directly when processing a &lt;point,&nbsp;<!-- /@w -->state&gt;
  114. instance. For example, if we&rsquo;re finding the successors of
  115. </p>
  116. <div class="smallexample">
  117. <pre class="smallexample"> &lt;point: before-stmt: &quot;free (ptr);&quot;,
  118. state: {&quot;ptr&quot;: freed}&gt;
  119. </pre></div>
  120. <p>then we can detect a double-free of &quot;ptr&quot;. We can then emit a path
  121. to reach the problem by finding the simplest route through the graph.
  122. </p>
  123. <p>Program points in the analysis are much more fine-grained than in the
  124. CFG and supergraph, with points (and thus potentially exploded nodes)
  125. for various events, including before individual statements.
  126. By default the exploded graph merges multiple consecutive statements
  127. in a supernode into one exploded edge to minimize the size of the
  128. exploded graph. This can be suppressed via
  129. <samp>-fanalyzer-fine-grained</samp>.
  130. The fine-grained approach seems to make things simpler and more debuggable
  131. that other approaches I tried, in that each point is responsible for one
  132. thing.
  133. </p>
  134. <p>Program points in the analysis also have a &quot;call string&quot; identifying the
  135. stack of callsites below them, so that paths in the exploded graph
  136. correspond to interprocedurally valid paths: we always return to the
  137. correct call site, propagating state information accordingly.
  138. We avoid infinite recursion by stopping the analysis if a callsite
  139. appears more than <code>analyzer-max-recursion-depth</code> in a callstring
  140. (defaulting to 2).
  141. </p>
  142. <a name="Graphs"></a>
  143. <h4 class="subsection">27.1.2 Graphs</h4>
  144. <p>Nodes and edges in the exploded graph are called &ldquo;exploded nodes&rdquo; and
  145. &ldquo;exploded edges&rdquo; and often referred to in the code as
  146. <code>enodes</code> and <code>eedges</code> (especially when distinguishing them
  147. from the <code>snodes</code> and <code>sedges</code> in the supergraph).
  148. </p>
  149. <p>Each graph numbers its nodes, giving unique identifiers - supernodes
  150. are referred to throughout dumps in the form &lsquo;<samp>SN': <var>index</var></samp>&rsquo; and
  151. exploded nodes in the form &lsquo;<samp>EN: <var>index</var></samp>&rsquo; (e.g. &lsquo;<samp>SN: 2</samp>&rsquo; and
  152. &lsquo;<samp>EN:29</samp>&rsquo;).
  153. </p>
  154. <p>The supergraph can be seen using <samp>-fdump-analyzer-supergraph-graph</samp>.
  155. </p>
  156. <p>The exploded graph can be seen using <samp>-fdump-analyzer-exploded-graph</samp>
  157. and other dump options. Exploded nodes are color-coded in the .dot output
  158. based on state-machine states to make it easier to see state changes at
  159. a glance.
  160. </p>
  161. <a name="State-Tracking"></a>
  162. <h4 class="subsection">27.1.3 State Tracking</h4>
  163. <p>There&rsquo;s a tension between:
  164. </p><ul>
  165. <li> precision of analysis in the straight-line case, vs
  166. </li><li> exponential blow-up in the face of control flow.
  167. </li></ul>
  168. <p>For example, in general, given this CFG:
  169. </p>
  170. <div class="smallexample">
  171. <pre class="smallexample"> A
  172. / \
  173. B C
  174. \ /
  175. D
  176. / \
  177. E F
  178. \ /
  179. G
  180. </pre></div>
  181. <p>we want to avoid differences in state-tracking in B and C from
  182. leading to blow-up. If we don&rsquo;t prevent state blowup, we end up
  183. with exponential growth of the exploded graph like this:
  184. </p>
  185. <div class="smallexample">
  186. <pre class="smallexample">
  187. 1:A
  188. / \
  189. / \
  190. / \
  191. 2:B 3:C
  192. | |
  193. 4:D 5:D (2 exploded nodes for D)
  194. / \ / \
  195. 6:E 7:F 8:E 9:F
  196. | | | |
  197. 10:G 11:G 12:G 13:G (4 exploded nodes for G)
  198. </pre></div>
  199. <p>Similar issues arise with loops.
  200. </p>
  201. <p>To prevent this, we follow various approaches:
  202. </p>
  203. <ol type="a" start="1">
  204. <li> state pruning: which tries to discard state that won&rsquo;t be relevant
  205. later on withing the function.
  206. This can be disabled via <samp>-fno-analyzer-state-purge</samp>.
  207. </li><li> state merging. We can try to find the commonality between two
  208. program_state instances to make a third, simpler program_state.
  209. We have two strategies here:
  210. <ol>
  211. <li> the worklist keeps new nodes for the same program_point together,
  212. and tries to merge them before processing, and thus before they have
  213. successors. Hence, in the above, the two nodes for D (4 and 5) reach
  214. the front of the worklist together, and we create a node for D with
  215. the merger of the incoming states.
  216. </li><li> try merging with the state of existing enodes for the program_point
  217. (which may have already been explored). There will be duplication,
  218. but only one set of duplication; subsequent duplicates are more likely
  219. to hit the cache. In particular, (hopefully) all merger chains are
  220. finite, and so we guarantee termination.
  221. This is intended to help with loops: we ought to explore the first
  222. iteration, and then have a &quot;subsequent iterations&quot; exploration,
  223. which uses a state merged from that of the first, to be more abstract.
  224. </li></ol>
  225. <p>We avoid merging pairs of states that have state-machine differences,
  226. as these are the kinds of differences that are likely to be most
  227. interesting. So, for example, given:
  228. </p>
  229. <div class="smallexample">
  230. <pre class="smallexample"> if (condition)
  231. ptr = malloc (size);
  232. else
  233. ptr = local_buf;
  234. .... do things with 'ptr'
  235. if (condition)
  236. free (ptr);
  237. ...etc
  238. </pre></div>
  239. <p>then we end up with an exploded graph that looks like this:
  240. </p>
  241. <div class="smallexample">
  242. <pre class="smallexample">
  243. if (condition)
  244. / T \ F
  245. --------- ----------
  246. / \
  247. ptr = malloc (size) ptr = local_buf
  248. | |
  249. copy of copy of
  250. &quot;do things with 'ptr'&quot; &quot;do things with 'ptr'&quot;
  251. with ptr: heap-allocated with ptr: stack-allocated
  252. | |
  253. if (condition) if (condition)
  254. | known to be T | known to be F
  255. free (ptr); |
  256. \ /
  257. -----------------------------
  258. | ('ptr' is pruned, so states can be merged)
  259. etc
  260. </pre></div>
  261. <p>where some duplication has occurred, but only for the places where the
  262. the different paths are worth exploringly separately.
  263. </p>
  264. <p>Merging can be disabled via <samp>-fno-analyzer-state-merge</samp>.
  265. </p></li></ol>
  266. <a name="Region-Model"></a>
  267. <h4 class="subsection">27.1.4 Region Model</h4>
  268. <p>Part of the state stored at a <code>exploded_node</code> is a <code>region_model</code>.
  269. This is an implementation of the region-based ternary model described in
  270. <a href="http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf">&quot;A Memory Model for Static Analysis of C Programs&quot;</a>
  271. (Zhongxing Xu, Ted Kremenek, and Jian Zhang).
  272. </p>
  273. <p>A <code>region_model</code> encapsulates a representation of the state of
  274. memory, with a tree of <code>region</code> instances, along with their associated
  275. values. The representation is graph-like because values can be pointers
  276. to regions. It also stores a constraint_manager, capturing relationships
  277. between the values.
  278. </p>
  279. <p>Because each node in the <code>exploded_graph</code> has a <code>region_model</code>,
  280. and each of the latter is graph-like, the <code>exploded_graph</code> is in some
  281. ways a graph of graphs.
  282. </p>
  283. <p>Here&rsquo;s an example of printing a <code>region_model</code>, showing the ASCII-art
  284. used to visualize the region hierarchy (colorized when printing to stderr):
  285. </p>
  286. <div class="smallexample">
  287. <pre class="smallexample">(gdb) call debug (*this)
  288. r0: {kind: 'root', parent: null, sval: null}
  289. |-stack: r1: {kind: 'stack', parent: r0, sval: sv1}
  290. | |: sval: sv1: {poisoned: uninit}
  291. | |-frame for 'test': r2: {kind: 'frame', parent: r1, sval: null, map: {'ptr_3': r3}, function: 'test', depth: 0}
  292. | | `-'ptr_3': r3: {kind: 'map', parent: r2, sval: sv3, type: 'void *', map: {}}
  293. | | |: sval: sv3: {type: 'void *', unknown}
  294. | | |: type: 'void *'
  295. | `-frame for 'calls_malloc': r4: {kind: 'frame', parent: r1, sval: null, map: {'result_3': r7, '_4': r8, '&lt;anonymous&gt;': r5}, function: 'calls_malloc', depth: 1}
  296. | |-'&lt;anonymous&gt;': r5: {kind: 'map', parent: r4, sval: sv4, type: 'void *', map: {}}
  297. | | |: sval: sv4: {type: 'void *', &amp;r6}
  298. | | |: type: 'void *'
  299. | |-'result_3': r7: {kind: 'map', parent: r4, sval: sv4, type: 'void *', map: {}}
  300. | | |: sval: sv4: {type: 'void *', &amp;r6}
  301. | | |: type: 'void *'
  302. | `-'_4': r8: {kind: 'map', parent: r4, sval: sv4, type: 'void *', map: {}}
  303. | |: sval: sv4: {type: 'void *', &amp;r6}
  304. | |: type: 'void *'
  305. `-heap: r9: {kind: 'heap', parent: r0, sval: sv2}
  306. |: sval: sv2: {poisoned: uninit}
  307. `-r6: {kind: 'symbolic', parent: r9, sval: null, map: {}}
  308. svalues:
  309. sv0: {type: 'size_t', '1024'}
  310. sv1: {poisoned: uninit}
  311. sv2: {poisoned: uninit}
  312. sv3: {type: 'void *', unknown}
  313. sv4: {type: 'void *', &amp;r6}
  314. constraint manager:
  315. equiv classes:
  316. ec0: {sv0 == '1024'}
  317. ec1: {sv4}
  318. constraints:
  319. </pre></div>
  320. <p>This is the state at the point of returning from <code>calls_malloc</code> back
  321. to <code>test</code> in the following:
  322. </p>
  323. <div class="smallexample">
  324. <pre class="smallexample">void *
  325. calls_malloc (void)
  326. {
  327. void *result = malloc (1024);
  328. return result;
  329. }
  330. void test (void)
  331. {
  332. void *ptr = calls_malloc ();
  333. /* etc. */
  334. }
  335. </pre></div>
  336. <p>The &ldquo;root&rdquo; region (&ldquo;r0&rdquo;) has a &ldquo;stack&rdquo; child (&ldquo;r1&rdquo;), with two
  337. children: a frame for <code>test</code> (&ldquo;r2&rdquo;), and a frame for
  338. <code>calls_malloc</code> (&ldquo;r4&rdquo;). These frame regions have child regions for
  339. storing their local variables. For example, the return region
  340. and that of various other regions within the &ldquo;calls_malloc&rdquo; frame all have
  341. value &ldquo;sv4&rdquo;, a pointer to a heap-allocated region &ldquo;r6&rdquo;. Within the parent
  342. frame, <code>ptr_3</code> has value &ldquo;sv3&rdquo;, an unknown <code>void *</code>.
  343. </p>
  344. <a name="Analyzer-Paths"></a>
  345. <h4 class="subsection">27.1.5 Analyzer Paths</h4>
  346. <p>We need to explain to the user what the problem is, and to persuade them
  347. that there really is a problem. Hence having a <code>diagnostic_path</code>
  348. isn&rsquo;t just an incidental detail of the analyzer; it&rsquo;s required.
  349. </p>
  350. <p>Paths ought to be:
  351. </p><ul>
  352. <li> interprocedurally-valid
  353. </li><li> feasible
  354. </li></ul>
  355. <p>Without state-merging, all paths in the exploded graph are feasible
  356. (in terms of constraints being satisified).
  357. With state-merging, paths in the exploded graph can be infeasible.
  358. </p>
  359. <p>We collate warnings and only emit them for the simplest path
  360. e.g. for a bug in a utility function, with lots of routes to calling it,
  361. we only emit the simplest path (which could be intraprocedural, if
  362. it can be reproduced without a caller). We apply a check that
  363. each duplicate warning&rsquo;s shortest path is feasible, rejecting any
  364. warnings for which the shortest path is infeasible (which could lead to
  365. false negatives).
  366. </p>
  367. <p>We use the shortest feasible <code>exploded_path</code> through the
  368. <code>exploded_graph</code> (a list of <code>exploded_edge *</code>) to build a
  369. <code>diagnostic_path</code> (a list of events for the diagnostic subsystem) -
  370. specifically a <code>checker_path</code>.
  371. </p>
  372. <p>Having built the <code>checker_path</code>, we prune it to try to eliminate
  373. events that aren&rsquo;t relevant, to minimize how much the user has to read.
  374. </p>
  375. <p>After pruning, we notify each event in the path of its ID and record the
  376. IDs of interesting events, allowing for events to refer to other events
  377. in their descriptions. The <code>pending_diagnostic</code> class has various
  378. vfuncs to support emitting more precise descriptions, so that e.g.
  379. </p>
  380. <ul>
  381. <li> a deref-of-unchecked-malloc diagnostic might use:
  382. <div class="smallexample">
  383. <pre class="smallexample"> returning possibly-NULL pointer to 'make_obj' from 'allocator'
  384. </pre></div>
  385. <p>for a <code>return_event</code> to make it clearer how the unchecked value moves
  386. from callee back to caller
  387. </p></li><li> a double-free diagnostic might use:
  388. <div class="smallexample">
  389. <pre class="smallexample"> second 'free' here; first 'free' was at (3)
  390. </pre></div>
  391. <p>and a use-after-free might use
  392. </p><div class="smallexample">
  393. <pre class="smallexample"> use after 'free' here; memory was freed at (2)
  394. </pre></div>
  395. </li></ul>
  396. <p>At this point we can emit the diagnostic.
  397. </p>
  398. <a name="Limitations"></a>
  399. <h4 class="subsection">27.1.6 Limitations</h4>
  400. <ul>
  401. <li> Only for C so far
  402. </li><li> The implementation of call summaries is currently very simplistic.
  403. </li><li> Lack of function pointer analysis
  404. </li><li> The constraint-handling code assumes reflexivity in some places
  405. (that values are equal to themselves), which is not the case for NaN.
  406. As a simple workaround, constraints on floating-point values are
  407. currently ignored.
  408. </li><li> The region model code creates lots of little mutable objects at each
  409. <code>region_model</code> (and thus per <code>exploded_node</code>) rather than
  410. sharing immutable objects and having the mutable state in the
  411. <code>program_state</code> or <code>region_model</code>. The latter approach might be
  412. more efficient, and might avoid dealing with IDs rather than pointers
  413. (which requires us to impose an ordering to get meaningful equality).
  414. </li><li> The region model code doesn&rsquo;t yet support <code>memcpy</code>. At the
  415. gimple-ssa level these have been optimized to statements like this:
  416. <div class="smallexample">
  417. <pre class="smallexample">_10 = MEM &lt;long unsigned int&gt; [(char * {ref-all})&amp;c]
  418. MEM &lt;long unsigned int&gt; [(char * {ref-all})&amp;d] = _10;
  419. </pre></div>
  420. <p>Perhaps they could be supported via a new <code>compound_svalue</code> type.
  421. </p></li><li> There are various other limitations in the region model (grep for TODO/xfail
  422. in the testsuite).
  423. </li><li> The constraint_manager&rsquo;s implementation of transitivity is currently too
  424. expensive to enable by default and so must be manually enabled via
  425. <samp>-fanalyzer-transitivity</samp>).
  426. </li><li> The checkers are currently hardcoded and don&rsquo;t allow for user extensibility
  427. (e.g. adding allocate/release pairs).
  428. </li><li> Although the analyzer&rsquo;s test suite has a proof-of-concept test case for
  429. LTO, LTO support hasn&rsquo;t had extensive testing. There are various
  430. lang-specific things in the analyzer that assume C rather than LTO.
  431. For example, SSA names are printed to the user in &ldquo;raw&rdquo; form, rather
  432. than printing the underlying variable name.
  433. </li></ul>
  434. <p>Some ideas for other checkers
  435. </p><ul>
  436. <li> File-descriptor-based APIs
  437. </li><li> Linux kernel internal APIs
  438. </li><li> Signal handling
  439. </li></ul>
  440. <hr>
  441. <div class="header">
  442. <p>
  443. Next: <a href="Debugging-the-Analyzer.html#Debugging-the-Analyzer" accesskey="n" rel="next">Debugging the Analyzer</a>, Up: <a href="Static-Analyzer.html#Static-Analyzer" accesskey="u" rel="up">Static Analyzer</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Option-Index.html#Option-Index" title="Index" rel="index">Index</a>]</p>
  444. </div>
  445. </body>
  446. </html>