<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Apr 26, 2018, at 10:26 AM, Gábor Horváth via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class=""><div class=""><div class=""><div class="">Hi!<br class=""><br class=""></div>This is a philosophical question to some extent. I think what _Nonnull means at the return value is that in case all the preconditions of a function is met the result will never be null.<br class=""></div>So in case a function has a _Nonnull parameter and a _Nonnull return value and the caller passes null, the function is free to return null.<br class=""><br class=""></div>Of course, passing null to this function was an error in the first place.<br class=""><br class=""></div><div class="">There is a tradeoff, constraining these values to not being null will reduce the coverage and lots of the errors found by the analyzer are actually in the error handling code.<br class=""></div><div class="">But having this information might increase the precision of the analysis.<br class=""><br class=""></div><div class="">I think the reason why it was developed that way there were lots of legacy APIs where the clients relied on the behavior that a _Nonnull function (which was not annotated<br class=""></div><div class="">in the past of course,) returns null when its precondition is not met.<br class=""><br class=""></div><div class="">Maybe people started to fix such code and now it makes sense to change this behavior?<br class=""></div></div></div></blockquote><div><br class=""></div><div>For anything that represents input to a framework we don’t want to change this behavior. This is because the implementation of frameworks must remain robust against, for example, clients passing in nil to a parameter marked as nonnull. If we were to model such parameters as constrained to be non-zero then the analyzer would never cover the defensive code paths that make the framework robust (since it would think that they are not feasible). However, defensive code paths are less likely to be covered and tested — so these are exactly the paths that benefit the most from static analysis!</div><div><br class=""></div><div>More broadly speaking, as Gabor notes, the meaning of ‘_Nonnull’ in parameter and return types is not ‘this value can never be nil’ but rather a more complex contract between caller and callee in which the callee promises to respect _Nonnull in its outputs as long as the caller respected it for the passed-in inputs. This kind of nuance is the inevitable result of adding more expressive types to a language where there is a large body of code developed without those types enforced.</div><div><br class=""></div><div>Devin</div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">Regards,<br class=""></div><div class="">Gábor<br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On 26 April 2018 at 19:12, Timothy J. Wood via cfe-dev <span dir="ltr" class=""><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">While working on my outError-writing checker, I thought I’d try to use as much of the built-in checker support for tracking which values/regions are marked a non-null as possible rather than adding tracking of every `NSError *` in my own state.<br class=""><br class="">The tl;dr version of the rest of this is whether the analyzer will mark a _Nonnull result as being constrained to nonnull.<br class=""><br class="">Here is what I’m doing, which makes it seem like the answer is “no”, but maybe I’m doing it wrong...<br class=""><br class="">In my test input I have something like:<br class=""><br class="">        @interface NSError : NSObject <NSCopying, NSCoding> {}<br class="">        + (instancetype _Nonnull)make; // convenient fiction to make exploded graph smaller while debugging<br class="">        @end<br class=""><br class="">        ...<br class=""><br class="">        - (BOOL)failWithErrorLocal:(<wbr class="">NSError **)outError;<br class="">        {<br class="">                NSError *e = [NSError make]; <br class="">                if (outError) {<br class="">                        *outError = e;<br class="">                }<br class="">                return NO;<br class="">        }<br class=""><br class="">Since +make is marked as returning a nonnull result, I was expecting/hoping the checkBind call for that assignment to have a r-value that was constrained to nonnull (and that this would get propagated to *outError if the body of the `if` was executed). But, in my checkBind(), if I do:<br class=""><br class="">         dmsg << "  Val " << Val << "\n";<br class=""><br class="">         ConditionTruthVal IsNull = State->isNull(Val);<br class="">         dmsg << "  IsNull.isConstrained() " << IsNull.isConstrained() << "\n";<br class="">         dmsg << "  IsNull.isConstrainedTrue() " << IsNull.isConstrainedTrue() << "\n”;<br class=""><br class="">I see:<br class=""><br class="">        Val &SymRegion{conj_$4{id _Nonnull}}<br class="">        IsNull.isConstrained() 0<br class="">        IsNull.isConstrainedTrue() 0<br class=""><br class="">If I set a breakpoint on my checkBind() and then finish out to ExprEngine::VisitDeclStmt, I get a exploded graph dot file like:<br class=""><br class=""><br class="">         <br class=""><br class=""><br class="">I’m still not really sure how to read these, but can see that it has bound the local `e` to the nonnull result of +make:<br class=""><br class="">        (e,0,direct) : &SymRegion{conj_$4{NSError * _Nonnull}}<br class=""><br class="">Thanks,<br class=""><br class="">-tim<br class=""><br class=""><br class="">______________________________<wbr class="">_________________<br class="">cfe-dev mailing list<br class=""><a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a><br class=""><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/cgi-bin/<wbr class="">mailman/listinfo/cfe-dev</a><br class=""><br class=""></blockquote></div><br class=""></div>_______________________________________________<br class="">cfe-dev mailing list<br class=""><a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev<br class=""></blockquote></div><div class=""><br class=""></div></body></html>