brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.5 KiB · f426892 Raw
131 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"10#include "CheckerRegistration.h"11#include "clang/Basic/LLVM.h"12#include "clang/Frontend/CompilerInstance.h"13#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"14#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"15#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"16#include "clang/StaticAnalyzer/Core/Checker.h"17#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"20#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"21#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"22#include "clang/Tooling/Tooling.h"23#include "gtest/gtest.h"24 25namespace clang {26namespace ento {27namespace {28 29void reportBug(const CheckerBase *Checker, const CallEvent &Call,30               CheckerContext &C, StringRef WarningMsg) {31  C.getBugReporter().EmitBasicReport(32      nullptr, Checker, "", categories::LogicError, WarningMsg,33      PathDiagnosticLocation(Call.getOriginExpr(), C.getSourceManager(),34                             C.getLocationContext()),35      {});36}37 38class CXXDeallocatorChecker : public Checker<check::PreCall> {39public:40  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {41    const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call);42    if (!DC) {43      return;44    }45 46    SmallString<100> WarningBuf;47    llvm::raw_svector_ostream WarningOS(WarningBuf);48    WarningOS << "NumArgs: " << DC->getNumArgs();49 50    reportBug(this, *DC, C, WarningBuf);51  }52};53 54void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,55                              AnalyzerOptions &AnOpts) {56  AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};57  AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {58    Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",59                                               "MockDescription");60  });61}62 63// TODO: What we should really be testing here is all the different varieties64// of delete operators, and whether the retrieval of their arguments works as65// intended. At the time of writing this file, CXXDeallocatorCall doesn't pick66// up on much of those due to the AST not containing CXXDeleteExpr for most of67// the standard/custom deletes.68TEST(CXXDeallocatorCall, SimpleDestructor) {69  std::string Diags;70  EXPECT_TRUE(runCheckerOnCode<addCXXDeallocatorChecker>(R"(71    struct A {};72 73    void f() {74      A *a = new A;75      delete a;76    }77  )",78                                                         Diags));79#if defined(_AIX) || defined(__MVS__) || defined(__MINGW32__)80  // AIX, ZOS and MinGW default to -fno-sized-deallocation.81  EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 1\n");82#else83  EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 2\n");84#endif85}86 87TEST(PrivateMethodCache, NeverReturnDanglingPointersWithMultipleASTs) {88  // Each iteration will load and unload an AST multiple times. Since the code89  // is always the same, we increase the chance of hitting a bug in the private90  // method cache, returning a dangling pointer and crashing the process. If the91  // cache is properly cleared between runs, the test should pass.92  for (int I = 0; I < 100; ++I) {93    auto const *Code = R"(94    typedef __typeof(sizeof(int)) size_t;95 96    extern void *malloc(size_t size);97    extern void *memcpy(void *dest, const void *src, size_t n);98 99    @interface SomeMoreData {100      char const* _buffer;101      int _size;102    }103    @property(nonatomic, readonly) const char* buffer;104    @property(nonatomic) int size;105 106    - (void)appendData:(SomeMoreData*)other;107 108    @end109 110    @implementation SomeMoreData111    @synthesize size = _size;112    @synthesize buffer = _buffer;113 114    - (void)appendData:(SomeMoreData*)other {115      int const len = (_size + other.size); // implicit self._length116      char* d = malloc(sizeof(char) * len);117      memcpy(d + 20, other.buffer, len);118    }119 120    @end121  )";122    std::string Diags;123    EXPECT_TRUE(runCheckerOnCodeWithArgs<addCXXDeallocatorChecker>(124        Code, {"-x", "objective-c", "-Wno-objc-root-class"}, Diags));125  }126}127 128} // namespace129} // namespace ento130} // namespace clang131