|
12 | 12 | //===----------------------------------------------------------------------===//
|
13 | 13 |
|
14 | 14 | #include "InterCheckerAPI.h"
|
| 15 | +#include "clang/Basic/Builtins.h" |
15 | 16 | #include "clang/Basic/CharInfo.h"
|
16 | 17 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
|
17 | 18 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
@@ -175,6 +176,8 @@ class CStringChecker : public Checker< eval::Call,
|
175 | 176 | std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
|
176 | 177 | {{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
|
177 | 178 | {{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
|
| 179 | + {{CDF_MaybeBuiltin, {"sprintf"}, 2}, &CStringChecker::evalSprintf}, |
| 180 | + {{CDF_MaybeBuiltin, {"snprintf"}, 2}, &CStringChecker::evalSnprintf}, |
178 | 181 | };
|
179 | 182 |
|
180 | 183 | // These require a bit of special handling.
|
@@ -228,6 +231,11 @@ class CStringChecker : public Checker< eval::Call,
|
228 | 231 | void evalMemset(CheckerContext &C, const CallExpr *CE) const;
|
229 | 232 | void evalBzero(CheckerContext &C, const CallExpr *CE) const;
|
230 | 233 |
|
| 234 | + void evalSprintf(CheckerContext &C, const CallExpr *CE) const; |
| 235 | + void evalSnprintf(CheckerContext &C, const CallExpr *CE) const; |
| 236 | + void evalSprintfCommon(CheckerContext &C, const CallExpr *CE, bool IsBounded, |
| 237 | + bool IsBuiltin) const; |
| 238 | + |
231 | 239 | // Utility methods
|
232 | 240 | std::pair<ProgramStateRef , ProgramStateRef >
|
233 | 241 | static assumeZero(CheckerContext &C,
|
@@ -2352,6 +2360,51 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
|
2352 | 2360 | C.addTransition(State);
|
2353 | 2361 | }
|
2354 | 2362 |
|
| 2363 | +void CStringChecker::evalSprintf(CheckerContext &C, const CallExpr *CE) const { |
| 2364 | + CurrentFunctionDescription = "'sprintf'"; |
| 2365 | + bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___sprintf_chk; |
| 2366 | + evalSprintfCommon(C, CE, /* IsBounded */ false, IsBI); |
| 2367 | +} |
| 2368 | + |
| 2369 | +void CStringChecker::evalSnprintf(CheckerContext &C, const CallExpr *CE) const { |
| 2370 | + CurrentFunctionDescription = "'snprintf'"; |
| 2371 | + bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___snprintf_chk; |
| 2372 | + evalSprintfCommon(C, CE, /* IsBounded */ true, IsBI); |
| 2373 | +} |
| 2374 | + |
| 2375 | +void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallExpr *CE, |
| 2376 | + bool IsBounded, bool IsBuiltin) const { |
| 2377 | + ProgramStateRef State = C.getState(); |
| 2378 | + DestinationArgExpr Dest = {CE->getArg(0), 0}; |
| 2379 | + |
| 2380 | + const auto NumParams = CE->getCalleeDecl()->getAsFunction()->getNumParams(); |
| 2381 | + assert(CE->getNumArgs() >= NumParams); |
| 2382 | + |
| 2383 | + const auto AllArguments = |
| 2384 | + llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs()); |
| 2385 | + const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams); |
| 2386 | + |
| 2387 | + for (const auto &[ArgIdx, ArgExpr] : VariadicArguments) { |
| 2388 | + // We consider only string buffers |
| 2389 | + if (const QualType type = ArgExpr->getType(); |
| 2390 | + !type->isAnyPointerType() || |
| 2391 | + !type->getPointeeType()->isAnyCharacterType()) |
| 2392 | + continue; |
| 2393 | + SourceArgExpr Source = {ArgExpr, unsigned(ArgIdx)}; |
| 2394 | + |
| 2395 | + // Ensure the buffers do not overlap. |
| 2396 | + SizeArgExpr SrcExprAsSizeDummy = {Source.Expression, Source.ArgumentIndex}; |
| 2397 | + State = CheckOverlap( |
| 2398 | + C, State, |
| 2399 | + (IsBounded ? SizeArgExpr{CE->getArg(1), 1} : SrcExprAsSizeDummy), Dest, |
| 2400 | + Source); |
| 2401 | + if (!State) |
| 2402 | + return; |
| 2403 | + } |
| 2404 | + |
| 2405 | + C.addTransition(State); |
| 2406 | +} |
| 2407 | + |
2355 | 2408 | //===----------------------------------------------------------------------===//
|
2356 | 2409 | // The driver method, and other Checker callbacks.
|
2357 | 2410 | //===----------------------------------------------------------------------===//
|
|
0 commit comments