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 mutable std::unique_ptr
<BugType
> BT
;
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 static const char *const DefaultMsg
=
53 "Assigned value is garbage or undefined";
55 BT
.reset(new BugType(this, DefaultMsg
));
57 // Generate a report for this bug.
58 llvm::SmallString
<128> Str
;
59 llvm::raw_svector_ostream
OS(Str
);
61 const Expr
*ex
= nullptr;
64 if (const UnaryOperator
*U
= dyn_cast
<UnaryOperator
>(StoreE
)) {
65 OS
<< "The expression is an uninitialized value. "
66 "The computed value will also be garbage";
72 if (const BinaryOperator
*B
= dyn_cast
<BinaryOperator
>(StoreE
)) {
73 if (B
->isCompoundAssignmentOp()) {
74 if (C
.getSVal(B
->getLHS()).isUndef()) {
75 OS
<< "The left expression of the compound assignment is an "
76 "uninitialized value. The computed value will also be garbage";
86 if (const DeclStmt
*DS
= dyn_cast
<DeclStmt
>(StoreE
)) {
87 const VarDecl
*VD
= cast
<VarDecl
>(DS
->getSingleDecl());
92 dyn_cast
<CXXConstructorDecl
>(C
.getStackFrame()->getDecl())) {
93 if (CD
->isImplicit()) {
94 for (auto *I
: CD
->inits()) {
95 if (I
->getInit()->IgnoreImpCasts() == StoreE
) {
96 OS
<< "Value assigned to field '" << I
->getMember()->getName()
97 << "' in implicit constructor is garbage or undefined";
107 if (OS
.str().empty())
110 auto R
= std::make_unique
<PathSensitiveBugReport
>(*BT
, OS
.str(), N
);
112 R
->addRange(ex
->getSourceRange());
113 bugreporter::trackExpressionValue(N
, ex
, *R
);
115 C
.emitReport(std::move(R
));
118 void ento::registerUndefinedAssignmentChecker(CheckerManager
&mgr
) {
119 mgr
.registerChecker
<UndefinedAssignmentChecker
>();
122 bool ento::shouldRegisterUndefinedAssignmentChecker(const CheckerManager
&mgr
) {