Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -39,6 +39,7 @@ BT_NotCString, BT_AdditionOverflow; mutable const char *CurrentFunctionDescription; + static bool isSrcUninit; public: /// The filter is used to filter out the diagnostics which are not enabled by @@ -195,6 +196,8 @@ NonLoc right) const; }; +bool CStringChecker::isSrcUninit = 0; + } //end anonymous namespace REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) @@ -667,6 +670,12 @@ const SVal *Recorded = state->get(MR); if (Recorded) return *Recorded; + else { + // set isSrcUninit, so that we will try to evaluate size of src for strcpy fn + // if we cannot calculate size in strcpy function + // we will use the symbolic value generated after this. + isSrcUninit = 1; + } } // Otherwise, get a new symbol and update the state. @@ -1360,6 +1369,35 @@ QualType cmpTy = svalBuilder.getConditionType(); QualType sizeTy = svalBuilder.getContext().getSizeType(); + // If we could not record proper string length, try to get the size of src buffer + if (isSrcUninit && !isAppending && !isBounded && !returnEnd) { + isSrcUninit = 0; + const MemRegion *R = srcVal.getAsRegion(); + if (!R) + return; + + const ElementRegion *ER = dyn_cast(R); + SVal retsize = UnknownVal(); + if (ER) { + assert(ER->getValueType() == C.getASTContext().CharTy && + "Should only be called with char* ElementRegions"); + + // Get the size of the array. + const SubRegion *superReg = cast(ER->getSuperRegion()); + SVal Extent = svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); + DefinedOrUnknownSVal strSize = cast(Extent); + retsize = strSize; + + NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs(); + NonLoc *knownStrSize = cast(&retsize); + retsize = (svalBuilder.evalBinOpNN(state, BO_Sub, *knownStrSize, One, sizeTy)); + + if (!(retsize.isUnknown()) && !(retsize.isUndef())) { + strLength = retsize; + } + } + } + // These two values allow checking two kinds of errors: // - actual overflows caused by a source that doesn't fit in the destination // - potential overflows caused by a bound that could exceed the destination Index: test/Analysis/string.c =================================================================== --- test/Analysis/string.c +++ test/Analysis/string.c @@ -303,6 +303,24 @@ strcpy(x, y); // no-warning } +void strcpy_src_uninit_overflow1() { + char x[3] = "abc"; + char y[4]; + strcpy(x,y); // expected-warning{{String copy function overflows destination buffer}} +} + +void strcpy_src_uninit_overflow2() { + char x[3] = "abc"; + char y[3]; + strcpy(x,y); // no-warning +} + +void strcpy_src_uninit_overflow3() { + char x[3] = "abc"; + char y[2]; + strcpy(x,y); // no-warning +} + //===----------------------------------------------------------------------=== // stpcpy() //===----------------------------------------------------------------------===