1 //=== StringChecker.cpp -------------------------------------------*- C++ -*--//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the modeling of the std::basic_string type.
10 // This involves checking preconditions of the operations and applying the
11 // effects of the operations, e.g. their post-conditions.
13 //===----------------------------------------------------------------------===//
15 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 using namespace clang
;
25 class StringChecker
: public Checker
<check::PreCall
> {
26 BugType BT_Null
{this, "Dereference of null pointer", categories::LogicError
};
27 mutable const FunctionDecl
*StringConstCharPtrCtor
= nullptr;
28 mutable CanQualType SizeTypeTy
;
29 const CallDescription TwoParamStdStringCtor
= {
30 {"std", "basic_string", "basic_string"}, 2, 2};
32 bool isCharToStringCtor(const CallEvent
&Call
, const ASTContext
&ACtx
) const;
35 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const;
38 bool StringChecker::isCharToStringCtor(const CallEvent
&Call
,
39 const ASTContext
&ACtx
) const {
40 if (!TwoParamStdStringCtor
.matches(Call
))
42 const auto *FD
= dyn_cast
<FunctionDecl
>(Call
.getDecl());
45 // See if we already cached it.
46 if (StringConstCharPtrCtor
&& StringConstCharPtrCtor
== FD
)
49 // Verify that the parameters have the expected types:
50 // - arg 1: `const CharT *`
51 // - arg 2: some allocator - which is definately not `size_t`.
52 const QualType Arg1Ty
= Call
.getArgExpr(0)->getType().getCanonicalType();
53 const QualType Arg2Ty
= Call
.getArgExpr(1)->getType().getCanonicalType();
55 if (!Arg1Ty
->isPointerType())
58 // It makes sure that we don't select the `string(const char* p, size_t len)`
59 // overload accidentally.
60 if (Arg2Ty
.getCanonicalType() == ACtx
.getSizeType())
63 StringConstCharPtrCtor
= FD
; // Cache the decl of the right overload.
67 void StringChecker::checkPreCall(const CallEvent
&Call
,
68 CheckerContext
&C
) const {
69 if (!isCharToStringCtor(Call
, C
.getASTContext()))
71 const auto Param
= Call
.getArgSVal(0).getAs
<Loc
>();
75 // We managed to constrain the parameter to non-null.
76 ProgramStateRef NotNull
, Null
;
77 std::tie(NotNull
, Null
) = C
.getState()->assume(*Param
);
80 const auto Callback
= [Param
](PathSensitiveBugReport
&BR
) -> std::string
{
81 return BR
.isInteresting(*Param
) ? "Assuming the pointer is not null."
85 // Emit note only if this operation constrained the pointer to be null.
86 C
.addTransition(NotNull
, Null
? C
.getNoteTag(Callback
) : nullptr);
90 // We found a path on which the parameter is NULL.
91 if (ExplodedNode
*N
= C
.generateErrorNode(C
.getState())) {
92 auto R
= std::make_unique
<PathSensitiveBugReport
>(
93 BT_Null
, "The parameter must not be null", N
);
94 bugreporter::trackExpressionValue(N
, Call
.getArgExpr(0), *R
);
95 C
.emitReport(std::move(R
));
99 } // end anonymous namespace
101 void ento::registerStringChecker(CheckerManager
&Mgr
) {
102 Mgr
.registerChecker
<StringChecker
>();
105 bool ento::shouldRegisterStringChecker(const CheckerManager
&) { return true; }