Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 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 | // |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 10 | // This defines UndefResultChecker, a builtin check in ExprEngine that |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 11 | // performs checks for undefined results of non-assignment binary operators. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
Argyrios Kyrtzidis | d4d3cee | 2011-02-28 01:27:22 +0000 | [diff] [blame] | 15 | #include "ClangSACheckers.h" |
Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 16 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
Argyrios Kyrtzidis | 6a5674f | 2011-03-01 01:16:21 +0000 | [diff] [blame] | 17 | #include "clang/StaticAnalyzer/Core/Checker.h" |
Argyrios Kyrtzidis | d4d3cee | 2011-02-28 01:27:22 +0000 | [diff] [blame] | 18 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
| 19 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
Ted Kremenek | f8cbac4 | 2011-02-10 01:03:03 +0000 | [diff] [blame] | 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
Benjamin Kramer | 4903802 | 2012-02-04 13:45:25 +0000 | [diff] [blame] | 21 | #include "llvm/ADT/SmallString.h" |
Benjamin Kramer | 444a130 | 2012-12-01 17:12:56 +0000 | [diff] [blame] | 22 | #include "llvm/Support/raw_ostream.h" |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 23 | |
| 24 | using namespace clang; |
Ted Kremenek | 98857c9 | 2010-12-23 07:20:52 +0000 | [diff] [blame] | 25 | using namespace ento; |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 26 | |
| 27 | namespace { |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 28 | class UndefResultChecker |
Argyrios Kyrtzidis | 6a5674f | 2011-03-01 01:16:21 +0000 | [diff] [blame] | 29 | : public Checker< check::PostStmt<BinaryOperator> > { |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 30 | |
Ahmed Charles | b898432 | 2014-03-07 20:03:18 +0000 | [diff] [blame] | 31 | mutable std::unique_ptr<BugType> BT; |
| 32 | |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 33 | public: |
Argyrios Kyrtzidis | d4d3cee | 2011-02-28 01:27:22 +0000 | [diff] [blame] | 34 | void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 35 | }; |
| 36 | } // end anonymous namespace |
| 37 | |
Argyrios Kyrtzidis | d4d3cee | 2011-02-28 01:27:22 +0000 | [diff] [blame] | 38 | void UndefResultChecker::checkPostStmt(const BinaryOperator *B, |
| 39 | CheckerContext &C) const { |
Ted Kremenek | 49b1e38 | 2012-01-26 21:29:00 +0000 | [diff] [blame] | 40 | ProgramStateRef state = C.getState(); |
Ted Kremenek | 632e3b7 | 2012-01-06 22:09:28 +0000 | [diff] [blame] | 41 | const LocationContext *LCtx = C.getLocationContext(); |
| 42 | if (state->getSVal(B, LCtx).isUndef()) { |
Anna Zaks | 0325646 | 2013-06-18 23:16:15 +0000 | [diff] [blame] | 43 | |
| 44 | // Do not report assignments of uninitialized values inside swap functions. |
| 45 | // This should allow to swap partially uninitialized structs |
| 46 | // (radar://14129997) |
| 47 | if (const FunctionDecl *EnclosingFunctionDecl = |
| 48 | dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) |
| 49 | if (C.getCalleeName(EnclosingFunctionDecl) == "swap") |
| 50 | return; |
| 51 | |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 52 | // Generate an error node. |
Devin Coughlin | e39bd40 | 2015-09-16 22:03:05 +0000 | [diff] [blame] | 53 | ExplodedNode *N = C.generateErrorNode(); |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 54 | if (!N) |
| 55 | return; |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 56 | |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 57 | if (!BT) |
Alexander Kornienko | 4aca9b1 | 2014-02-11 21:49:21 +0000 | [diff] [blame] | 58 | BT.reset( |
| 59 | new BuiltinBug(this, "Result of operation is garbage or undefined")); |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 60 | |
Dylan Noblesmith | 2c1dd27 | 2012-02-05 02:13:05 +0000 | [diff] [blame] | 61 | SmallString<256> sbuf; |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 62 | llvm::raw_svector_ostream OS(sbuf); |
Craig Topper | 0dbb783 | 2014-05-27 02:45:47 +0000 | [diff] [blame] | 63 | const Expr *Ex = nullptr; |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 64 | bool isLeft = true; |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 65 | |
Ted Kremenek | 632e3b7 | 2012-01-06 22:09:28 +0000 | [diff] [blame] | 66 | if (state->getSVal(B->getLHS(), LCtx).isUndef()) { |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 67 | Ex = B->getLHS()->IgnoreParenCasts(); |
| 68 | isLeft = true; |
| 69 | } |
Ted Kremenek | 632e3b7 | 2012-01-06 22:09:28 +0000 | [diff] [blame] | 70 | else if (state->getSVal(B->getRHS(), LCtx).isUndef()) { |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 71 | Ex = B->getRHS()->IgnoreParenCasts(); |
| 72 | isLeft = false; |
| 73 | } |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 74 | |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 75 | if (Ex) { |
| 76 | OS << "The " << (isLeft ? "left" : "right") |
| 77 | << " operand of '" |
| 78 | << BinaryOperator::getOpcodeStr(B->getOpcode()) |
| 79 | << "' is a garbage value"; |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 80 | } |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 81 | else { |
| 82 | // Neither operand was undefined, but the result is undefined. |
| 83 | OS << "The result of the '" |
| 84 | << BinaryOperator::getOpcodeStr(B->getOpcode()) |
| 85 | << "' expression is undefined"; |
| 86 | } |
Aaron Ballman | 8d3a7a5 | 2015-06-23 13:15:32 +0000 | [diff] [blame] | 87 | auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N); |
Ted Kremenek | 33e88a7 | 2009-11-29 06:37:44 +0000 | [diff] [blame] | 88 | if (Ex) { |
| 89 | report->addRange(Ex->getSourceRange()); |
Jordan Rose | a0f7d35 | 2012-08-28 00:50:51 +0000 | [diff] [blame] | 90 | bugreporter::trackNullOrUndefValue(N, Ex, *report); |
Ted Kremenek | 33e88a7 | 2009-11-29 06:37:44 +0000 | [diff] [blame] | 91 | } |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 92 | else |
Jordan Rose | a0f7d35 | 2012-08-28 00:50:51 +0000 | [diff] [blame] | 93 | bugreporter::trackNullOrUndefValue(N, B, *report); |
Ted Kremenek | 3a0678e | 2015-09-08 03:50:52 +0000 | [diff] [blame] | 94 | |
Aaron Ballman | 8d3a7a5 | 2015-06-23 13:15:32 +0000 | [diff] [blame] | 95 | C.emitReport(std::move(report)); |
Zhongxing Xu | c6123a1 | 2009-11-24 08:24:26 +0000 | [diff] [blame] | 96 | } |
| 97 | } |
Argyrios Kyrtzidis | d4d3cee | 2011-02-28 01:27:22 +0000 | [diff] [blame] | 98 | |
| 99 | void ento::registerUndefResultChecker(CheckerManager &mgr) { |
| 100 | mgr.registerChecker<UndefResultChecker>(); |
| 101 | } |