/// Insert a diagnostic piece at function exit
/// if a function parameter is annotated as "os_consumed",
/// but it does not actually consume the reference.
static std::shared_ptr<PathDiagnosticEventPiece>
annotateConsumedSummaryMismatch(const ExplodedNode *N,
                                CallExitBegin &CallExitLoc,
                                const SourceManager &SM,
                                CallEventManager &CEMgr) {

  const ExplodedNode *CN = getCalleeNode(N);
  if (!CN)
    return nullptr;

  CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());

  std::string sbuf;
  llvm::raw_string_ostream os(sbuf);
  ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
  for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
    const ParmVarDecl *PVD = Parameters[I];

    if (!PVD->hasAttr<OSConsumedAttr>())
      continue;

    if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
      const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
      const RefVal *CountAtExit = getRefBinding(N->getState(), SR);

      if (!CountBeforeCall || !CountAtExit)
        continue;

      unsigned CountBefore = CountBeforeCall->getCount();
      unsigned CountAfter = CountAtExit->getCount();

      bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
      if (!AsExpected) {
        os << "Parameter '";
        PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
                                  /*Qualified=*/false);
        os << "' is marked as consuming, but the function did not consume "
           << "the reference\n";
      }
    }
  }

  if (os.str().empty())
    return nullptr;

  // FIXME: remove the code duplication with NoStoreFuncVisitor.
  PathDiagnosticLocation L;
  if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) {
    L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext());
  } else {
    L = PathDiagnosticLocation(
        Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM);
  }

  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
}
Beispiel #2
0
PathDiagnosticPiece *
UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
                                  const ExplodedNode *PrevN,
                                  BugReporterContext &BRC,
                                  BugReport &BR) {

  ProgramStateRef State = N->getState();
  ProgramPoint ProgLoc = N->getLocation();

  // We are only interested in visiting CallEnter nodes.
  Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
  if (!CEnter)
    return 0;

  // Check if one of the arguments is the region the visitor is tracking.
  CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
  CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
  unsigned Idx = 0;
  for (CallEvent::param_iterator I = Call->param_begin(),
                                 E = Call->param_end(); I != E; ++I, ++Idx) {
    const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();

    // Are we tracking the argument or its subregion?
    if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts())))
      continue;

    // Check the function parameter type.
    const ParmVarDecl *ParamDecl = *I;
    assert(ParamDecl && "Formal parameter has no decl?");
    QualType T = ParamDecl->getType();

    if (!(T->isAnyPointerType() || T->isReferenceType())) {
      // Function can only change the value passed in by address.
      continue;
    }
    
    // If it is a const pointer value, the function does not intend to
    // change the value.
    if (T->getPointeeType().isConstQualified())
      continue;

    // Mark the call site (LocationContext) as interesting if the value of the 
    // argument is undefined or '0'/'NULL'.
    SVal BoundVal = State->getSVal(R);
    if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
      BR.markInteresting(CEnter->getCalleeContext());
      return 0;
    }
  }
  return 0;
}