Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp
35269 views
//=== CXXDeleteChecker.cpp -------------------------------------*- C++ -*--===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the following new checkers for C++ delete expressions:9//10// * DeleteWithNonVirtualDtorChecker11// Defines a checker for the OOP52-CPP CERT rule: Do not delete a12// polymorphic object without a virtual destructor.13//14// Diagnostic flags -Wnon-virtual-dtor and -Wdelete-non-virtual-dtor15// report if an object with a virtual function but a non-virtual16// destructor exists or is deleted, respectively.17//18// This check exceeds them by comparing the dynamic and static types of19// the object at the point of destruction and only warns if it happens20// through a pointer to a base type without a virtual destructor. The21// check places a note at the last point where the conversion from22// derived to base happened.23//24// * CXXArrayDeleteChecker25// Defines a checker for the EXP51-CPP CERT rule: Do not delete an array26// through a pointer of the incorrect type.27//28//===----------------------------------------------------------------------===//2930#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"31#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"32#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"33#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"34#include "clang/StaticAnalyzer/Core/Checker.h"35#include "clang/StaticAnalyzer/Core/CheckerManager.h"36#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"37#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"38#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"39#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"4041using namespace clang;42using namespace ento;4344namespace {45class CXXDeleteChecker : public Checker<check::PreStmt<CXXDeleteExpr>> {46protected:47class PtrCastVisitor : public BugReporterVisitor {48public:49void Profile(llvm::FoldingSetNodeID &ID) const override {50static int X = 0;51ID.AddPointer(&X);52}53PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,54BugReporterContext &BRC,55PathSensitiveBugReport &BR) override;56};5758virtual void59checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,60const TypedValueRegion *BaseClassRegion,61const SymbolicRegion *DerivedClassRegion) const = 0;6263public:64void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;65};6667class DeleteWithNonVirtualDtorChecker : public CXXDeleteChecker {68const BugType BT{69this, "Destruction of a polymorphic object with no virtual destructor"};7071void72checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,73const TypedValueRegion *BaseClassRegion,74const SymbolicRegion *DerivedClassRegion) const override;75};7677class CXXArrayDeleteChecker : public CXXDeleteChecker {78const BugType BT{this,79"Deleting an array of polymorphic objects is undefined"};8081void82checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,83const TypedValueRegion *BaseClassRegion,84const SymbolicRegion *DerivedClassRegion) const override;85};86} // namespace8788void CXXDeleteChecker::checkPreStmt(const CXXDeleteExpr *DE,89CheckerContext &C) const {90const Expr *DeletedObj = DE->getArgument();91const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion();92if (!MR)93return;9495OverloadedOperatorKind DeleteKind =96DE->getOperatorDelete()->getOverloadedOperator();9798if (DeleteKind != OO_Delete && DeleteKind != OO_Array_Delete)99return;100101const auto *BaseClassRegion = MR->getAs<TypedValueRegion>();102const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>();103if (!BaseClassRegion || !DerivedClassRegion)104return;105106checkTypedDeleteExpr(DE, C, BaseClassRegion, DerivedClassRegion);107}108109void DeleteWithNonVirtualDtorChecker::checkTypedDeleteExpr(110const CXXDeleteExpr *DE, CheckerContext &C,111const TypedValueRegion *BaseClassRegion,112const SymbolicRegion *DerivedClassRegion) const {113const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();114const auto *DerivedClass =115DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();116if (!BaseClass || !DerivedClass)117return;118119if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())120return;121122if (BaseClass->getDestructor()->isVirtual())123return;124125if (!DerivedClass->isDerivedFrom(BaseClass))126return;127128ExplodedNode *N = C.generateNonFatalErrorNode();129if (!N)130return;131auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);132133// Mark region of problematic base class for later use in the BugVisitor.134R->markInteresting(BaseClassRegion);135R->addVisitor<PtrCastVisitor>();136C.emitReport(std::move(R));137}138139void CXXArrayDeleteChecker::checkTypedDeleteExpr(140const CXXDeleteExpr *DE, CheckerContext &C,141const TypedValueRegion *BaseClassRegion,142const SymbolicRegion *DerivedClassRegion) const {143const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();144const auto *DerivedClass =145DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();146if (!BaseClass || !DerivedClass)147return;148149if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())150return;151152if (DE->getOperatorDelete()->getOverloadedOperator() != OO_Array_Delete)153return;154155if (!DerivedClass->isDerivedFrom(BaseClass))156return;157158ExplodedNode *N = C.generateNonFatalErrorNode();159if (!N)160return;161162SmallString<256> Buf;163llvm::raw_svector_ostream OS(Buf);164165QualType SourceType = BaseClassRegion->getValueType();166QualType TargetType =167DerivedClassRegion->getSymbol()->getType()->getPointeeType();168169OS << "Deleting an array of '" << TargetType.getAsString()170<< "' objects as their base class '"171<< SourceType.getAsString(C.getASTContext().getPrintingPolicy())172<< "' is undefined";173174auto R = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);175176// Mark region of problematic base class for later use in the BugVisitor.177R->markInteresting(BaseClassRegion);178R->addVisitor<PtrCastVisitor>();179C.emitReport(std::move(R));180}181182PathDiagnosticPieceRef183CXXDeleteChecker::PtrCastVisitor::VisitNode(const ExplodedNode *N,184BugReporterContext &BRC,185PathSensitiveBugReport &BR) {186const Stmt *S = N->getStmtForDiagnostics();187if (!S)188return nullptr;189190const auto *CastE = dyn_cast<CastExpr>(S);191if (!CastE)192return nullptr;193194// FIXME: This way of getting base types does not support reference types.195QualType SourceType = CastE->getSubExpr()->getType()->getPointeeType();196QualType TargetType = CastE->getType()->getPointeeType();197198if (SourceType.isNull() || TargetType.isNull() || SourceType == TargetType)199return nullptr;200201// Region associated with the current cast expression.202const MemRegion *M = N->getSVal(CastE).getAsRegion();203if (!M)204return nullptr;205206// Check if target region was marked as problematic previously.207if (!BR.isInteresting(M))208return nullptr;209210SmallString<256> Buf;211llvm::raw_svector_ostream OS(Buf);212213OS << "Casting from '" << SourceType.getAsString() << "' to '"214<< TargetType.getAsString() << "' here";215216PathDiagnosticLocation Pos(S, BRC.getSourceManager(),217N->getLocationContext());218return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),219/*addPosRange=*/true);220}221222void ento::registerArrayDeleteChecker(CheckerManager &mgr) {223mgr.registerChecker<CXXArrayDeleteChecker>();224}225226bool ento::shouldRegisterArrayDeleteChecker(const CheckerManager &mgr) {227return true;228}229230void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {231mgr.registerChecker<DeleteWithNonVirtualDtorChecker>();232}233234bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker(235const CheckerManager &mgr) {236return true;237}238239240