11184aebb761cbeac9124c37189a80a1a58f04b6bhkuang//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//
3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//                     The LLVM Compiler Infrastructure
4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//
5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// This file is distributed under the University of Illinois Open Source
6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// License. See LICENSE.TXT for details.
7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//
8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//===----------------------------------------------------------------------===//
9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//
10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// This defines UndefResultChecker, a builtin check in ExprEngine that
11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// performs checks for undefined results of non-assignment binary operators.
12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//
13ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//===----------------------------------------------------------------------===//
14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
15ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "ClangSACheckers.h"
162ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
172ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/Checker.h"
182ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "llvm/ADT/SmallString.h"
221184aebb761cbeac9124c37189a80a1a58f04b6bhkuang#include "llvm/Support/raw_ostream.h"
231184aebb761cbeac9124c37189a80a1a58f04b6bhkuang
242ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianusing namespace clang;
25f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangusing namespace ento;
26f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
27da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniannamespace {
28da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianclass UndefResultChecker
29da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  : public Checker< check::PostStmt<BinaryOperator> > {
30f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
31f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  mutable std::unique_ptr<BugType> BT;
32da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
33f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangpublic:
34f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
35f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang};
36f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} // end anonymous namespace
371184aebb761cbeac9124c37189a80a1a58f04b6bhkuang
382ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianvoid UndefResultChecker::checkPostStmt(const BinaryOperator *B,
395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                       CheckerContext &C) const {
404fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang  ProgramStateRef state = C.getState();
414fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang  const LocationContext *LCtx = C.getLocationContext();
421184aebb761cbeac9124c37189a80a1a58f04b6bhkuang  if (state->getSVal(B, LCtx).isUndef()) {
431184aebb761cbeac9124c37189a80a1a58f04b6bhkuang
441184aebb761cbeac9124c37189a80a1a58f04b6bhkuang    // Do not report assignments of uninitialized values inside swap functions.
452ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    // This should allow to swap partially uninitialized structs
461184aebb761cbeac9124c37189a80a1a58f04b6bhkuang    // (radar://14129997)
472ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    if (const FunctionDecl *EnclosingFunctionDecl =
48da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
49da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
502ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian        return;
51da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
52da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    // Generate an error node.
53ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    ExplodedNode *N = C.generateErrorNode();
54ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    if (!N)
55ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      return;
56f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
57f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang    if (!BT)
58f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang      BT.reset(
591184aebb761cbeac9124c37189a80a1a58f04b6bhkuang          new BuiltinBug(this, "Result of operation is garbage or undefined"));
602ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    SmallString<256> sbuf;
624fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang    llvm::raw_svector_ostream OS(sbuf);
634fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang    const Expr *Ex = nullptr;
642ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    bool isLeft = true;
651184aebb761cbeac9124c37189a80a1a58f04b6bhkuang
662ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
67da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      Ex = B->getLHS()->IgnoreParenCasts();
682ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian      isLeft = true;
69da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
70ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
71ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      Ex = B->getRHS()->IgnoreParenCasts();
72ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      isLeft = false;
73da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
74da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
75da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    if (Ex) {
76da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      OS << "The " << (isLeft ? "left" : "right")
77da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian         << " operand of '"
78da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian         << BinaryOperator::getOpcodeStr(B->getOpcode())
79da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian         << "' is a garbage value";
80da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
81da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    else {
82da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      // Neither operand was undefined, but the result is undefined.
83f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang      OS << "The result of the '"
84da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian         << BinaryOperator::getOpcodeStr(B->getOpcode())
85da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian         << "' expression is undefined";
86da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
87da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N);
88da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    if (Ex) {
89da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      report->addRange(Ex->getSourceRange());
90da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      bugreporter::trackNullOrUndefValue(N, Ex, *report);
91da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
92da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    else
93da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      bugreporter::trackNullOrUndefValue(N, B, *report);
94da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
95ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    C.emitReport(std::move(report));
96ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
97f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang}
98f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
99f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangvoid ento::registerUndefResultChecker(CheckerManager &mgr) {
100f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  mgr.registerChecker<UndefResultChecker>();
1011184aebb761cbeac9124c37189a80a1a58f04b6bhkuang}
1022ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian