UndefResultChecker.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. //
  10. // This defines UndefResultChecker, a builtin check in ExprEngine that
  11. // performs checks for undefined results of non-assignment binary operators.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  16. #include "clang/StaticAnalyzer/Core/Checker.h"
  17. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/Support/raw_ostream.h"
  22. using namespace clang;
  23. using namespace ento;
  24. namespace {
  25. class UndefResultChecker
  26. : public Checker< check::PostStmt<BinaryOperator> > {
  27. mutable std::unique_ptr<BugType> BT;
  28. public:
  29. void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
  30. };
  31. } // end anonymous namespace
  32. void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
  33. CheckerContext &C) const {
  34. ProgramStateRef state = C.getState();
  35. const LocationContext *LCtx = C.getLocationContext();
  36. if (state->getSVal(B, LCtx).isUndef()) {
  37. // Do not report assignments of uninitialized values inside swap functions.
  38. // This should allow to swap partially uninitialized structs
  39. // (radar://14129997)
  40. if (const FunctionDecl *EnclosingFunctionDecl =
  41. dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
  42. if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
  43. return;
  44. // Generate an error node.
  45. ExplodedNode *N = C.generateSink();
  46. if (!N)
  47. return;
  48. if (!BT)
  49. BT.reset(
  50. new BuiltinBug(this, "Result of operation is garbage or undefined"));
  51. SmallString<256> sbuf;
  52. llvm::raw_svector_ostream OS(sbuf);
  53. const Expr *Ex = nullptr;
  54. bool isLeft = true;
  55. if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
  56. Ex = B->getLHS()->IgnoreParenCasts();
  57. isLeft = true;
  58. }
  59. else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
  60. Ex = B->getRHS()->IgnoreParenCasts();
  61. isLeft = false;
  62. }
  63. if (Ex) {
  64. OS << "The " << (isLeft ? "left" : "right")
  65. << " operand of '"
  66. << BinaryOperator::getOpcodeStr(B->getOpcode())
  67. << "' is a garbage value";
  68. }
  69. else {
  70. // Neither operand was undefined, but the result is undefined.
  71. OS << "The result of the '"
  72. << BinaryOperator::getOpcodeStr(B->getOpcode())
  73. << "' expression is undefined";
  74. }
  75. auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N);
  76. if (Ex) {
  77. report->addRange(Ex->getSourceRange());
  78. bugreporter::trackNullOrUndefValue(N, Ex, *report);
  79. }
  80. else
  81. bugreporter::trackNullOrUndefValue(N, B, *report);
  82. C.emitReport(std::move(report));
  83. }
  84. }
  85. void ento::registerUndefResultChecker(CheckerManager &mgr) {
  86. mgr.registerChecker<UndefResultChecker>();
  87. }