aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp53
1 files changed, 53 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 12b948a..01a3550 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "InterCheckerAPI.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/CharInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -175,6 +176,8 @@ public:
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
{{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
+ {{CDF_MaybeBuiltin, {"sprintf"}, 2}, &CStringChecker::evalSprintf},
+ {{CDF_MaybeBuiltin, {"snprintf"}, 2}, &CStringChecker::evalSnprintf},
};
// These require a bit of special handling.
@@ -228,6 +231,11 @@ public:
void evalMemset(CheckerContext &C, const CallExpr *CE) const;
void evalBzero(CheckerContext &C, const CallExpr *CE) const;
+ void evalSprintf(CheckerContext &C, const CallExpr *CE) const;
+ void evalSnprintf(CheckerContext &C, const CallExpr *CE) const;
+ void evalSprintfCommon(CheckerContext &C, const CallExpr *CE, bool IsBounded,
+ bool IsBuiltin) const;
+
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
static assumeZero(CheckerContext &C,
@@ -2352,6 +2360,51 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
C.addTransition(State);
}
+void CStringChecker::evalSprintf(CheckerContext &C, const CallExpr *CE) const {
+ CurrentFunctionDescription = "'sprintf'";
+ bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___sprintf_chk;
+ evalSprintfCommon(C, CE, /* IsBounded */ false, IsBI);
+}
+
+void CStringChecker::evalSnprintf(CheckerContext &C, const CallExpr *CE) const {
+ CurrentFunctionDescription = "'snprintf'";
+ bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___snprintf_chk;
+ evalSprintfCommon(C, CE, /* IsBounded */ true, IsBI);
+}
+
+void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallExpr *CE,
+ bool IsBounded, bool IsBuiltin) const {
+ ProgramStateRef State = C.getState();
+ DestinationArgExpr Dest = {CE->getArg(0), 0};
+
+ const auto NumParams = CE->getCalleeDecl()->getAsFunction()->getNumParams();
+ assert(CE->getNumArgs() >= NumParams);
+
+ const auto AllArguments =
+ llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
+ const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
+
+ for (const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
+ // We consider only string buffers
+ if (const QualType type = ArgExpr->getType();
+ !type->isAnyPointerType() ||
+ !type->getPointeeType()->isAnyCharacterType())
+ continue;
+ SourceArgExpr Source = {ArgExpr, unsigned(ArgIdx)};
+
+ // Ensure the buffers do not overlap.
+ SizeArgExpr SrcExprAsSizeDummy = {Source.Expression, Source.ArgumentIndex};
+ State = CheckOverlap(
+ C, State,
+ (IsBounded ? SizeArgExpr{CE->getArg(1), 1} : SrcExprAsSizeDummy), Dest,
+ Source);
+ if (!State)
+ return;
+ }
+
+ C.addTransition(State);
+}
+
//===----------------------------------------------------------------------===//
// The driver method, and other Checker callbacks.
//===----------------------------------------------------------------------===//