AdjustedReturnValueChecker.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. //== AdjustedReturnValueChecker.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 file defines AdjustedReturnValueChecker, a simple check to see if the
  11. // return value of a function call is different than the one the caller thinks
  12. // it is.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #include "InternalChecks.h"
  16. #include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
  17. #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
  18. #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
  19. using namespace clang;
  20. using namespace ento;
  21. namespace {
  22. class AdjustedReturnValueChecker :
  23. public CheckerVisitor<AdjustedReturnValueChecker> {
  24. public:
  25. AdjustedReturnValueChecker() {}
  26. void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
  27. static void *getTag() {
  28. static int x = 0; return &x;
  29. }
  30. };
  31. }
  32. void ento::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) {
  33. Eng.registerCheck(new AdjustedReturnValueChecker());
  34. }
  35. void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
  36. const CallExpr *CE) {
  37. // Get the result type of the call.
  38. QualType expectedResultTy = CE->getType();
  39. // Fetch the signature of the called function.
  40. const GRState *state = C.getState();
  41. SVal V = state->getSVal(CE);
  42. if (V.isUnknown())
  43. return;
  44. // Casting to void? Discard the value.
  45. if (expectedResultTy->isVoidType()) {
  46. C.generateNode(state->BindExpr(CE, UnknownVal()));
  47. return;
  48. }
  49. const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
  50. if (!callee)
  51. return;
  52. QualType actualResultTy;
  53. if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
  54. const FunctionDecl *FD = FT->getDecl();
  55. actualResultTy = FD->getResultType();
  56. }
  57. else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
  58. const BlockTextRegion *BR = BD->getCodeRegion();
  59. const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
  60. const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
  61. actualResultTy = FT->getResultType();
  62. }
  63. // Can this happen?
  64. if (actualResultTy.isNull())
  65. return;
  66. // For now, ignore references.
  67. if (actualResultTy->getAs<ReferenceType>())
  68. return;
  69. // Are they the same?
  70. if (expectedResultTy != actualResultTy) {
  71. // FIXME: Do more checking and actual emit an error. At least performing
  72. // the cast avoids some assertion failures elsewhere.
  73. SValBuilder &svalBuilder = C.getSValBuilder();
  74. V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
  75. C.generateNode(state->BindExpr(CE, V));
  76. }
  77. }