clang API Documentation

UndefResultChecker.cpp
Go to the documentation of this file.
00001 //=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This defines UndefResultChecker, a builtin check in ExprEngine that 
00011 // performs checks for undefined results of non-assignment binary operators.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "ClangSACheckers.h"
00016 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
00017 #include "clang/StaticAnalyzer/Core/Checker.h"
00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
00020 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
00021 #include "llvm/ADT/SmallString.h"
00022 #include "llvm/Support/raw_ostream.h"
00023 
00024 using namespace clang;
00025 using namespace ento;
00026 
00027 namespace {
00028 class UndefResultChecker 
00029   : public Checker< check::PostStmt<BinaryOperator> > {
00030 
00031   mutable std::unique_ptr<BugType> BT;
00032 
00033 public:
00034   void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
00035 };
00036 } // end anonymous namespace
00037 
00038 void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
00039                                        CheckerContext &C) const {
00040   ProgramStateRef state = C.getState();
00041   const LocationContext *LCtx = C.getLocationContext();
00042   if (state->getSVal(B, LCtx).isUndef()) {
00043 
00044     // Do not report assignments of uninitialized values inside swap functions.
00045     // This should allow to swap partially uninitialized structs
00046     // (radar://14129997)
00047     if (const FunctionDecl *EnclosingFunctionDecl =
00048         dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
00049       if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
00050         return;
00051 
00052     // Generate an error node.
00053     ExplodedNode *N = C.generateSink();
00054     if (!N)
00055       return;
00056     
00057     if (!BT)
00058       BT.reset(
00059           new BuiltinBug(this, "Result of operation is garbage or undefined"));
00060 
00061     SmallString<256> sbuf;
00062     llvm::raw_svector_ostream OS(sbuf);
00063     const Expr *Ex = nullptr;
00064     bool isLeft = true;
00065     
00066     if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
00067       Ex = B->getLHS()->IgnoreParenCasts();
00068       isLeft = true;
00069     }
00070     else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
00071       Ex = B->getRHS()->IgnoreParenCasts();
00072       isLeft = false;
00073     }
00074     
00075     if (Ex) {
00076       OS << "The " << (isLeft ? "left" : "right")
00077          << " operand of '"
00078          << BinaryOperator::getOpcodeStr(B->getOpcode())
00079          << "' is a garbage value";
00080     }          
00081     else {
00082       // Neither operand was undefined, but the result is undefined.
00083       OS << "The result of the '"
00084          << BinaryOperator::getOpcodeStr(B->getOpcode())
00085          << "' expression is undefined";
00086     }
00087     BugReport *report = new BugReport(*BT, OS.str(), N);
00088     if (Ex) {
00089       report->addRange(Ex->getSourceRange());
00090       bugreporter::trackNullOrUndefValue(N, Ex, *report);
00091     }
00092     else
00093       bugreporter::trackNullOrUndefValue(N, B, *report);
00094     
00095     C.emitReport(report);
00096   }
00097 }
00098 
00099 void ento::registerUndefResultChecker(CheckerManager &mgr) {
00100   mgr.registerChecker<UndefResultChecker>();
00101 }