xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp (revision 49b1e38e4bee0f0c6f8b49e1a62d5284084e09e7)
1 //=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This defines UndefResultChecker, a builtin check in ExprEngine that
11 // performs checks for undefined results of non-assignment binary operators.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 class UndefResultChecker
27   : public Checker< check::PostStmt<BinaryOperator> > {
28 
29   mutable llvm::OwningPtr<BugType> BT;
30 
31 public:
32   void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
33 };
34 } // end anonymous namespace
35 
36 void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
37                                        CheckerContext &C) const {
38   ProgramStateRef state = C.getState();
39   const LocationContext *LCtx = C.getLocationContext();
40   if (state->getSVal(B, LCtx).isUndef()) {
41     // Generate an error node.
42     ExplodedNode *N = C.generateSink();
43     if (!N)
44       return;
45 
46     if (!BT)
47       BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
48 
49     llvm::SmallString<256> sbuf;
50     llvm::raw_svector_ostream OS(sbuf);
51     const Expr *Ex = NULL;
52     bool isLeft = true;
53 
54     if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
55       Ex = B->getLHS()->IgnoreParenCasts();
56       isLeft = true;
57     }
58     else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
59       Ex = B->getRHS()->IgnoreParenCasts();
60       isLeft = false;
61     }
62 
63     if (Ex) {
64       OS << "The " << (isLeft ? "left" : "right")
65          << " operand of '"
66          << BinaryOperator::getOpcodeStr(B->getOpcode())
67          << "' is a garbage value";
68     }
69     else {
70       // Neither operand was undefined, but the result is undefined.
71       OS << "The result of the '"
72          << BinaryOperator::getOpcodeStr(B->getOpcode())
73          << "' expression is undefined";
74     }
75     BugReport *report = new BugReport(*BT, OS.str(), N);
76     if (Ex) {
77       report->addRange(Ex->getSourceRange());
78       report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
79     }
80     else
81       report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B));
82     C.EmitReport(report);
83   }
84 }
85 
86 void ento::registerUndefResultChecker(CheckerManager &mgr) {
87   mgr.registerChecker<UndefResultChecker>();
88 }
89