<div dir="ltr"><div class="gmail_quote"><div class="gmail_attr">Hi,</div><div class="gmail_attr"><br></div><div class="gmail_attr">Thanks! It took me a while since this original mailing list post, but I have now returned to this project and have made some progress.<br></div><div dir="ltr" class="gmail_attr"><br></div><div dir="ltr" class="gmail_attr">On Thu, Aug 1, 2019 at 5:40 PM Artem Dergachev <<a href="mailto:noqnoqneo@gmail.com">noqnoqneo@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF">
    On 7/31/19 2:01 PM, via cfe-dev wrote:<br>
    <blockquote type="cite">
      
      <div dir="ltr">
        <div>Hi list,<br>
        </div>
        <div><br>
        </div>
        <div>I have the following code to analyze:</div>
        <div><br>
        </div>
        <div>struct BoolConvertibleStruct {<br>
              int n;<br>
              BoolConvertibleStruct(int m) : n(m) {}<br>
              operator bool() const { return n != 0; }<br>
          };<br>
          <br>
          BoolConvertibleStruct StructFunc() {<br>
              return 1;<br>
          }</div>
        <div><br>
        </div>
        <div>I have reduced my problem to wanting to analyze
          StructFunc() to figure out the truth value of its return
          value. (The actual problem is more complicated and you might
          recognize that BoolConvertibleStruct is a stand-in for
          std::unique_ptr<T>, among other things :-P)</div>
      </div>
    </blockquote>
    <br>
    That's a very important detail. If it's a struct that you've
    implemented yourself, then all you need to do is extract the value
    from a field of the structure (it's not a problem when you know the
    name of the field).<br></div></blockquote><div><br></div><div>Indeed, I've gotten my contrived example to work (see below) but you're right it is quite different when dealing with std::unique_ptr.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF">
    
    However, if it's something in the C++ standard library and it's
    implemented differently depending on the particular implementation
    of the standard library that you may be using, then you can't access
    the field because you've no idea what meaning does every field
    carry, so you'll have to treat the structure as an opaque object and
    reason about its contents by modeling every method of the structure.
    I.e.:<br>
    <br>
    1. Subscribe to the constructor of the structure and map (as in
    REGISTER_MAP_WITH_PROGRAMSTATE) the region of the structure to the
    value with which it was constructed.<br>
    2. Subscribe to the copy/move constructor of the structure and map
    the region into which it's copied/moved to the same value.<br>
    3. Subscribe to any method that mutates the value and update your
    maps.<br>
    4. Once you do all of this, you would be able to simply retrieve the
    value from your map when you need to model operator bool.<br>
    <br>
    This approach is costly and annoying and easy to get wrong and i
    wish we had better tools for implementing it but for now it assumes
    a lot of boilerplate. If you want examples, see how the experimental
    IteratorChecker tries to model iterators (which is a harder
    problem).<br></div></blockquote><div><br></div><div>I think I have got a skeleton of this approach almost working, but I seem to be stuck in some of the details. My program state map is from "const MemRegion*" to "SVal" (I don't think I need an additional map for symbols as in IteratorChecker?) However it seems that the MemRegion I get when subscribing to the constructor in PreCall or PostCall is different from the MemRegion I get when modeling std::unique_ptr::get() in EvalCall. I'm getting the MemRegion from the CallEvent like so (in the constructor I use CXXConstructorCall instead):</div><div><br></div><div>    const auto* instCall = cast<CXXInstanceCall>(&call);<br>    const MemRegion* thisRegion = instCall->getCXXThisVal().getAsRegion();<br>    if (thisRegion)<br>        thisRegion = thisRegion->getMostDerivedObjectRegion();</div><div><br></div><div>However, the returned region seems to be different in the constructor and in the get() method. For example I'm testing my code with a "struct MyStruct : std::unique_ptr<char>" and I'll get debug output such as:</div><div><div><br></div><div>    constructor: Storing 0 (Loc) into map with key SymRegion{conj_$5{struct MyStruct *, LC1, S3038538, #1}}</div><div>    get(): Retrieving key SymRegion{reg_$0<const struct MyStruct * this>}: not present</div><div><br></div><div>I did find <a href="https://reviews.llvm.org/D26762">https://reviews.llvm.org/D26762</a> linked from another mailing list post (<a href="http://lists.llvm.org/pipermail/cfe-dev/2017-June/054100.html">http://lists.llvm.org/pipermail/cfe-dev/2017-June/054100.html</a>), which seems like it might be related to where I'm stuck, but the code in that patch always seems to return None, maybe I'm not using it correctly.<br></div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF">
    
    Generally, i'll be pretty excited to accept patches that improve
    modeling of smart pointers in this manner. If that aligns with your
    interests, please extend our fairly minimal SmartPtrChecker and put
    your work to Phabricator (on an as early of a stage as possible) so
    that we could merge it!<br></div></blockquote><div><br></div><div>I am trying to make the modeling work well enough for my own purpose first and then I will take a look at posting it to Phabricator. I will try to make it general enough to be able to submit it.<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF">
    <blockquote type="cite">
      <div dir="ltr">
        <div>I have the following sample checker:<br>
        </div>
        <div><br>
        </div>
        <div>class Analyzer : public Checker<check::EndFunction> {<br>
           public:<br>
              void checkEndFunction(const ReturnStmt* ret,
          CheckerContext& cx) const {<br>
        </div>
      </div>
    </blockquote>
    
    <blockquote type="cite">
      <div dir="ltr">
        <div>        const auto* func =
          cast<FunctionDecl>(cx.getStackFrame()->getDecl());<br>
                  if (func->getQualifiedNameAsString() !=
          "StructFunc")<br>
                      return;<br>
          <br>
                  ProgramStateRef state = cx.getState();<br>
                  SValBuilder& builder = cx.getSValBuilder();<br>
                  ASTContext& ast = cx.getASTContext();<br>
          <br>
                  SVal returnValue = cx.getSVal(ret->getRetValue());<br>
                  SVal falseValue = builder.makeZeroVal(ast.BoolTy);<br>
                  SVal returnedFalse = builder.evalEQ(state,
          returnValue, falseValue);<br>
          <br>
                  errs() << "Evaluating (" << returnValue
          << " == " << falseValue<br>
                      << ") -> " << returnedFalse
          << "\n";<br>
              }<br>
          };</div>
        <div><br>
        </div>
        <div>However when I run it on my sample code I get this output:</div>
        <div><br>
        </div>
        <div>Evaluating
          (lazyCompoundVal{0x7f98f1871c70,Element{SymRegion{conj_$0{struct
          BoolConvertibleStruct *, LC1, S973, #1}},0 S64b,struct
          BoolConvertibleStruct}} == 0 U1b) -> Unknown</div>
      </div>
    </blockquote>
    <br>
    lazyCompoundVal is a snapshot of the structure as a whole. You can
    extract values of particular fields from it with the following
    procedure:<br>
    <br>
    - Take the lazyCompoundVal's parent region
    (`LazyCompoundVal::getRegion()`, in your case it's
    `Element{SymRegion{conj_$0{struct BoolConvertibleStruct *, LC1,
    S973, #1}},0 S64b,struct BoolConvertibleStruct}`).<br>
    - Construct a FieldRegion as a sub-region of the parent region with
    the FieldDecl of the field (i.e., State->getLValue(fieldDecl,
    parentRegion)).<br>
    - Ask StoreManager to do a getBinding() for that region from the
    lazyCompoundVal's Store (`LazyCompoundVal::getStore()`, in your case
    it's `0x7f98f1871c70`).<br>
  </div>

</blockquote></div><div><br></div><div>OK, I did get the contrived example to work that way. I guess the information I was missing was that I expected to be able to see any known bytes of the struct in the LazyCompoundVal, and that's not the case. In case any future readers want to know, the code I used is below. It turned out to be quite a lot more complicated than I expected and I am still not sure I understand why it works this way, but this seems to work.<br></div><div><br></div><div>        const Expr* returnExpr = ret->getRetValue();<br>        QualType returnType = returnExpr->getType();<br>        auto* klass = returnType.getTypePtr()->getAsCXXRecordDecl();<br>        const FieldDecl* nField = nullptr;<br>        for (const auto* field : klass->fields()) {<br>            if (field->getNameAsString() == "n")<br>                nField = field;<br>        }<br>        assert(nField);<br>        SVal returnValue = cx.getSVal(ret->getRetValue());<br>        Optional<nonloc::LazyCompoundVal> compoundValue = returnValue.getAs<nonloc::LazyCompoundVal>();<br>        assert(compoundValue);<br>        const TypedValueRegion* parentRegion = compoundValue->getRegion();<br>        SVal parentVal = state->getLValue(klass, parentRegion, /* isVirtual = */ false);<br>        SVal fieldVal = state->getLValue(nField, parentVal);<br>        Optional<Loc> fieldLoc = fieldVal.getAs<Loc>();<br>        assert(fieldLoc);<br>        StoreManager& storeManager = cx.getStoreManager();<br>        returnValue = storeManager.getBinding(compoundValue->getStore(), *fieldLoc);<br></div><div><br></div><div>Cheers,<br></div>-- <br><div dir="ltr" class="gmail_signature">Philip</div></div>