bool OSAtomicChecker::inlineCall(const CallExpr *CE,
                                 ExprEngine &Eng,
                                 ExplodedNode *Pred,
                                 ExplodedNodeSet &Dst) const {
  const ProgramState *state = Pred->getState();
  const Expr *Callee = CE->getCallee();
  SVal L = state->getSVal(Callee);

  const FunctionDecl *FD = L.getAsFunctionDecl();
  if (!FD)
    return false;

  const IdentifierInfo *II = FD->getIdentifier();
  if (!II)
    return false;
  
  StringRef FName(II->getName());

  // Check for compare and swap.
  if (FName.startswith("OSAtomicCompareAndSwap") ||
      FName.startswith("objc_atomicCompareAndSwap"))
    return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);

  // FIXME: Other atomics.
  return false;
}
Пример #2
0
static StringRef getCalleeName(ProgramStateRef State,
                               const CallExpr *CE,
                               const LocationContext *LCtx) {
  const Expr *Callee = CE->getCallee();
  SVal L = State->getSVal(Callee, LCtx);
  const FunctionDecl *funDecl =  L.getAsFunctionDecl();
  if (!funDecl)
    return StringRef();
  IdentifierInfo *funI = funDecl->getIdentifier();
  if (!funI)
    return StringRef();
  return funI->getName();
}
Пример #3
0
const Decl *CallOrObjCMessage::getDecl() const {
  if (isCXXCall()) {
    const CXXMemberCallExpr *CE =
        cast<CXXMemberCallExpr>(CallE.dyn_cast<const CallExpr *>());
    assert(CE);
    return CE->getMethodDecl();
  } else if (isObjCMessage()) {
    return Msg.getMethodDecl();
  } else if (isFunctionCall()) {
    // In case of a C style call, use the path sensitive information to find
    // the function declaration.
    SVal CalleeVal = getFunctionCallee();
    return CalleeVal.getAsFunctionDecl();
  }
  return 0;
}
void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
                                            CheckerContext &C) const {
  const ProgramState *state = C.getState();
  const Expr *Callee = CE->getCallee();

  bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();

  if (!BuildSinks) {
    SVal L = state->getSVal(Callee);
    const FunctionDecl *FD = L.getAsFunctionDecl();
    if (!FD)
      return;

    if (FD->getAttr<AnalyzerNoReturnAttr>())
      BuildSinks = true;
    else if (const IdentifierInfo *II = FD->getIdentifier()) {
      // HACK: Some functions are not marked noreturn, and don't return.
      //  Here are a few hardwired ones.  If this takes too long, we can
      //  potentially cache these results.
      BuildSinks
        = llvm::StringSwitch<bool>(StringRef(II->getName()))
            .Case("exit", true)
            .Case("panic", true)
            .Case("error", true)
            .Case("Assert", true)
            // FIXME: This is just a wrapper around throwing an exception.
            //  Eventually inter-procedural analysis should handle this easily.
            .Case("ziperr", true)
            .Case("assfail", true)
            .Case("db_error", true)
            .Case("__assert", true)
            .Case("__assert_rtn", true)
            .Case("__assert_fail", true)
            .Case("dtrace_assfail", true)
            .Case("yy_fatal_error", true)
            .Case("_XCAssertionFailureHandler", true)
            .Case("_DTAssertionFailureHandler", true)
            .Case("_TSAssertionFailureHandler", true)
            .Default(false);
    }
  }

  if (BuildSinks)
    C.generateSink();
}
bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
  const GRState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  SVal L = state->getSVal(Callee);
  
  const FunctionDecl *FD = L.getAsFunctionDecl();
  if (!FD)
    return false;

  if (!FD->getBody(FD))
    return false;

  // Now we have the definition of the callee, create a CallEnter node.
  CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext());
  C.addTransition(state, Loc);

  return true;
}
Пример #6
0
    virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {

      ProgramStateRef state = getReplayWithoutInliningState(Pred, CE);

      // First, try to inline the call.
      if (state == 0 && Eng.InlineCall(Dst, CE, Pred))
        return;

      // First handle the return value.
      StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext);

      // Get the callee.
      const Expr *Callee = CE->getCallee()->IgnoreParens();
      if (state == 0)
        state = Pred->getState();
      SVal L = state->getSVal(Callee, Pred->getLocationContext());

      // Figure out the result type. We do this dance to handle references.
      QualType ResultTy;
      if (const FunctionDecl *FD = L.getAsFunctionDecl())
        ResultTy = FD->getResultType();
      else
        ResultTy = CE->getType();

      if (CE->isLValue())
        ResultTy = Eng.getContext().getPointerType(ResultTy);

      // Conjure a symbol value to use as the result.
      SValBuilder &SVB = Eng.getSValBuilder();
      unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount();
      const LocationContext *LCtx = Pred->getLocationContext();
      SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);

      // Generate a new state with the return value set.
      state = state->BindExpr(CE, LCtx, RetVal);

      // Invalidate the arguments.
      state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx),
                                      LCtx);

      // And make the result node.
      Bldr.generateNode(CE, Pred, state);
    }
bool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) {
  const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());

  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return false;

  // Check if we called CFRetain/CFRelease.
  const GRState* state = N->getState();
  SVal X = state->getSVal(CE->getCallee());
  const FunctionDecl* FD = X.getAsFunctionDecl();

  if (!FD)
    return false;

  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release))
    return false;

  // Finally, check if the argument is NULL.
  // FIXME: We should be able to bifurcate the state here, as a successful
  // check will result in the value not being NULL afterwards.
  // FIXME: Need a way to register vistors for the BugReporter.  Would like
  // to benefit from the same diagnostics that regular null dereference
  // reporting has.
  if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) {
    if (!BT)
      BT = new APIMisuse("null passed to CFRetain/CFRelease");

    const char *description = (FuncII == Retain)
                            ? "Null pointer argument in call to CFRetain"
                            : "Null pointer argument in call to CFRelease";

    RangedBugReport *report = new RangedBugReport(*BT, description, N);
    report->addRange(CE->getArg(0)->getSourceRange());
    BR.EmitReport(report);
    return true;
  }

  return false;
}
Пример #8
0
void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
                           GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L,
                           ExplodedNode* Pred) {
  FunctionDecl const *FD = L.getAsFunctionDecl();
  if (!FD)
    return; // GRExprEngine is responsible for the autotransition.

  // Make a new LocationContext.
  StackFrameContext const *LocCtx =
  Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE);

  CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());

  assert (Entry->empty() && "Entry block must be empty.");

  assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");

  // Get the solitary successor.
  CFGBlock const *SuccB = *(Entry->succ_begin());

  // Construct an edge representing the starting location in the function.
  BlockEdge Loc(Entry, SuccB, LocCtx);

  GRState const *state = Builder.GetState(Pred);  
  state = Engine.getStoreManager().EnterStackFrame(state, LocCtx);

  bool isNew;
  ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew);
  SuccN->addPredecessor(Pred, Engine.getGraph());

  Builder.Deferred.erase(Pred);

  // This is a hack. We really should not use the GRStmtNodeBuilder.
  if (isNew)
    Builder.getWorkList()->Enqueue(SuccN);

  Builder.HasGeneratedNode = true;
}
Пример #9
0
bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
  const ProgramState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  SVal L = state->getSVal(Callee);

  const FunctionDecl *FD = L.getAsFunctionDecl();
  if (!FD)
    return false;

  const IdentifierInfo *II = FD->getIdentifier();
  if (!II)
    return false;
  
  StringRef FName(II->getName());

  // Check for compare and swap.
  if (FName.startswith("OSAtomicCompareAndSwap") ||
      FName.startswith("objc_atomicCompareAndSwap"))
    return evalOSAtomicCompareAndSwap(C, CE);

  // FIXME: Other atomics.
  return false;
}
Пример #10
0
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
    const GRState *state = C.getState();
    const Expr *Callee = CE->getCallee();
    SVal L = state->getSVal(Callee);
    const FunctionDecl *FD = L.getAsFunctionDecl();
    if (!FD)
        return false;

    ASTContext &Ctx = C.getASTContext();
    if (!II_fopen)
        II_fopen = &Ctx.Idents.get("fopen");
    if (!II_tmpfile)
        II_tmpfile = &Ctx.Idents.get("tmpfile");
    if (!II_fclose)
        II_fclose = &Ctx.Idents.get("fclose");
    if (!II_fread)
        II_fread = &Ctx.Idents.get("fread");
    if (!II_fwrite)
        II_fwrite = &Ctx.Idents.get("fwrite");
    if (!II_fseek)
        II_fseek = &Ctx.Idents.get("fseek");
    if (!II_ftell)
        II_ftell = &Ctx.Idents.get("ftell");
    if (!II_rewind)
        II_rewind = &Ctx.Idents.get("rewind");
    if (!II_fgetpos)
        II_fgetpos = &Ctx.Idents.get("fgetpos");
    if (!II_fsetpos)
        II_fsetpos = &Ctx.Idents.get("fsetpos");
    if (!II_clearerr)
        II_clearerr = &Ctx.Idents.get("clearerr");
    if (!II_feof)
        II_feof = &Ctx.Idents.get("feof");
    if (!II_ferror)
        II_ferror = &Ctx.Idents.get("ferror");
    if (!II_fileno)
        II_fileno = &Ctx.Idents.get("fileno");

    if (FD->getIdentifier() == II_fopen) {
        Fopen(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_tmpfile) {
        Tmpfile(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fclose) {
        Fclose(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fread) {
        Fread(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fwrite) {
        Fwrite(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fseek) {
        Fseek(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_ftell) {
        Ftell(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_rewind) {
        Rewind(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fgetpos) {
        Fgetpos(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fsetpos) {
        Fsetpos(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_clearerr) {
        Clearerr(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_feof) {
        Feof(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_ferror) {
        Ferror(C, CE);
        return true;
    }
    if (FD->getIdentifier() == II_fileno) {
        Fileno(C, CE);
        return true;
    }

    return false;
}
Пример #11
0
const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
  ProgramStateRef State = getState();
  const Expr *Callee = CE->getCallee();
  SVal L = State->getSVal(Callee, Pred->getLocationContext());
  return L.getAsFunctionDecl();
}
Пример #12
0
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, 
                                          const CallExpr *CE) {
  const GRState *state = C.getState();
  const GRState *originalState = state;

  // Check if the callee has a 'nonnull' attribute.
  SVal X = state->getSVal(CE->getCallee());

  const FunctionDecl* FD = X.getAsFunctionDecl();
  if (!FD)
    return;

  const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
  if (!Att)
    return;

  // Iterate through the arguments of CE and check them for null.
  unsigned idx = 0;

  for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
       ++I, ++idx) {

    if (!Att->isNonNull(idx))
      continue;

    const SVal &V = state->getSVal(*I);
    const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);

    if (!DV)
      continue;

    ConstraintManager &CM = C.getConstraintManager();
    const GRState *stateNotNull, *stateNull;
    llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);

    if (stateNull && !stateNotNull) {
      // Generate an error node.  Check for a null node in case
      // we cache out.
      if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {

        // Lazily allocate the BugType object if it hasn't already been
        // created. Ownership is transferred to the BugReporter object once
        // the BugReport is passed to 'EmitWarning'.
        if (!BT)
          BT = new BugType("Argument with 'nonnull' attribute passed null",
                           "API");

        EnhancedBugReport *R =
          new EnhancedBugReport(*BT,
                                "Null pointer passed as an argument to a "
                                "'nonnull' parameter", errorNode);

        // Highlight the range of the argument that was null.
        const Expr *arg = *I;
        R->addRange(arg->getSourceRange());
        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);

        // Emit the bug report.
        C.EmitReport(R);
      }

      // Always return.  Either we cached out or we just emitted an error.
      return;
    }

    // If a pointer value passed the check we should assume that it is
    // indeed not null from this point forward.
    assert(stateNotNull);
    state = stateNotNull;
  }

  // If we reach here all of the arguments passed the nonnull check.
  // If 'state' has been updated generated a new node.
  if (state != originalState)
    C.addTransition(C.GenerateNode(CE, state));
}
Пример #13
0
bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
  const GRState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  SVal L = state->getSVal(Callee);

  const FunctionDecl *FD = L.getAsFunctionDecl();
  if (!FD)
    return false;

  ASTContext &Ctx = C.getASTContext();
  if (!II_malloc)
    II_malloc = &Ctx.Idents.get("malloc");
  if (!II_free)
    II_free = &Ctx.Idents.get("free");
  if (!II_realloc)
    II_realloc = &Ctx.Idents.get("realloc");
  if (!II_calloc)
    II_calloc = &Ctx.Idents.get("calloc");

  if (FD->getIdentifier() == II_malloc) {
    MallocMem(C, CE);
    return true;
  }

  if (FD->getIdentifier() == II_free) {
    FreeMem(C, CE);
    return true;
  }

  if (FD->getIdentifier() == II_realloc) {
    ReallocMem(C, CE);
    return true;
  }

  if (FD->getIdentifier() == II_calloc) {
    CallocMem(C, CE);
    return true;
  }

  // Check all the attributes, if there are any.
  // There can be multiple of these attributes.
  bool rv = false;
  if (FD->hasAttrs()) {
    for (specific_attr_iterator<OwnershipAttr>
                  i = FD->specific_attr_begin<OwnershipAttr>(),
                  e = FD->specific_attr_end<OwnershipAttr>();
         i != e; ++i) {
      switch ((*i)->getOwnKind()) {
      case OwnershipAttr::Returns: {
        MallocMemReturnsAttr(C, CE, *i);
        rv = true;
        break;
      }
      case OwnershipAttr::Takes:
      case OwnershipAttr::Holds: {
        FreeMemAttr(C, CE, *i);
        rv = true;
        break;
      }
      default:
        break;
      }
    }
  }
  return rv;
}
Пример #14
0
const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
  const ProgramState *State = getState();
  const Expr *Callee = CE->getCallee();
  SVal L = State->getSVal(Callee);
  return L.getAsFunctionDecl();
}
bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
  const CallExpr* CE =
    cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
  const Expr* Callee = CE->getCallee();
  SVal CallV = N->getState()->getSVal(Callee);
  const FunctionDecl* FD = CallV.getAsFunctionDecl();

  if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
    return false;

  // Get the value of the "theType" argument.
  SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1));

    // FIXME: We really should allow ranges of valid theType values, and
    //   bifurcate the state appropriately.
  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);

  if (!V)
    return false;

  uint64_t NumberKind = V->getValue().getLimitedValue();
  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);

  // FIXME: In some cases we can emit an error.
  if (!TargetSize.isKnown())
    return false;

  // Look at the value of the integer being passed by reference.  Essentially
  // we want to catch cases where the value passed in is not equal to the
  // size of the type being created.
  SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2));

  // FIXME: Eventually we should handle arbitrary locations.  We can do this
  //  by having an enhanced memory model that does low-level typing.
  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);

  if (!LV)
    return false;

  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());

  if (!R)
    return false;

  QualType T = Ctx.getCanonicalType(R->getValueType(Ctx));

  // FIXME: If the pointee isn't an integer type, should we flag a warning?
  //  People can do weird stuff with pointers.

  if (!T->isIntegerType())
    return false;

  uint64_t SourceSize = Ctx.getTypeSize(T);

  // CHECK: is SourceSize == TargetSize

  if (SourceSize == TargetSize)
    return false;

  AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);

  // FIXME: We can actually create an abstract "CFNumber" object that has
  //  the bits initialized to the provided values.
  return SourceSize < TargetSize;
}
Пример #16
0
void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
                                             const CallExpr *CE)
{
  const Expr* Callee = CE->getCallee();
  const GRState *state = C.getState();
  SVal CallV = state->getSVal(Callee);
  const FunctionDecl* FD = CallV.getAsFunctionDecl();

  if (!FD)
    return;
  
  ASTContext &Ctx = C.getASTContext();
  if (!II)
    II = &Ctx.Idents.get("CFNumberCreate");

  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
    return;

  // Get the value of the "theType" argument.
  SVal TheTypeVal = state->getSVal(CE->getArg(1));

  // FIXME: We really should allow ranges of valid theType values, and
  //   bifurcate the state appropriately.
  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
  if (!V)
    return;

  uint64_t NumberKind = V->getValue().getLimitedValue();
  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);

  // FIXME: In some cases we can emit an error.
  if (!TargetSize.isKnown())
    return;

  // Look at the value of the integer being passed by reference.  Essentially
  // we want to catch cases where the value passed in is not equal to the
  // size of the type being created.
  SVal TheValueExpr = state->getSVal(CE->getArg(2));

  // FIXME: Eventually we should handle arbitrary locations.  We can do this
  //  by having an enhanced memory model that does low-level typing.
  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
  if (!LV)
    return;

  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
  if (!R)
    return;

  QualType T = Ctx.getCanonicalType(R->getValueType());

  // FIXME: If the pointee isn't an integer type, should we flag a warning?
  //  People can do weird stuff with pointers.

  if (!T->isIntegerType())
    return;

  uint64_t SourceSize = Ctx.getTypeSize(T);

  // CHECK: is SourceSize == TargetSize
  if (SourceSize == TargetSize)
    return;

  // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
  // otherwise generate a regular node.
  //
  // FIXME: We can actually create an abstract "CFNumber" object that has
  //  the bits initialized to the provided values.
  //
  if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 
                                                : C.generateNode()) {
    llvm::SmallString<128> sbuf;
    llvm::raw_svector_ostream os(sbuf);
    
    os << (SourceSize == 8 ? "An " : "A ")
       << SourceSize << " bit integer is used to initialize a CFNumber "
                        "object that represents "
       << (TargetSize == 8 ? "an " : "a ")
       << TargetSize << " bit integer. ";
    
    if (SourceSize < TargetSize)
      os << (TargetSize - SourceSize)
      << " bits of the CFNumber value will be garbage." ;
    else
      os << (SourceSize - TargetSize)
      << " bits of the input integer will be lost.";

    if (!BT)
      BT = new APIMisuse("Bad use of CFNumberCreate");
    
    RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
    report->addRange(CE->getArg(2)->getSourceRange());
    C.EmitReport(report);
  }
}
Пример #17
0
void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
                                              const CallExpr* CE) {
  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return;

  // Get the function declaration of the callee.
  const GRState* state = C.getState();
  SVal X = state->getSVal(CE->getCallee());
  const FunctionDecl* FD = X.getAsFunctionDecl();

  if (!FD)
    return;
  
  if (!BT) {
    ASTContext &Ctx = C.getASTContext();
    Retain = &Ctx.Idents.get("CFRetain");
    Release = &Ctx.Idents.get("CFRelease");
    BT = new APIMisuse("null passed to CFRetain/CFRelease");
  }

  // Check if we called CFRetain/CFRelease.
  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release))
    return;

  // FIXME: The rest of this just checks that the argument is non-null.
  // It should probably be refactored and combined with AttrNonNullChecker.

  // Get the argument's value.
  const Expr *Arg = CE->getArg(0);
  SVal ArgVal = state->getSVal(Arg);
  DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
  if (!DefArgVal)
    return;

  // Get a NULL value.
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));

  // Make an expression asserting that they're equal.
  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);

  // Are they equal?
  const GRState *stateTrue, *stateFalse;
  llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);

  if (stateTrue && !stateFalse) {
    ExplodedNode *N = C.generateSink(stateTrue);
    if (!N)
      return;

    const char *description = (FuncII == Retain)
                            ? "Null pointer argument in call to CFRetain"
                            : "Null pointer argument in call to CFRelease";

    EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
    report->addRange(Arg->getSourceRange());
    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
    C.EmitReport(report);
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateFalse);
}
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
                                           const LocationContext *LCtx,
                                           const RefVal &CurrV, SymbolRef &Sym,
                                           const Stmt *S,
                                           llvm::raw_string_ostream &os) {
  CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
    // Get the name of the callee (if it is available)
    // from the tracked SVal.
    SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
    const FunctionDecl *FD = X.getAsFunctionDecl();

    // If failed, try to get it from AST.
    if (!FD)
      FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());

    if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
      os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
    } else if (FD) {
      os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
    } else {
      os << "function call";
    }
  } else if (isa<CXXNewExpr>(S)) {
    os << "Operator 'new'";
  } else {
    assert(isa<ObjCMessageExpr>(S));
    CallEventRef<ObjCMethodCall> Call =
        Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);

    switch (Call->getMessageKind()) {
    case OCM_Message:
      os << "Method";
      break;
    case OCM_PropertyAccess:
      os << "Property";
      break;
    case OCM_Subscript:
      os << "Subscript";
      break;
    }
  }

  Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
  auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);

  // If index is not found, we assume that the symbol was returned.
  if (!Idx) {
    os << " returns ";
  } else {
    os << " writes ";
  }

  if (CurrV.getObjKind() == ObjKind::CF) {
    os << "a Core Foundation object of type '"
       << Sym->getType().getAsString() << "' with a ";
  } else if (CurrV.getObjKind() == ObjKind::OS) {
    os << "an OSObject of type '" << getPrettyTypeName(Sym->getType())
       << "' with a ";
  } else if (CurrV.getObjKind() == ObjKind::Generalized) {
    os << "an object of type '" << Sym->getType().getAsString()
       << "' with a ";
  } else {
    assert(CurrV.getObjKind() == ObjKind::ObjC);
    QualType T = Sym->getType();
    if (!isa<ObjCObjectPointerType>(T)) {
      os << "an Objective-C object with a ";
    } else {
      const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
      os << "an instance of " << PT->getPointeeType().getAsString()
         << " with a ";
    }
  }

  if (CurrV.isOwned()) {
    os << "+1 retain count";
  } else {
    assert(CurrV.isNotOwned());
    os << "+0 retain count";
  }

  if (Idx) {
    os << " into an out parameter '";
    const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
    PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
                              /*Qualified=*/false);
    os << "'";

    QualType RT = (*CE)->getResultType();
    if (!RT.isNull() && !RT->isVoidType()) {
      SVal RV = (*CE)->getReturnValue();
      if (CurrSt->isNull(RV).isConstrainedTrue()) {
        os << " (assuming the call returns zero)";
      } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
        os << " (assuming the call returns non-zero)";
      }

    }
  }
}