1 //== ReturnUndefChecker.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 defines ReturnUndefChecker, which is a path-sensitive
10 // check which looks for undefined or garbage values being returned to the
13 //===----------------------------------------------------------------------===//
15 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 using namespace clang
;
26 class ReturnUndefChecker
: public Checker
< check::PreStmt
<ReturnStmt
> > {
27 mutable std::unique_ptr
<BugType
> BT_Undef
;
28 mutable std::unique_ptr
<BugType
> BT_NullReference
;
30 void emitUndef(CheckerContext
&C
, const Expr
*RetE
) const;
31 void checkReference(CheckerContext
&C
, const Expr
*RetE
,
32 DefinedOrUnknownSVal RetVal
) const;
34 void checkPreStmt(const ReturnStmt
*RS
, CheckerContext
&C
) const;
38 void ReturnUndefChecker::checkPreStmt(const ReturnStmt
*RS
,
39 CheckerContext
&C
) const {
40 const Expr
*RetE
= RS
->getRetValue();
43 SVal RetVal
= C
.getSVal(RetE
);
45 const StackFrameContext
*SFC
= C
.getStackFrame();
46 QualType RT
= CallEvent::getDeclaredResultType(SFC
->getDecl());
48 if (RetVal
.isUndef()) {
49 // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal
50 // to be returned in functions returning void to support this pattern:
57 if (!RT
.isNull() && RT
->isVoidType())
60 // Not all blocks have explicitly-specified return types; if the return type
61 // is not available, but the return value expression has 'void' type, assume
62 // Sema already checked it.
63 if (RT
.isNull() && isa
<BlockDecl
>(SFC
->getDecl()) &&
64 RetE
->getType()->isVoidType())
74 if (RT
->isReferenceType()) {
75 checkReference(C
, RetE
, RetVal
.castAs
<DefinedOrUnknownSVal
>());
80 static void emitBug(CheckerContext
&C
, BugType
&BT
, StringRef Msg
,
81 const Expr
*RetE
, const Expr
*TrackingE
= nullptr) {
82 ExplodedNode
*N
= C
.generateErrorNode();
86 auto Report
= std::make_unique
<PathSensitiveBugReport
>(BT
, Msg
, N
);
88 Report
->addRange(RetE
->getSourceRange());
89 bugreporter::trackExpressionValue(N
, TrackingE
? TrackingE
: RetE
, *Report
);
91 C
.emitReport(std::move(Report
));
94 void ReturnUndefChecker::emitUndef(CheckerContext
&C
, const Expr
*RetE
) const {
96 BT_Undef
.reset(new BugType(this, "Garbage return value"));
97 emitBug(C
, *BT_Undef
, "Undefined or garbage value returned to caller", RetE
);
100 void ReturnUndefChecker::checkReference(CheckerContext
&C
, const Expr
*RetE
,
101 DefinedOrUnknownSVal RetVal
) const {
102 ProgramStateRef StNonNull
, StNull
;
103 std::tie(StNonNull
, StNull
) = C
.getState()->assume(RetVal
);
106 // Going forward, assume the location is non-null.
107 C
.addTransition(StNonNull
);
111 // The return value is known to be null. Emit a bug report.
112 if (!BT_NullReference
)
113 BT_NullReference
.reset(new BugType(this, "Returning null reference"));
115 emitBug(C
, *BT_NullReference
, BT_NullReference
->getDescription(), RetE
,
116 bugreporter::getDerefExpr(RetE
));
119 void ento::registerReturnUndefChecker(CheckerManager
&mgr
) {
120 mgr
.registerChecker
<ReturnUndefChecker
>();
123 bool ento::shouldRegisterReturnUndefChecker(const CheckerManager
&mgr
) {