1 //===--- UndefinedAssignmentChecker.h ---------------------------*- 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 defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
10 // checks for assigning undefined values.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20 using namespace clang
;
24 class UndefinedAssignmentChecker
25 : public Checker
<check::Bind
> {
26 const BugType BT
{this, "Assigned value is garbage or undefined"};
29 void checkBind(SVal location
, SVal val
, const Stmt
*S
,
30 CheckerContext
&C
) const;
34 void UndefinedAssignmentChecker::checkBind(SVal location
, SVal val
,
36 CheckerContext
&C
) const {
40 // Do not report assignments of uninitialized values inside swap functions.
41 // This should allow to swap partially uninitialized structs
42 if (const FunctionDecl
*EnclosingFunctionDecl
=
43 dyn_cast
<FunctionDecl
>(C
.getStackFrame()->getDecl()))
44 if (C
.getCalleeName(EnclosingFunctionDecl
) == "swap")
47 ExplodedNode
*N
= C
.generateErrorNode();
52 // Generate a report for this bug.
53 llvm::SmallString
<128> Str
;
54 llvm::raw_svector_ostream
OS(Str
);
56 const Expr
*ex
= nullptr;
59 if (const UnaryOperator
*U
= dyn_cast
<UnaryOperator
>(StoreE
)) {
60 OS
<< "The expression is an uninitialized value. "
61 "The computed value will also be garbage";
67 if (const BinaryOperator
*B
= dyn_cast
<BinaryOperator
>(StoreE
)) {
68 if (B
->isCompoundAssignmentOp()) {
69 if (C
.getSVal(B
->getLHS()).isUndef()) {
70 OS
<< "The left expression of the compound assignment is an "
71 "uninitialized value. The computed value will also be garbage";
81 if (const DeclStmt
*DS
= dyn_cast
<DeclStmt
>(StoreE
)) {
82 const VarDecl
*VD
= cast
<VarDecl
>(DS
->getSingleDecl());
87 dyn_cast
<CXXConstructorDecl
>(C
.getStackFrame()->getDecl())) {
88 if (CD
->isImplicit()) {
89 for (auto *I
: CD
->inits()) {
90 if (I
->getInit()->IgnoreImpCasts() == StoreE
) {
91 OS
<< "Value assigned to field '" << I
->getMember()->getName()
92 << "' in implicit constructor is garbage or undefined";
102 if (OS
.str().empty())
103 OS
<< BT
.getDescription();
105 auto R
= std::make_unique
<PathSensitiveBugReport
>(BT
, OS
.str(), N
);
107 R
->addRange(ex
->getSourceRange());
108 bugreporter::trackExpressionValue(N
, ex
, *R
);
110 C
.emitReport(std::move(R
));
113 void ento::registerUndefinedAssignmentChecker(CheckerManager
&mgr
) {
114 mgr
.registerChecker
<UndefinedAssignmentChecker
>();
117 bool ento::shouldRegisterUndefinedAssignmentChecker(const CheckerManager
&mgr
) {