123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- //=== StringChecker.cpp -------------------------------------------*- C++ -*--//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the modeling of the std::basic_string type.
- // This involves checking preconditions of the operations and applying the
- // effects of the operations, e.g. their post-conditions.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
- #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
- using namespace clang;
- using namespace ento;
- namespace {
- class StringChecker : public Checker<check::PreCall> {
- BugType BT_Null{this, "Dereference of null pointer", categories::LogicError};
- mutable const FunctionDecl *StringConstCharPtrCtor = nullptr;
- mutable CanQualType SizeTypeTy;
- const CallDescription TwoParamStdStringCtor = {
- {"std", "basic_string", "basic_string"}, 2, 2};
- bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const;
- public:
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- };
- bool StringChecker::isCharToStringCtor(const CallEvent &Call,
- const ASTContext &ACtx) const {
- if (!TwoParamStdStringCtor.matches(Call))
- return false;
- const auto *FD = dyn_cast<FunctionDecl>(Call.getDecl());
- assert(FD);
- // See if we already cached it.
- if (StringConstCharPtrCtor && StringConstCharPtrCtor == FD)
- return true;
- // Verify that the parameters have the expected types:
- // - arg 1: `const CharT *`
- // - arg 2: some allocator - which is definately not `size_t`.
- const QualType Arg1Ty = Call.getArgExpr(0)->getType().getCanonicalType();
- const QualType Arg2Ty = Call.getArgExpr(1)->getType().getCanonicalType();
- if (!Arg1Ty->isPointerType())
- return false;
- // It makes sure that we don't select the `string(const char* p, size_t len)`
- // overload accidentally.
- if (Arg2Ty.getCanonicalType() == ACtx.getSizeType())
- return false;
- StringConstCharPtrCtor = FD; // Cache the decl of the right overload.
- return true;
- }
- void StringChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- if (!isCharToStringCtor(Call, C.getASTContext()))
- return;
- const auto Param = Call.getArgSVal(0).getAs<Loc>();
- if (!Param.hasValue())
- return;
- // We managed to constrain the parameter to non-null.
- ProgramStateRef NotNull, Null;
- std::tie(NotNull, Null) = C.getState()->assume(*Param);
- if (NotNull) {
- const auto Callback = [Param](PathSensitiveBugReport &BR) -> std::string {
- return BR.isInteresting(*Param) ? "Assuming the pointer is not null."
- : "";
- };
- // Emit note only if this operation constrained the pointer to be null.
- C.addTransition(NotNull, Null ? C.getNoteTag(Callback) : nullptr);
- return;
- }
- // We found a path on which the parameter is NULL.
- if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
- auto R = std::make_unique<PathSensitiveBugReport>(
- BT_Null, "The parameter must not be null", N);
- bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
- C.emitReport(std::move(R));
- }
- }
- } // end anonymous namespace
- void ento::registerStringChecker(CheckerManager &Mgr) {
- Mgr.registerChecker<StringChecker>();
- }
- bool ento::shouldRegisterStringChecker(const CheckerManager &) { return true; }
|