RecyclerAnalyzer.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. //===----------------------------------------------------------------------===//
  6. //
  7. // Defines a checker for proper use of Recycler Write Barrier functionality
  8. //
  9. //===----------------------------------------------------------------------===//
  10. #include "llvm/ADT/StringSwitch.h"
  11. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  12. #include "clang/StaticAnalyzer/Core/Checker.h"
  13. #include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
  14. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  15. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  16. #include <cassert>
  17. using namespace clang;
  18. using namespace ento;
  19. class RecyclerChecker
  20. : public Checker<check::PostStmt<CXXNewExpr> > {
  21. std::unique_ptr<BugType> InvalidAllocatorBugType;
  22. public:
  23. RecyclerChecker();
  24. void checkPostStmt(const CXXNewExpr *newExpr, CheckerContext& ctx) const;
  25. };
  26. static BugType* createRecyclerCheckerError(StringRef name) {
  27. return new BugType(
  28. new CheckerBase(),
  29. name, "Recycler Checker Error");
  30. }
  31. static bool isCastToRecycler(const CXXStaticCastExpr* castNode)
  32. {
  33. // Not a cast
  34. if (castNode == nullptr)
  35. {
  36. return false;
  37. }
  38. QualType targetType = castNode->getTypeAsWritten();
  39. if (const IdentifierInfo* info = targetType.getBaseTypeIdentifier())
  40. {
  41. //printf("Cast to %s\n", info->getName().str().c_str());
  42. return info->getName().equals("Recycler");
  43. }
  44. else
  45. {
  46. printf("Can't get base type identifier");
  47. return false;
  48. }
  49. }
  50. RecyclerChecker::RecyclerChecker()
  51. {
  52. InvalidAllocatorBugType.reset(createRecyclerCheckerError("Invalid type"));
  53. }
  54. void RecyclerChecker::checkPostStmt(const CXXNewExpr* newExpr, CheckerContext& ctx) const
  55. {
  56. if (newExpr->getNumPlacementArgs() > 1)
  57. {
  58. const Expr* firstArgNode = newExpr->getPlacementArg(0);
  59. // Check if the first argument to new is a static cast
  60. // AllocatorNew in Chakra always does a static_cast to the AllocatorType
  61. CXXStaticCastExpr* castNode = nullptr;
  62. if (firstArgNode != nullptr &&
  63. (castNode = const_cast<CXXStaticCastExpr*>(dyn_cast<CXXStaticCastExpr>(firstArgNode))))
  64. {
  65. //printf("Expr is %s\n", firstArgNode->getStmtClassName());
  66. if (isCastToRecycler(castNode))
  67. {
  68. //printf("Recycler allocation found\n");
  69. const Expr* secondArgNode = newExpr->getPlacementArg(1);
  70. // Chakra has two types of allocating functions- throwing and non-throwing
  71. // However, recycler allocations are always throwing, so the second parameter
  72. // should be the address of the allocator function
  73. auto unaryNode = cast<UnaryOperator>(secondArgNode);
  74. if (unaryNode != nullptr && unaryNode->getOpcode() == UnaryOperatorKind::UO_AddrOf)
  75. {
  76. Expr* subExpr = unaryNode->getSubExpr();
  77. if (DeclRefExpr* declRef = cast<DeclRefExpr>(subExpr))
  78. {
  79. auto declNameInfo = declRef->getNameInfo();
  80. printf("AllocFunc: %s\n", declNameInfo.getName().getAsString().c_str());
  81. if (const IdentifierInfo* info = newExpr->getAllocatedType().getBaseTypeIdentifier())
  82. {
  83. printf("Type: %s\n", info->getName().str().c_str());
  84. }
  85. else
  86. {
  87. printf("Can't get base type identifier\n");
  88. }
  89. }
  90. else
  91. {
  92. printf("Expected DeclRefExpr:\n");
  93. subExpr->dump();
  94. }
  95. }
  96. else
  97. {
  98. printf("Expected unary node:\n");
  99. secondArgNode->dump();
  100. }
  101. //printf("-------------------\n");
  102. }
  103. /*
  104. else
  105. {
  106. printf("Not a cast node? 0x%x\n", castNode);
  107. firstArgNode->dump();
  108. printf("\n");
  109. }
  110. */
  111. }
  112. }
  113. }
  114. static void initRecyclerChecker(CheckerManager &mgr) {
  115. mgr.registerChecker<RecyclerChecker>();
  116. }
  117. extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
  118. registry.addChecker(initRecyclerChecker, "chakra.RecyclerChecker",
  119. "Check Recycler allocator usage");
  120. }
  121. extern "C" const char clang_analyzerAPIVersionString[] =
  122. CLANG_ANALYZER_API_VERSION_STRING;