diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 84 | 
1 files changed, 61 insertions, 23 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index aa1ca6f2f809..c3736d7e5d71 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -141,8 +141,9 @@ public:                                           SVal val) const;    static ProgramStateRef InvalidateBuffer(CheckerContext &C, -                                              ProgramStateRef state, -                                              const Expr *Ex, SVal V); +                                          ProgramStateRef state, +                                          const Expr *Ex, SVal V, +                                          bool IsSourceBuffer);    static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,                                const MemRegion *MR); @@ -231,7 +232,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,        return NULL;      if (!BT_Null) -      BT_Null.reset(new BuiltinBug("Unix API", +      BT_Null.reset(new BuiltinBug(categories::UnixAPI,          "Null pointer argument in call to byte string function"));      SmallString<80> buf; @@ -525,7 +526,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,      return;    if (!BT_Overlap) -    BT_Overlap.reset(new BugType("Unix API", "Improper arguments")); +    BT_Overlap.reset(new BugType(categories::UnixAPI, "Improper arguments"));    // Generate a report for this bug.    BugReport *report =  @@ -661,7 +662,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,      if (Recorded)        return *Recorded;    } -   +    // Otherwise, get a new symbol and update the state.    SValBuilder &svalBuilder = C.getSValBuilder();    QualType sizeTy = svalBuilder.getContext().getSizeType(); @@ -669,8 +670,21 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,                                                      MR, Ex, sizeTy,                                                      C.blockCount()); -  if (!hypothetical) +  if (!hypothetical) { +    if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { +      // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 +      BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); +      const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); +      llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); +      const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, +                                                        fourInt); +      NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); +      SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, +                                                maxLength, sizeTy); +      state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); +    }      state = state->set<CStringLength>(MR, strLength); +  }    return strLength;  } @@ -689,7 +703,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,        if (ExplodedNode *N = C.addTransition(state)) {          if (!BT_NotCString) -          BT_NotCString.reset(new BuiltinBug("Unix API", +          BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,              "Argument is not a null-terminated string."));          SmallString<120> buf; @@ -749,7 +763,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,      if (ExplodedNode *N = C.addTransition(state)) {        if (!BT_NotCString) -        BT_NotCString.reset(new BuiltinBug("Unix API", +        BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,            "Argument is not a null-terminated string."));        SmallString<120> buf; @@ -796,8 +810,9 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,  }  ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, -                                                ProgramStateRef state, -                                                const Expr *E, SVal V) { +                                                 ProgramStateRef state, +                                                 const Expr *E, SVal V, +                                                 bool IsSourceBuffer) {    Optional<Loc> L = V.getAs<Loc>();    if (!L)      return state; @@ -817,8 +832,20 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,      // Invalidate this region.      const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); -    return state->invalidateRegions(R, E, C.blockCount(), LCtx, -                                    /*CausesPointerEscape*/ false); + +    bool CausesPointerEscape = false; +    RegionAndSymbolInvalidationTraits ITraits; +    // Invalidate and escape only indirect regions accessible through the source +    // buffer. +    if (IsSourceBuffer) { +      ITraits.setTrait(R,  +                       RegionAndSymbolInvalidationTraits::TK_PreserveContents); +      ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); +      CausesPointerEscape = true; +    } + +    return state->invalidateRegions(R, E, C.blockCount(), LCtx,  +                                    CausesPointerEscape, 0, 0, &ITraits);    }    // If we have a non-region value by chance, just remove the binding. @@ -955,13 +982,20 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,        state = state->BindExpr(CE, LCtx, destVal);      } -    // Invalidate the destination. +    // Invalidate the destination (regular invalidation without pointer-escaping +    // the address of the top-level region).      // FIXME: Even if we can't perfectly model the copy, we should see if we      // can use LazyCompoundVals to copy the source values into the destination.      // This would probably remove any existing bindings past the end of the      // copied region, but that's still an improvement over blank invalidation. -    state = InvalidateBuffer(C, state, Dest, -                             state->getSVal(Dest, C.getLocationContext())); +    state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest),  +                             /*IsSourceBuffer*/false); + +    // Invalidate the source (const-invalidation without const-pointer-escaping +    // the address of the top-level region). +    state = InvalidateBuffer(C, state, Source, C.getSVal(Source),  +                             /*IsSourceBuffer*/true); +      C.addTransition(state);    }  } @@ -1564,13 +1598,19 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,          Result = lastElement;      } -    // Invalidate the destination. This must happen before we set the C string -    // length because invalidation will clear the length. +    // Invalidate the destination (regular invalidation without pointer-escaping +    // the address of the top-level region). This must happen before we set the +    // C string length because invalidation will clear the length.      // FIXME: Even if we can't perfectly model the copy, we should see if we      // can use LazyCompoundVals to copy the source values into the destination.      // This would probably remove any existing bindings past the end of the      // string, but that's still an improvement over blank invalidation. -    state = InvalidateBuffer(C, state, Dst, *dstRegVal); +    state = InvalidateBuffer(C, state, Dst, *dstRegVal, +                             /*IsSourceBuffer*/false); + +    // Invalidate the source (const-invalidation without const-pointer-escaping +    // the address of the top-level region). +    state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true);      // Set the C string length of the destination, if we know it.      if (isBounded && !isAppending) { @@ -1792,7 +1832,8 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {      // Invalidate the search string, representing the change of one delimiter      // character to NUL. -    State = InvalidateBuffer(C, State, SearchStrPtr, Result); +    State = InvalidateBuffer(C, State, SearchStrPtr, Result, +                             /*IsSourceBuffer*/false);      // Overwrite the search string pointer. The new value is either an address      // further along in the same string, or NULL if there are no more tokens. @@ -2018,10 +2059,7 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,  #define REGISTER_CHECKER(name) \  void ento::register##name(CheckerManager &mgr) {\ -  static CStringChecker *TheChecker = 0; \ -  if (TheChecker == 0) \ -    TheChecker = mgr.registerChecker<CStringChecker>(); \ -  TheChecker->Filter.Check##name = true; \ +  mgr.registerChecker<CStringChecker>()->Filter.Check##name = true; \  }  REGISTER_CHECKER(CStringNullArg)  | 
