Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== StringChecker.cpp -------------------------------------------*- C++ -*--//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
//
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.
12
//
13
//===----------------------------------------------------------------------===//
14
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"
20
21
using namespace clang;
22
using namespace ento;
23
24
namespace {
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};
31
32
  bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const;
33
34
public:
35
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
36
};
37
38
bool StringChecker::isCharToStringCtor(const CallEvent &Call,
39
31.0k
                                       const ASTContext &ACtx) const {
40
31.0k
  if (!TwoParamStdStringCtor.matches(Call))
41
31.0k
    return false;
42
8
  const auto *FD = dyn_cast<FunctionDecl>(Call.getDecl());
43
8
  assert(FD);
44
45
  // See if we already cached it.
46
8
  if (StringConstCharPtrCtor && 
StringConstCharPtrCtor == FD7
)
47
6
    return true;
48
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
2
  const QualType Arg1Ty = Call.getArgExpr(0)->getType().getCanonicalType();
53
2
  const QualType Arg2Ty = Call.getArgExpr(1)->getType().getCanonicalType();
54
55
2
  if (!Arg1Ty->isPointerType())
56
1
    return false;
57
58
  // It makes sure that we don't select the `string(const char* p, size_t len)`
59
  // overload accidentally.
60
1
  if (Arg2Ty.getCanonicalType() == ACtx.getSizeType())
61
0
    return false;
62
63
1
  StringConstCharPtrCtor = FD; // Cache the decl of the right overload.
64
1
  return true;
65
1
}
66
67
void StringChecker::checkPreCall(const CallEvent &Call,
68
31.0k
                                 CheckerContext &C) const {
69
31.0k
  if (!isCharToStringCtor(Call, C.getASTContext()))
70
31.0k
    return;
71
7
  const auto Param = Call.getArgSVal(0).getAs<Loc>();
72
7
  if (!Param)
73
1
    return;
74
75
  // We managed to constrain the parameter to non-null.
76
6
  ProgramStateRef NotNull, Null;
77
6
  std::tie(NotNull, Null) = C.getState()->assume(*Param);
78
79
6
  if (NotNull) {
80
4
    const auto Callback = [Param](PathSensitiveBugReport &BR) -> std::string {
81
4
      return BR.isInteresting(*Param) ? 
"Assuming the pointer is not null."2
82
4
                                      : 
""2
;
83
4
    };
84
85
    // Emit note only if this operation constrained the pointer to be null.
86
4
    C.addTransition(NotNull, Null ? 
C.getNoteTag(Callback)3
:
nullptr1
);
87
4
    return;
88
4
  }
89
90
  // We found a path on which the parameter is NULL.
91
2
  if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
92
2
    auto R = std::make_unique<PathSensitiveBugReport>(
93
2
        BT_Null, "The parameter must not be null", N);
94
2
    bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
95
2
    C.emitReport(std::move(R));
96
2
  }
97
2
}
98
99
} // end anonymous namespace
100
101
66
void ento::registerStringChecker(CheckerManager &Mgr) {
102
66
  Mgr.registerChecker<StringChecker>();
103
66
}
104
105
132
bool ento::shouldRegisterStringChecker(const CheckerManager &) { return true; }