1f4a2713aSLionel Sambuc //===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
11f4a2713aSLionel Sambuc // checks for assigning undefined values.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc
15f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
16f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20f4a2713aSLionel Sambuc
21f4a2713aSLionel Sambuc using namespace clang;
22f4a2713aSLionel Sambuc using namespace ento;
23f4a2713aSLionel Sambuc
24f4a2713aSLionel Sambuc namespace {
25f4a2713aSLionel Sambuc class UndefinedAssignmentChecker
26f4a2713aSLionel Sambuc : public Checker<check::Bind> {
27*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<BugType> BT;
28f4a2713aSLionel Sambuc
29f4a2713aSLionel Sambuc public:
30f4a2713aSLionel Sambuc void checkBind(SVal location, SVal val, const Stmt *S,
31f4a2713aSLionel Sambuc CheckerContext &C) const;
32f4a2713aSLionel Sambuc };
33f4a2713aSLionel Sambuc }
34f4a2713aSLionel Sambuc
checkBind(SVal location,SVal val,const Stmt * StoreE,CheckerContext & C) const35f4a2713aSLionel Sambuc void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
36f4a2713aSLionel Sambuc const Stmt *StoreE,
37f4a2713aSLionel Sambuc CheckerContext &C) const {
38f4a2713aSLionel Sambuc if (!val.isUndef())
39f4a2713aSLionel Sambuc return;
40f4a2713aSLionel Sambuc
41f4a2713aSLionel Sambuc // Do not report assignments of uninitialized values inside swap functions.
42f4a2713aSLionel Sambuc // This should allow to swap partially uninitialized structs
43f4a2713aSLionel Sambuc // (radar://14129997)
44f4a2713aSLionel Sambuc if (const FunctionDecl *EnclosingFunctionDecl =
45f4a2713aSLionel Sambuc dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
46f4a2713aSLionel Sambuc if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
47f4a2713aSLionel Sambuc return;
48f4a2713aSLionel Sambuc
49f4a2713aSLionel Sambuc ExplodedNode *N = C.generateSink();
50f4a2713aSLionel Sambuc
51f4a2713aSLionel Sambuc if (!N)
52f4a2713aSLionel Sambuc return;
53f4a2713aSLionel Sambuc
54f4a2713aSLionel Sambuc const char *str = "Assigned value is garbage or undefined";
55f4a2713aSLionel Sambuc
56f4a2713aSLionel Sambuc if (!BT)
57*0a6a1f1dSLionel Sambuc BT.reset(new BuiltinBug(this, str));
58f4a2713aSLionel Sambuc
59f4a2713aSLionel Sambuc // Generate a report for this bug.
60*0a6a1f1dSLionel Sambuc const Expr *ex = nullptr;
61f4a2713aSLionel Sambuc
62f4a2713aSLionel Sambuc while (StoreE) {
63f4a2713aSLionel Sambuc if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
64f4a2713aSLionel Sambuc if (B->isCompoundAssignmentOp()) {
65f4a2713aSLionel Sambuc ProgramStateRef state = C.getState();
66f4a2713aSLionel Sambuc if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
67f4a2713aSLionel Sambuc str = "The left expression of the compound assignment is an "
68f4a2713aSLionel Sambuc "uninitialized value. The computed value will also be garbage";
69f4a2713aSLionel Sambuc ex = B->getLHS();
70f4a2713aSLionel Sambuc break;
71f4a2713aSLionel Sambuc }
72f4a2713aSLionel Sambuc }
73f4a2713aSLionel Sambuc
74f4a2713aSLionel Sambuc ex = B->getRHS();
75f4a2713aSLionel Sambuc break;
76f4a2713aSLionel Sambuc }
77f4a2713aSLionel Sambuc
78f4a2713aSLionel Sambuc if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
79f4a2713aSLionel Sambuc const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
80f4a2713aSLionel Sambuc ex = VD->getInit();
81f4a2713aSLionel Sambuc }
82f4a2713aSLionel Sambuc
83f4a2713aSLionel Sambuc break;
84f4a2713aSLionel Sambuc }
85f4a2713aSLionel Sambuc
86f4a2713aSLionel Sambuc BugReport *R = new BugReport(*BT, str, N);
87f4a2713aSLionel Sambuc if (ex) {
88f4a2713aSLionel Sambuc R->addRange(ex->getSourceRange());
89f4a2713aSLionel Sambuc bugreporter::trackNullOrUndefValue(N, ex, *R);
90f4a2713aSLionel Sambuc }
91f4a2713aSLionel Sambuc C.emitReport(R);
92f4a2713aSLionel Sambuc }
93f4a2713aSLionel Sambuc
registerUndefinedAssignmentChecker(CheckerManager & mgr)94f4a2713aSLionel Sambuc void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
95f4a2713aSLionel Sambuc mgr.registerChecker<UndefinedAssignmentChecker>();
96f4a2713aSLionel Sambuc }
97