blob: 2ef6855ba6b7b2862c977cd5d97ba2a7f1104381 [file] [log] [blame]
Ted Kremenekef910042009-11-04 04:24:16 +00001//===--- UndefinedAssignmentChecker.h ---------------------------*- 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//
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000010// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
Ted Kremenekef910042009-11-04 04:24:16 +000011// checks for assigning undefined values.
12//
13//===----------------------------------------------------------------------===//
14
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000015#include "ClangSACheckers.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekef910042009-11-04 04:24:16 +000020
21using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000022using namespace ento;
Ted Kremenekef910042009-11-04 04:24:16 +000023
Zhongxing Xuf0b7fc82009-11-22 12:29:52 +000024namespace {
Kovarththanan Rajaratnam65c65662009-11-28 06:07:30 +000025class UndefinedAssignmentChecker
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000026 : public Checker<check::Bind> {
Ahmed Charlesb8984322014-03-07 20:03:18 +000027 mutable std::unique_ptr<BugType> BT;
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000028
Zhongxing Xuf0b7fc82009-11-22 12:29:52 +000029public:
Anna Zaks3e0f4152011-10-06 00:43:15 +000030 void checkBind(SVal location, SVal val, const Stmt *S,
31 CheckerContext &C) const;
Zhongxing Xuf0b7fc82009-11-22 12:29:52 +000032};
33}
34
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000035void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
Anna Zaks3e0f4152011-10-06 00:43:15 +000036 const Stmt *StoreE,
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +000037 CheckerContext &C) const {
Ted Kremenekef910042009-11-04 04:24:16 +000038 if (!val.isUndef())
39 return;
40
Anna Zaks03256462013-06-18 23:16:15 +000041 // Do not report assignments of uninitialized values inside swap functions.
42 // This should allow to swap partially uninitialized structs
43 // (radar://14129997)
44 if (const FunctionDecl *EnclosingFunctionDecl =
45 dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
46 if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
47 return;
48
Devin Coughline39bd402015-09-16 22:03:05 +000049 ExplodedNode *N = C.generateErrorNode();
Ted Kremenekef910042009-11-04 04:24:16 +000050
51 if (!N)
52 return;
53
Artem Dergachevf119bf92018-02-27 22:05:55 +000054 static const char *const DefaultMsg =
55 "Assigned value is garbage or undefined";
Ted Kremenekef910042009-11-04 04:24:16 +000056 if (!BT)
Artem Dergachevf119bf92018-02-27 22:05:55 +000057 BT.reset(new BuiltinBug(this, DefaultMsg));
Ted Kremenekef910042009-11-04 04:24:16 +000058
59 // Generate a report for this bug.
Artem Dergachevf119bf92018-02-27 22:05:55 +000060 llvm::SmallString<128> Str;
61 llvm::raw_svector_ostream OS(Str);
62
Craig Topper0dbb7832014-05-27 02:45:47 +000063 const Expr *ex = nullptr;
Ted Kremenekef910042009-11-04 04:24:16 +000064
Ted Kremenek07343c02010-09-02 00:56:20 +000065 while (StoreE) {
Roman Lebedev88b56ca2017-11-30 09:18:35 +000066 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(StoreE)) {
Artem Dergachevf119bf92018-02-27 22:05:55 +000067 OS << "The expression is an uninitialized value. "
Roman Lebedev88b56ca2017-11-30 09:18:35 +000068 "The computed value will also be garbage";
69
70 ex = U->getSubExpr();
71 break;
72 }
73
Ted Kremenek07343c02010-09-02 00:56:20 +000074 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
Ted Kremenek28ec56d2010-03-22 22:16:26 +000075 if (B->isCompoundAssignmentOp()) {
George Karpenkovd703ec92018-01-17 20:27:29 +000076 if (C.getSVal(B->getLHS()).isUndef()) {
Artem Dergachevf119bf92018-02-27 22:05:55 +000077 OS << "The left expression of the compound assignment is an "
Ted Kremenek28ec56d2010-03-22 22:16:26 +000078 "uninitialized value. The computed value will also be garbage";
79 ex = B->getLHS();
80 break;
81 }
82 }
Ted Kremenekef910042009-11-04 04:24:16 +000083
Ted Kremenek209e31b2009-11-05 00:42:23 +000084 ex = B->getRHS();
Ted Kremenek28ec56d2010-03-22 22:16:26 +000085 break;
86 }
87
Ted Kremenek07343c02010-09-02 00:56:20 +000088 if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
Ted Kremenek5ef32db2011-08-12 23:37:29 +000089 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
Ted Kremenek209e31b2009-11-05 00:42:23 +000090 ex = VD->getInit();
91 }
Ted Kremenek28ec56d2010-03-22 22:16:26 +000092
Artem Dergachevf119bf92018-02-27 22:05:55 +000093 if (const auto *CD =
94 dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
95 if (CD->isImplicit()) {
96 for (auto I : CD->inits()) {
97 if (I->getInit()->IgnoreImpCasts() == StoreE) {
98 OS << "Value assigned to field '" << I->getMember()->getName()
99 << "' in implicit constructor is garbage or undefined";
100 break;
101 }
102 }
103 }
104 }
105
Ted Kremenek28ec56d2010-03-22 22:16:26 +0000106 break;
Ted Kremenekef910042009-11-04 04:24:16 +0000107 }
108
Artem Dergachevf119bf92018-02-27 22:05:55 +0000109 if (OS.str().empty())
110 OS << DefaultMsg;
111
112 auto R = llvm::make_unique<BugReport>(*BT, OS.str(), N);
Ted Kremenek28ec56d2010-03-22 22:16:26 +0000113 if (ex) {
114 R->addRange(ex->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000115 bugreporter::trackNullOrUndefValue(N, ex, *R);
Ted Kremenek28ec56d2010-03-22 22:16:26 +0000116 }
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000117 C.emitReport(std::move(R));
Ted Kremenek28ec56d2010-03-22 22:16:26 +0000118}
Ted Kremenekef910042009-11-04 04:24:16 +0000119
Argyrios Kyrtzidis098874a2011-02-28 01:27:37 +0000120void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
121 mgr.registerChecker<UndefinedAssignmentChecker>();
122}