Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -196,9 +196,8 @@ void evalBzero(CheckerContext &C, const CallExpr *CE) const; // Utility methods - std::pair - static assumeZero(CheckerContext &C, - ProgramStateRef state, SVal V, QualType Ty); + static std::pair + assumeZero(ProgramStateRef State, SVal V); static ProgramStateRef setCStringLength(ProgramStateRef state, const MemRegion *MR, @@ -279,16 +278,18 @@ // Individual checks and utility methods. //===----------------------------------------------------------------------===// -std::pair -CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, - QualType Ty) { - Optional val = V.getAs(); - if (!val) - return std::pair(state, state); +std::pair +CStringChecker::assumeZero(ProgramStateRef State, SVal V) { + auto States = std::make_pair(State, State); - SValBuilder &svalBuilder = C.getSValBuilder(); - DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); - return state->assume(svalBuilder.evalEQ(state, *val, zero)); + Optional Val = V.getAs(); + // FIXME: We should understand how LazyCompoundVal can be possible here, + // fix the root cause and get rid of this check. + if (Val && !V.getAs()) + // Returned pair shall be {null, non-null} so reorder states. + std::tie(States.second, States.first) = State->assume(*Val); + + return States; } ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, @@ -299,8 +300,7 @@ return nullptr; ProgramStateRef stateNull, stateNonNull; - std::tie(stateNull, stateNonNull) = - assumeZero(C, State, l, Arg.Expression->getType()); + std::tie(stateNull, stateNonNull) = assumeZero(State, l); if (stateNull && !stateNonNull) { if (Filter.CheckCStringNullArg) { @@ -1071,8 +1071,7 @@ CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); ProgramStateRef StateNullChar, StateNonNullChar; - std::tie(StateNullChar, StateNonNullChar) = - assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); + std::tie(StateNullChar, StateNonNullChar) = assumeZero(State, CharVal); if (StateWholeReg && !StateNotWholeReg && StateNullChar && !StateNonNullChar) { @@ -1133,11 +1132,9 @@ // See if the size argument is zero. const LocationContext *LCtx = C.getLocationContext(); SVal sizeVal = state->getSVal(Size.Expression, LCtx); - QualType sizeTy = Size.Expression->getType(); ProgramStateRef stateZeroSize, stateNonZeroSize; - std::tie(stateZeroSize, stateNonZeroSize) = - assumeZero(C, state, sizeVal, sizeTy); + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(state, sizeVal); // Get the value of the Dest. SVal destVal = state->getSVal(Dest.Expression, LCtx); @@ -1287,11 +1284,9 @@ // See if the size argument is zero. SVal sizeVal = State->getSVal(Size.Expression, LCtx); - QualType sizeTy = Size.Expression->getType(); ProgramStateRef stateZeroSize, stateNonZeroSize; - std::tie(stateZeroSize, stateNonZeroSize) = - assumeZero(C, State, sizeVal, sizeTy); + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(State, sizeVal); // If the size can be zero, the result will be 0 in that case, and we don't // have to check either of the buffers. @@ -1367,8 +1362,7 @@ SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); ProgramStateRef stateZeroSize, stateNonZeroSize; - std::tie(stateZeroSize, stateNonZeroSize) = - assumeZero(C, state, maxlenVal, maxlenExpr->getType()); + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(state, maxlenVal); // If the size can be zero, the result will be 0 in that case, and we don't // have to check the string itself. @@ -1706,7 +1700,7 @@ // as the last element accessed, so n == 0 is problematic. ProgramStateRef StateZeroSize, StateNonZeroSize; std::tie(StateZeroSize, StateNonZeroSize) = - assumeZero(C, state, *lenValNL, sizeTy); + assumeZero(state, *lenValNL); // If the size is known to be zero, we're done. if (StateZeroSize && !StateNonZeroSize) { @@ -2177,10 +2171,9 @@ // See if the size argument is zero. const LocationContext *LCtx = C.getLocationContext(); SVal SizeVal = C.getSVal(Size.Expression); - QualType SizeTy = Size.Expression->getType(); ProgramStateRef ZeroSize, NonZeroSize; - std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy); + std::tie(ZeroSize, NonZeroSize) = assumeZero(State, SizeVal); // Get the value of the memory area. SVal BufferPtrVal = C.getSVal(Buffer.Expression); @@ -2225,11 +2218,9 @@ // See if the size argument is zero. SVal SizeVal = C.getSVal(Size.Expression); - QualType SizeTy = Size.Expression->getType(); ProgramStateRef StateZeroSize, StateNonZeroSize; - std::tie(StateZeroSize, StateNonZeroSize) = - assumeZero(C, State, SizeVal, SizeTy); + std::tie(StateZeroSize, StateNonZeroSize) = assumeZero(State, SizeVal); // If the size is zero, there won't be any actual memory access, // In this case we just return. Index: clang/test/Analysis/string.c =================================================================== --- clang/test/Analysis/string.c +++ clang/test/Analysis/string.c @@ -363,6 +363,15 @@ strcpy(x, y); // no-warning } +// PR37503 +void *func_strcpy_no_assertion(); +char ***ptr_strcpy_no_assertion; +void strcpy_no_assertion() { + *(unsigned char **)ptr_strcpy_no_assertion = (unsigned char *)(func_strcpy_no_assertion()); + char c; + strcpy(**ptr_strcpy_no_assertion, &c); // no-assertion +} + //===----------------------------------------------------------------------=== // stpcpy() //===----------------------------------------------------------------------===