コード例 #1
0
ファイル: SimpleStreamChecker.cpp プロジェクト: 4ntoine/clang
void SimpleStreamChecker::reportLeaks(ArrayRef<SymbolRef> LeakedStreams,
                                      CheckerContext &C,
                                      ExplodedNode *ErrNode) const {
  // Attach bug reports to the leak node.
  // TODO: Identify the leaked file descriptor.
  for (SymbolRef LeakedStream : LeakedStreams) {
    BugReport *R = new BugReport(*LeakBugType,
        "Opened file is never closed; potential resource leak", ErrNode);
    R->markInteresting(LeakedStream);
    C.emitReport(R);
  }
}
コード例 #2
0
void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
                                               CheckerContext &C,
                                               ExplodedNode *ErrNode) const {
  // Attach bug reports to the leak node.
  // TODO: Identify the leaked file descriptor.
  for (SmallVectorImpl<SymbolRef>::iterator
         I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
    BugReport *R = new BugReport(*LeakBugType,
        "Opened file is never closed; potential resource leak", ErrNode);
    R->markInteresting(*I);
    C.emitReport(R);
  }
}
コード例 #3
0
void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
                                            const CallEvent &Call,
                                            CheckerContext &C) const {
  // We reached a bug, stop exploring the path here by generating a sink.
  ExplodedNode *ErrNode = C.generateSink();
  // If we've already reached this node on another path, return.
  if (!ErrNode)
    return;

  // Generate the report.
  BugReport *R = new BugReport(*DoubleCloseBugType,
      "Closing a previously closed file stream", ErrNode);
  R->addRange(Call.getSourceRange());
  R->markInteresting(FileDescSym);
  C.emitReport(R);
}
コード例 #4
0
bool PHPZPPCheckerImpl::compareTypeWithSVal(const SVal val,
                                            const std::string &expectedType,
                                            CheckerContext &C) const {
  if (expectedType != getTypeForSVal(val).getAsString()) {
    BugReport *R = new BugReport(
        *InvalidTypeBugType,
        std::string("Arguments don't match the type expected by the format "
                    "string (") +
            expectedType + std::string(" != ") +
            getTypeForSVal(val).getAsString() + std::string(")"),
        C.addTransition());
    R->markInteresting(val);
    C.emitReport(R);
    return false;
  }
  return true;
}
コード例 #5
0
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
                                   CheckerContext &C, bool IsBind) const {
  // Generate an error node.
  ExplodedNode *N = C.generateSink(State);
  if (!N)
    return;

  // We know that 'location' cannot be non-null.  This is what
  // we call an "explicit" null dereference.
  if (!BT_null)
    BT_null.reset(new BuiltinBug("Dereference of null pointer"));

  SmallString<100> buf;
  SmallVector<SourceRange, 2> Ranges;

  // Walk through lvalue casts to get the original expression
  // that syntactically caused the load.
  if (const Expr *expr = dyn_cast<Expr>(S))
    S = expr->IgnoreParenLValueCasts();

  const MemRegion *sourceR = 0;

  if (IsBind) {
    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
      if (BO->isAssignmentOp())
        S = BO->getRHS();
    } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
      assert(DS->isSingleDecl() && "We process decls one by one");
      if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
        if (const Expr *Init = VD->getAnyInitializer())
          S = Init;
    }
  }

  switch (S->getStmtClass()) {
  case Stmt::ArraySubscriptExprClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Array access";
    const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
    sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
                             State.getPtr(), N->getLocationContext());
    os << " results in a null pointer dereference";
    break;
  }
  case Stmt::UnaryOperatorClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Dereference of null pointer";
    const UnaryOperator *U = cast<UnaryOperator>(S);
    sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
                             State.getPtr(), N->getLocationContext(), true);
    break;
  }
  case Stmt::MemberExprClass: {
    const MemberExpr *M = cast<MemberExpr>(S);
    if (M->isArrow()) {
      llvm::raw_svector_ostream os(buf);
      os << "Access to field '" << M->getMemberNameInfo()
         << "' results in a dereference of a null pointer";
      sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
                               State.getPtr(), N->getLocationContext(), true);
    }
    break;
  }
  case Stmt::ObjCIvarRefExprClass: {
    const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
    if (const DeclRefExpr *DR =
        dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        llvm::raw_svector_ostream os(buf);
        os << "Instance variable access (via '" << VD->getName()
           << "') results in a null pointer dereference";
      }
    }
    Ranges.push_back(IV->getSourceRange());
    break;
  }
  default:
    break;
  }

  BugReport *report =
    new BugReport(*BT_null,
                  buf.empty() ? BT_null->getDescription() : buf.str(),
                  N);

  bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N),
                                               report);

  for (SmallVectorImpl<SourceRange>::iterator
       I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
    report->addRange(*I);

  if (sourceR) {
    report->markInteresting(sourceR);
    report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR)));
  }

  C.EmitReport(report);
}
コード例 #6
0
ファイル: MacOSKeychainAPIChecker.cpp プロジェクト: gix/clang
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
                                           CheckerContext &C) const {
  unsigned idx = InvalidIdx;
  ProgramStateRef State = C.getState();

  const FunctionDecl *FD = C.getCalleeDecl(CE);
  if (!FD || FD->getKind() != Decl::Function)
    return;
  
  StringRef funName = C.getCalleeName(FD);
  if (funName.empty())
    return;

  // If it is a call to an allocator function, it could be a double allocation.
  idx = getTrackedFunctionIndex(funName, true);
  if (idx != InvalidIdx) {
    const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
    if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
      if (const AllocationState *AS = State->get<AllocatedData>(V)) {
        if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
          // Remove the value from the state. The new symbol will be added for
          // tracking when the second allocator is processed in checkPostStmt().
          State = State->remove<AllocatedData>(V);
          ExplodedNode *N = C.addTransition(State);
          if (!N)
            return;
          initBugType();
          SmallString<128> sbuf;
          llvm::raw_svector_ostream os(sbuf);
          unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
          os << "Allocated data should be released before another call to "
              << "the allocator: missing a call to '"
              << FunctionsToTrack[DIdx].Name
              << "'.";
          BugReport *Report = new BugReport(*BT, os.str(), N);
          Report->addVisitor(new SecKeychainBugVisitor(V));
          Report->addRange(ArgExpr->getSourceRange());
          Report->markInteresting(AS->Region);
          C.emitReport(Report);
        }
      }
    return;
  }

  // Is it a call to one of deallocator functions?
  idx = getTrackedFunctionIndex(funName, false);
  if (idx == InvalidIdx)
    return;

  // Check the argument to the deallocator.
  const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
  SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());

  // Undef is reported by another checker.
  if (ArgSVal.isUndef())
    return;

  SymbolRef ArgSM = ArgSVal.getAsLocSymbol();

  // If the argument is coming from the heap, globals, or unknown, do not
  // report it.
  bool RegionArgIsBad = false;
  if (!ArgSM) {
    if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
      return;
    RegionArgIsBad = true;
  }

  // Is the argument to the call being tracked?
  const AllocationState *AS = State->get<AllocatedData>(ArgSM);
  if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
    return;
  }
  // If trying to free data which has not been allocated yet, report as a bug.
  // TODO: We might want a more precise diagnostic for double free
  // (that would involve tracking all the freed symbols in the checker state).
  if (!AS || RegionArgIsBad) {
    // It is possible that this is a false positive - the argument might
    // have entered as an enclosing function parameter.
    if (isEnclosingFunctionParam(ArgExpr))
      return;

    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Trying to free data which has not been allocated.", N);
    Report->addRange(ArgExpr->getSourceRange());
    if (AS)
      Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  // Process functions which might deallocate.
  if (FunctionsToTrack[idx].Kind == PossibleAPI) {

    if (funName == "CFStringCreateWithBytesNoCopy") {
      const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
      // NULL ~ default deallocator, so warn.
      if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
          Expr::NPC_ValueDependentIsNotNull)) {
        const AllocationPair AP = std::make_pair(ArgSM, AS);
        generateDeallocatorMismatchReport(AP, ArgExpr, C);
        return;
      }
      // One of the default allocators, so warn.
      if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
        StringRef DeallocatorName = DE->getFoundDecl()->getName();
        if (DeallocatorName == "kCFAllocatorDefault" ||
            DeallocatorName == "kCFAllocatorSystemDefault" ||
            DeallocatorName == "kCFAllocatorMalloc") {
          const AllocationPair AP = std::make_pair(ArgSM, AS);
          generateDeallocatorMismatchReport(AP, ArgExpr, C);
          return;
        }
        // If kCFAllocatorNull, which does not deallocate, we still have to
        // find the deallocator.
        if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
          return;
      }
      // In all other cases, assume the user supplied a correct deallocator
      // that will free memory so stop tracking.
      State = State->remove<AllocatedData>(ArgSM);
      C.addTransition(State);
      return;
    }

    llvm_unreachable("We know of no other possible APIs.");
  }

  // The call is deallocating a value we previously allocated, so remove it
  // from the next state.
  State = State->remove<AllocatedData>(ArgSM);

  // Check if the proper deallocator is used.
  unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
  if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
    const AllocationPair AP = std::make_pair(ArgSM, AS);
    generateDeallocatorMismatchReport(AP, ArgExpr, C);
    return;
  }

  // If the buffer can be null and the return status can be an error,
  // report a bad call to free.
  if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
      !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Only call free if a valid (non-NULL) buffer was returned.", N);
    Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
    Report->addRange(ArgExpr->getSourceRange());
    Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  C.addTransition(State);
}
コード例 #7
0
ファイル: BugReporterVisitors.cpp プロジェクト: Godin/clang
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
                                        const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !ErrorNode)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  const ExplodedNode *N = ErrorNode;

  const Expr *Inner = 0;
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    Ex = Ex->IgnoreParenCasts();
    if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
      Inner = Ex;
  }

  if (IsArg) {
    assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    // Alternately, if we hit a known lvalue for the statement, we know we've
    // gone too far (though we can likely track the lvalue better anyway).
    do {
      const ProgramPoint &pp = N->getLocation();
      if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) {
        if (ps->getStmt() == S || ps->getStmt() == Inner)
          break;
      } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
        if (CEE->getCalleeContext()->getCallSite() == S ||
            CEE->getCalleeContext()->getCallSite() == Inner)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
    const MemRegion *R = 0;

    // First check if this is a DeclRefExpr for a C++ reference type.
    // For those, we want the location of the reference.
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        if (VD->getType()->isReferenceType()) {
          ProgramStateManager &StateMgr = state->getStateManager();
          MemRegionManager &MRMgr = StateMgr.getRegionManager();
          R = MRMgr.getVarRegion(VD, N->getLocationContext());
        }
      }
    }

    // For all other cases, find the location by scouring the ExplodedGraph.
    if (!R) {
      // Find the ExplodedNode where the lvalue (the value of 'Ex')
      // was computed.  We need this for getting the location value.
      const ExplodedNode *LVNode = N;
      while (LVNode) {
        if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
          if (P->getStmt() == Inner)
            break;
        }
        LVNode = LVNode->getFirstPred();
      }
      assert(LVNode && "Unable to find the lvalue node.");
      ProgramStateRef LVState = LVNode->getState();
      R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
    }

    if (R) {
      // Mark both the variable region and its contents as interesting.
      SVal V = state->getRawSVal(loc::MemRegionVal(R));

      // If the value matches the default for the variable region, that
      // might mean that it's been cleared out of the state. Fall back to
      // the full argument expression (with casts and such intact).
      if (IsArg) {
        bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
        if (!UseArgValue) {
          const SymbolRegionValue *SRV =
            dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
          if (SRV)
            UseArgValue = (SRV->getRegion() == R);
        }
        if (UseArgValue)
          V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
      }

      report.markInteresting(R);
      report.markInteresting(V);
      report.addVisitor(new UndefOrNullArgVisitor(R));

      if (isa<SymbolicRegion>(R)) {
        TrackConstraintBRVisitor *VI =
          new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
        report.addVisitor(VI);
      }

      // If the contents are symbolic, find out when they became null.
      if (V.getAsLocSymbol()) {
        BugReporterVisitor *ConstraintTracker =
          new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
        report.addVisitor(ConstraintTracker);

        // Add visitor, which will suppress inline defensive checks.
        if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) {
          BugReporterVisitor *IDCSuppressor =
            new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
                                                     ErrorNode);
          report.addVisitor(IDCSuppressor);
        }
      }

      if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
        report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
      return true;
    }
  }

  // If the expression is not an "lvalue expression", we can still
  // track the constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // If the value came from an inlined function call, we should at least make
  // sure that function isn't pruned in our output.
  if (const Expr *E = dyn_cast<Expr>(S))
    S = E->IgnoreParenCasts();
  ReturnVisitor::addVisitorIfNecessary(N, S, report);

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());
  // Is it a symbolic value?
  if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));

    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  }

  return true;
}
コード例 #8
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !N)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  if (IsArg) {
    assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    do {
      const ProgramPoint &pp = N->getLocation();
      if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
        if (ps->getStmt() == S)
          break;
      } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
        if (CEE->getCalleeContext()->getCallSite() == S)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        ProgramStateManager &StateMgr = state->getStateManager();
        MemRegionManager &MRMgr = StateMgr.getRegionManager();
        const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));

        // If the value matches the default for the variable region, that
        // might mean that it's been cleared out of the state. Fall back to
        // the full argument expression (with casts and such intact).
        if (IsArg) {
          bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
          if (!UseArgValue) {
            const SymbolRegionValue *SRV =
              dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
            if (SRV)
              UseArgValue = (SRV->getRegion() == R);
          }
          if (UseArgValue)
            V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
        }

        report.markInteresting(R);
        report.markInteresting(V);
        report.addVisitor(new UndefOrNullArgVisitor(R));

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return true;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));


    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    if (const Expr *E = dyn_cast<Expr>(S))
      S = E->IgnoreParenCasts();
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }

  return true;
}
コード例 #9
0
void PHPZPPCheckerImpl::checkPreCall(const CallEvent &Call,
                                     CheckerContext &C) const {
  initIdentifierInfo(C.getASTContext());

  unsigned offset;

  if (!Call.isGlobalCFunction())
    return;

  if (Call.getCalleeIdentifier() == IIzpp) {
    offset = 1;
  } else if (Call.getCalleeIdentifier() == IIzpp_ex) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp_ex) {
    offset = 3;
  } else {
    return;
  }

  if (TSRMBuild) {
    ++offset;
  }

  if (Call.getNumArgs() <= offset)
    // Something is really weird - this should be caught by the compiler
    return;

  const StringLiteral *format_spec_sl =
      getCStringLiteral(Call.getArgSVal(offset));
  if (!format_spec_sl) {
    // TODO need a good way to report this, even though this is no error
    std::cout << "Couldn't get format string looked at offset " << offset << std::endl;
    Call.dump();
    return;
  }
  const StringRef format_spec = format_spec_sl->getBytes();

  // Call.dump();
  for (StringRef::const_iterator modifier = format_spec.begin(),
                                 last_mod = format_spec.end();
       modifier != last_mod; ++modifier) {
//std::cout << "  I am checking for " << *modifier << std::endl;
    const PHPTypeRange range = map.equal_range(*modifier);

    if (range.first == range.second) {
      BugReport *R = new BugReport(
          *InvalidModifierBugType,
          std::string("Unknown modifier '") + *modifier + "'", C.addTransition());
      C.emitReport(R);
      return;
    }

    for (PHPTypeMap::const_iterator type = range.first; type != range.second;
         ++type) {
      if (!type->second) {
        // Current modifier doesn't need an argument, these are special things
        // like |, ! or /
        continue;
      }
      ++offset;
//std::cout << "    I need a " << *type->second << " (" << offset << ")" << std::endl;
      if (Call.getNumArgs() <= offset) {
        BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                     "Too few arguments for format specified",
                                     C.addTransition());
        C.emitReport(R);
//std::cout << "!!!!I am missing args! " << Call.getNumArgs() << "<=" << offset << std::endl;
        return;
      }

      SVal val = Call.getArgSVal(offset);
      if (!compareTypeWithSVal(val, *type->second, C)) {
        // TODO: Move error reporting here?

        // Even if there is a type mismatch we can continue, most of the time
        // this should be a simple mistake by the user, in rare cases the user
        // missed an argument and will get many subsequent errors
      }
    }
  }

  if (Call.getNumArgs() > 1 + offset) {
    BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                 "Too many arguments for format specified",
                                 C.addTransition());
    R->markInteresting(Call.getArgSVal(offset));
    C.emitReport(R);
  }
}
コード例 #10
0
void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report) {
  if (!S || !N)
    return;

  ProgramStateManager &StateMgr = N->getState()->getStateManager();

  // Walk through nodes until we get one that matches the statement exactly.
  while (N) {
    const ProgramPoint &pp = N->getLocation();
    if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
      if (ps->getStmt() == S)
        break;
    } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
      if (CEE->getCalleeContext()->getCallSite() == S)
        break;
    }
    N = N->getFirstPred();
  }

  if (!N)
    return;
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        const VarRegion *R =
          StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));
        report.markInteresting(R);
        report.markInteresting(V);

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    const MemRegion *Base = L->getRegion()->getBaseRegion();
    if (isa<SymbolicRegion>(Base)) {
      report.markInteresting(Base);
      report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base),
                                                      false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }
}
コード例 #11
0
std::shared_ptr<PathDiagnosticPiece>
RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
                                   const ExplodedNode *EndN, BugReport &BR) {

  // Tell the BugReporterContext to report cases when the tracked symbol is
  // assigned to different variables, etc.
  BR.markInteresting(Sym);

  // We are reporting a leak.  Walk up the graph to get to the first node where
  // the symbol appeared, and also get the first VarDecl that tracked object
  // is stored to.
  AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);

  const MemRegion* FirstBinding = AllocI.R;
  BR.markInteresting(AllocI.InterestingMethodContext);

  SourceManager& SM = BRC.getSourceManager();

  // Compute an actual location for the leak.  Sometimes a leak doesn't
  // occur at an actual statement (e.g., transition between blocks; end
  // of function) so we need to walk the graph and compute a real location.
  const ExplodedNode *LeakN = EndN;
  PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);

  std::string sbuf;
  llvm::raw_string_ostream os(sbuf);

  os << "Object leaked: ";

  Optional<std::string> RegionDescription = describeRegion(FirstBinding);
  if (RegionDescription) {
    os << "object allocated and stored into '" << *RegionDescription << '\'';
  } else {
    os << "allocated object of type '" << getPrettyTypeName(Sym->getType())
       << "'";
  }

  // Get the retain count.
  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
  assert(RV);

  if (RV->getKind() == RefVal::ErrorLeakReturned) {
    // FIXME: Per comments in rdar://6320065, "create" only applies to CF
    // objects.  Only "copy", "alloc", "retain" and "new" transfer ownership
    // to the caller for NS objects.
    const Decl *D = &EndN->getCodeDecl();

    os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
                                  : " is returned from a function ");

    if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
      os << "that is annotated as CF_RETURNS_NOT_RETAINED";
    } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
      os << "that is annotated as NS_RETURNS_NOT_RETAINED";
    } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
      os << "that is annotated as OS_RETURNS_NOT_RETAINED";
    } else {
      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
        if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
          os << "managed by Automatic Reference Counting";
        } else {
          os << "whose name ('" << MD->getSelector().getAsString()
             << "') does not start with "
                "'copy', 'mutableCopy', 'alloc' or 'new'."
                "  This violates the naming convention rules"
                " given in the Memory Management Guide for Cocoa";
        }
      } else {
        const FunctionDecl *FD = cast<FunctionDecl>(D);
        os << "whose name ('" << *FD
           << "') does not contain 'Copy' or 'Create'.  This violates the naming"
              " convention rules given in the Memory Management Guide for Core"
              " Foundation";
      }
    }
  } else {
    os << " is not referenced later in this execution path and has a retain "
          "count of +" << RV->getCount();
  }

  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
}
コード例 #12
0
std::shared_ptr<PathDiagnosticPiece>
RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
                               const ExplodedNode *EndN, BugReport &BR) {
  BR.markInteresting(Sym);
  return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
}