<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
The analyzer constructs only one exploded graph for every top-level
function. It's the same graph used by all checkers. This is why we
have dozens of checkers enabled simultaneously without significant
performance regressions - we are designed to scale really well in
this sense. But it also means that different checkers cannot have
different ideas of what functions they need to inline.<br>
<br>
You really do want to inline as much as possible. Even if nothing
interesting happens within the function with respect to your
checker, the analyzer will be able to model everything else
correctly, and the ultimate goal of that would be to make sure that
the execution path on which a bug is found by your checker is indeed
a valid path through the program. For instance, if the function does
not ever return null on any path, the analyzer will not proceed to
explore the path on which the return value of that function is
assumed to be null; if it did explore such path, any bugs found on
such path would immediately be classified as false positives.<br>
<br>
Still, the analyzer cannot inline everything, because sometimes the
source code of the function is not available, and in other cases it
needs to make difficult choices on whether it's worth it to inline a
huge function and make the user wait forever for the analysis to
complete, or skip the function and risk producing false positives.
And the *lack* of inlining often *does* indeed requiring a special
care on the checker side to carefully assume that the inlined
function is indeed doing something sane (that's why checkers are
subscribing for "pointer escapes" and/or "invalidations").<br>
<br>
That said, i don't think i understand your question. Controlling
inlining by the checker is definitely not possible, but what makes
you think it's necessary? Because for now no checkers have ever
needed that. Just in case - you might be thinking about a situation
like this:<br>
<br>
// calls the block and exits<br>
void call_block(^(*block)());<br>
<br>
void foo() {<br>
call_block(^{});<br>
}<br>
<br>
In this case if call_block isn't inlined, there's no way for the
analyzer to understand that the block will be called within
call_block(). Letting the checker model such call_block() call by
explaining to the analyzer core that this function does indeed call
the block is currently an open problem for the analyzer. It should
be possible, but nobody had it implemented. Some such functions are
modeled with the "body farm" technique - eg. dispatch_once(), but
there's no way of doing it in the checker.<br>
<br>
<br>
<div class="moz-cite-prefix">On 4/27/18 5:21 PM, Timothy J. Wood
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:FB77191E-9591-4BD1-8466-351A37E746C7@omnigroup.com">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<br class="">
<div><br class="">
<blockquote type="cite" class="">
<div class="">On Apr 27, 2018, at 4:03 PM, Artem Dergachev
<<a href="mailto:noqnoqneo@gmail.com" class=""
moz-do-not-send="true">noqnoqneo@gmail.com</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div class="">Yep, indeed, this interface could be improved
dramatically with a bit of work.<br class="">
<br class="">
I'm usually getting away pretty well by searching the
graph in clever manners. If your dot viewer doesn't
support text search across the graph (most don't), you
might want to convert it to .svg (eg. dot -Tsvg graph.dot
-o graph.svg) and open the svg in a web browser and then
use the find-on-page feature.<br class="">
<br class="">
</div>
</div>
</blockquote>
</div>
<div class=""><br class="">
</div>
Thanks for the hints!
<div class=""><br class="">
<div class="">I started printing the state pointers in my log
output and that’s helping match up my log messages with where
I am in the graph.</div>
<div class=""><br class="">
</div>
<div class="">One other thing that occurred to me is that some
of the large graphs I’m seeing are due to inlining across ObjC
methods:</div>
<div class=""><br class="">
</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>-
(BOOL)inner:(NSError **)outError; {…}</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>-
(BOOL)outer:(NSError **)outError; {</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>return
[self inner: outError];</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>}</div>
<div class=""><br class="">
</div>
<div class="">Here I’ll get something like:</div>
<div class=""><br class="">
</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding:
0px;" class="">
<div class="">begin function</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>begin
call</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>begin
function</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>…</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>end
function</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>end
call</div>
<div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>…</div>
<div class="">end function</div>
<div class=""><br class="">
</div>
</blockquote>
but I don’t need this sort of inlining for my checker. When
processing -outer: I can assume that the call to -inner: does
the right thing (writes to outError if its result is null, and
leaves it undefined if it is non-null), and then -inner: can be
independently checked.
<div class=""><br class="">
</div>
<div class="">But, if a method calls a block literal, I do need
to let the inner function be processed. I haven’t yet arrived
at a way using generateSink() that doesn’t just end the whole
checking pass — is there a way to conditionally stop inline
checking that I can use here?</div>
<div class=""><br class="">
</div>
<div class="">
<div class="">void
NSErrorWriteChecker::checkBeginFunction(CheckerContext
&C) const {</div>
</div>
<div class=""><br class="">
</div>
<div class="">
<div class=""> if (!C.inTopFrame()) {</div>
<div class=""> const LocationContext *LocCtxt =
C.getLocationContext();</div>
<div class=""> if
(dyn_cast<BlockDecl>(LocCtxt->getDecl()) == NULL) {</div>
<div class=""> // ???</div>
</div>
</div>
<div class=""> return;</div>
<div class=""> }</div>
<div class=""> }</div>
<div class=""><br class="">
</div>
<div class=""> …</div>
<div class="">}</div>
<div class=""><br class="">
</div>
<div class="">Thanks!</div>
<div class=""><br class="">
</div>
<div class="">
<div class="">-Tim</div>
<div class=""><br class="">
</div>
</div>
</blockquote>
<br>
</body>
</html>