<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Aug 21, 2012, at 12:11 , Anna Zaks <<a href="mailto:ganna@apple.com">ganna@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Aug 21, 2012, at 9:04 AM, Jordan Rose wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><br>On Aug 20, 2012, at 18:47 , Jordan Rose <<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>> wrote:<br><br><blockquote type="cite">Yeah, I don't like this approach as much as I thought I would. My original reason for making a new summary out of an old one was to re-use the existing summary evaluation code. This eliminates that, and processSummaryOfInlined is crippled since it only handles StopTrackingHard and NoRetHard. And there's a lot of duplication elsewhere.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">I'd rather see this:<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"> RetainSummaryManager &Summaries = getSummaryManager(C);<br></blockquote><blockquote type="cite"> const RetainSummary *Summ = Summaries.getSummary(Call, C.getState());<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"> if (C.wasInlined && !Summ->appliesToInlined())<br></blockquote><blockquote type="cite"> return;<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"> checkSummary(*Summ, Call, C);<br></blockquote><br>Thinking about this again, this is about whether we're saying "this summary should be applied even when inlining", or "these /effects/ should be applied even when inlining". Even in the latter case I'd consider adding flags to the ArgEffects rather than adding new ArgEffect kinds, but that's an interesting distinction/decision. Obviously the latter is more flexible, but which do you think we /should/ be doing?</blockquote><div><blockquote type="cite"></blockquote></div><div><br></div><div>There are several reasons why I am not reusing the checkSummary code when processing summaries for inlined function.</div><div> - As you mentioned above, parts/individual effects in a summary are marked as "applied when inlining" not the whole summary. It makes sense to keep it this way. We make decisions on what effect each argument/return value should have separately.</div><div> - I do not perform checking for errors in processSummaryOfInlined, which is a big part of checkSummary. Even in DecRefAndStopTracking, I think it's OK to not check for use-after-free since we did inline the function and know better if it used the object or not. We should have generated the warning while analyzing the function in the former case.</div><div> - Passing an extra flag to checkSummary to act differently in the inlined case is much more messy - the only thing the functions share is the argument visitation logic. I'd rather have the argument iterator and get receiver code duplicated rather than one huge function with a lot of conditions. If you are very concerned about it, we could reduce parameter visitation to a single loop by adding another iteration APIs to EvalCall and RetainSummary, which processes both the arguments and receiver. That would make both functions (checkSummary and processSummaryOfInlined<span class="Apple-style-span" style="font-size: 11px;">)</span> much smaller. (Not sure that it's worth it though.)</div></div></div></blockquote><br></div><div>Okay, you've convinced me. I wish we didn't have to distinguish "StopTracking" and "StopTrackingHard", but unfortunately a few uses of getPersistentStopSummary() only really apply when the function is not inlined. (In particular, getSummary's switch statement for "unsupported calls". We probably can't assume anything about how most of those calls affect retain counts, except possibly blocks, unless we are able to inline.)</div><div><br></div><div>Spot comments on the original patch:</div><div><br></div><div><div>+ // In some cases, we obtain a better summary for this checker</div><div>+ // by looking at the call site than by inlining the function.</div><div>+ // Signifies that we should stop tracking the symbol even if</div><div>+ // the perfect summary is available.</div><div>+ StopTrackingHard,</div><div><br></div><div>I don't like this phrasing; the summary is not "better" at the call site, nor is inlining a "perfect summary" with respect to retain count semantics. In particular, "StopTracking" is <i>always</i> a heuristic; we are voluntarily sacrificing coverage of this symbol because we suspect our model doesn't cover this particular usage. (Remember, most uses of delegates, probably the vast majority, would still benefit from leak warnings…but we err on the side of false negatives.)</div><div><br></div><div>I don't have a good alternate phrasing in mind right now.</div><div><br></div><div><br></div><div><div>+ // The function decrements the reference count and we should </div><div>+ // stop tracking the argument.</div><div>+ DecRefAndStopTrackingHard, DecRefMsgAndStopTrackingHard</div><div><br></div><div>This comment doesn't explain anything, IMHO; if anything it is <i>less</i> explicit than the name since there are now two active agents, "the function" and "we". (If you want me to add comments to all the current ArgEffects and RetEffects I can.)</div><div><br></div><div><br></div><div><div>+ // Treat this function as returning a non-tracked symbol even if</div><div>+ // the function has been inlined. This is used where the call</div><div>+ // site summary is more presise than the inlining produced</div><div>+ // summary.</div><div>+ NoRetHard</div></div><div><br></div><div>Again, the call summary is not more precise (sp). It augments the effects of inlining, and in this case augments the effects of inlining to be more conservative.</div><div><br></div><div><br></div><div><div>+ // Evaluate the effect of the arguments.</div><div>+ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {</div><div>+ SVal V = CallOrMsg.getArgSVal(idx);</div><div>+ if (SymbolRef Sym = V.getAsLocSymbol()) {</div><div>+ if (Summ.getArg(idx) == StopTrackingHard) {</div><div>+ state = removeRefBinding(state, Sym);</div><div>+ C.addTransition(state);</div><div>+ }</div><div>+ }</div><div>+ }</div></div><div><br></div><div>In this version of the loop, it may be cheaper to test the summary's effect before seeing if the argument is a symbol.</div><div><br></div><div><br></div><div>In the test case:</div><div><div>++ (void) test: (Delegate *)d {</div><div>+ Cell *obj1 = [[Cell alloc] initWithDelegate: d]; // no-warning</div><div>+ Cell *obj2 = [[Cell alloc] init]; // no-warning</div><div>+ updateObject(obj2, releaseObj);</div><div>+ [Cell updateObject: obj2</div><div>+ WithCallback: releaseObj];</div><div>+</div><div>+}</div></div><div><br></div><div>The last test case should probably be a separate object, since once you StopTracking[Hard] an object it doesn't matter what else you do to it. Also, there are two paths I can think of that should be added here: calling a non-init method that contains the word "delegate" (-setDelegate: would work well), and making sure the /receiver/ is invalidated when you use a callback.</div><div><br></div><div>Not so happy about the additional complexity, but I guess this is necessary for properly handling inlined calls. Thanks for bearing with me.</div><div>Jordan</div></div><div><br></div></div><br></body></html>