diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 100 |
1 files changed, 67 insertions, 33 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 987cf65..9a6c013 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -26,9 +26,11 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" +#include <functional> using namespace clang; using namespace ento; +using namespace std::placeholders; namespace { struct AnyArgExpr { @@ -118,10 +120,14 @@ public: const LocationContext *LCtx, const CallEvent *Call) const; - typedef void (CStringChecker::*FnCheck)(CheckerContext &, - const CallExpr *) const; + using FnCheck = std::function<void(const CStringChecker *, CheckerContext &, + const CallExpr *)>; + CallDescriptionMap<FnCheck> Callbacks = { - {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, + {{CDF_MaybeBuiltin, "memcpy", 3}, + std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)}, + {{CDF_MaybeBuiltin, "wmemcpy", 3}, + std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)}, {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, @@ -135,7 +141,9 @@ public: {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, + {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength}, {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, + {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength}, {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, @@ -152,14 +160,14 @@ public: StdCopyBackward{{"std", "copy_backward"}, 3}; FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; - void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; + void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const; void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; void evalMemmove(CheckerContext &C, const CallExpr *CE) const; void evalBcopy(CheckerContext &C, const CallExpr *CE) const; void evalCopyCommon(CheckerContext &C, const CallExpr *CE, ProgramStateRef state, SizeArgExpr Size, DestinationArgExpr Dest, SourceArgExpr Source, - bool Restricted, bool IsMempcpy) const; + bool Restricted, bool IsMempcpy, bool IsWide) const; void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; @@ -240,13 +248,14 @@ public: AnyArgExpr Arg, SVal l) const; ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state, AnyArgExpr Buffer, SVal Element, - AccessKind Access) const; + AccessKind Access, bool IsWide = false) const; ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State, AnyArgExpr Buffer, SizeArgExpr Size, - AccessKind Access) const; + AccessKind Access, + bool IsWide = false) const; ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state, SizeArgExpr Size, AnyArgExpr First, - AnyArgExpr Second) const; + AnyArgExpr Second, bool IsWide = false) const; void emitOverlapBug(CheckerContext &C, ProgramStateRef state, const Stmt *First, @@ -329,7 +338,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, ProgramStateRef state, AnyArgExpr Buffer, SVal Element, - AccessKind Access) const { + AccessKind Access, + bool IsWide) const { // If a previous check has failed, propagate the failure. if (!state) @@ -344,17 +354,36 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, if (!ER) return state; - if (ER->getValueType() != C.getASTContext().CharTy) - return state; + SValBuilder &svalBuilder = C.getSValBuilder(); + ASTContext &Ctx = svalBuilder.getContext(); + + // Get the index of the accessed element. + NonLoc Idx = ER->getIndex(); + + if (!IsWide) { + if (ER->getValueType() != Ctx.CharTy) + return state; + } else { + if (ER->getValueType() != Ctx.WideCharTy) + return state; + + QualType SizeTy = Ctx.getSizeType(); + NonLoc WideSize = + svalBuilder + .makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(), + SizeTy) + .castAs<NonLoc>(); + SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy); + if (Offset.isUnknown()) + return state; + Idx = Offset.castAs<NonLoc>(); + } // Get the size of the array. const auto *superReg = cast<SubRegion>(ER->getSuperRegion()); DefinedOrUnknownSVal Size = getDynamicExtent(state, superReg, C.getSValBuilder()); - // Get the index of the accessed element. - DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); - ProgramStateRef StInBound, StOutBound; std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size); if (StOutBound && !StInBound) { @@ -385,11 +414,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, return StInBound; } -ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, - ProgramStateRef State, - AnyArgExpr Buffer, - SizeArgExpr Size, - AccessKind Access) const { +ProgramStateRef +CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State, + AnyArgExpr Buffer, SizeArgExpr Size, + AccessKind Access, bool IsWide) const { // If a previous check has failed, propagate the failure. if (!State) return nullptr; @@ -398,7 +426,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, ASTContext &Ctx = svalBuilder.getContext(); QualType SizeTy = Size.Expression->getType(); - QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); + QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy); // Check that the first buffer is non-null. SVal BufVal = C.getSVal(Buffer.Expression); @@ -432,7 +460,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, SVal BufEnd = svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy); - State = CheckLocation(C, State, Buffer, BufEnd, Access); + State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide); // If the buffer isn't large enough, abort. if (!State) @@ -446,7 +474,8 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, ProgramStateRef state, SizeArgExpr Size, AnyArgExpr First, - AnyArgExpr Second) const { + AnyArgExpr Second, + bool IsWide) const { if (!Filter.CheckCStringBufferOverlap) return state; @@ -525,7 +554,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, // Convert the first buffer's start address to char*. // Bail out if the cast fails. ASTContext &Ctx = svalBuilder.getContext(); - QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); + QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy); SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType()); Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); @@ -1161,7 +1190,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, ProgramStateRef state, SizeArgExpr Size, DestinationArgExpr Dest, SourceArgExpr Source, bool Restricted, - bool IsMempcpy) const { + bool IsMempcpy, bool IsWide) const { CurrentFunctionDescription = "memory copy function"; // See if the size argument is zero. @@ -1204,11 +1233,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, return; // Ensure the accesses are valid and that the buffers do not overlap. - state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write); - state = CheckBufferAccess(C, state, Source, Size, AccessKind::read); + state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide); + state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide); if (Restricted) - state = CheckOverlap(C, state, Size, Dest, Source); + state = CheckOverlap(C, state, Size, Dest, Source, IsWide); if (!state) return; @@ -1258,7 +1287,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, } } -void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { +void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE, + bool IsWide) const { // void *memcpy(void *restrict dst, const void *restrict src, size_t n); // The return value is the address of the destination buffer. DestinationArgExpr Dest = {CE->getArg(0), 0}; @@ -1269,7 +1299,8 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { constexpr bool IsRestricted = true; constexpr bool IsMempcpy = false; - evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy); + evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy, + IsWide); } void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { @@ -1281,7 +1312,8 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { constexpr bool IsRestricted = true; constexpr bool IsMempcpy = true; - evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); + evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy, + false); } void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { @@ -1293,7 +1325,8 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { constexpr bool IsRestricted = false; constexpr bool IsMempcpy = false; - evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); + evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy, + false); } void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { @@ -1304,7 +1337,8 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { constexpr bool IsRestricted = false; constexpr bool IsMempcpy = false; - evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); + evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy, + false); } void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { @@ -2336,7 +2370,7 @@ bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { // Check and evaluate the call. const auto *CE = cast<CallExpr>(Call.getOriginExpr()); - (this->*Callback)(C, CE); + Callback(this, C, CE); // If the evaluate call resulted in no change, chain to the next eval call // handler. |