================ @@ -0,0 +1,178 @@ +//=== PolymorphicPtrArithmetic.cpp ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This checker reports pointer arithmetic operations on arrays of +// polymorphic objects, where the array has the type of its base class. +// Corresponds to the CTR56-CPP. Do not use pointer arithmetic on +// polymorphic objects +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" + +using namespace clang; +using namespace ento; + +namespace { +class PolymorphicPtrArithmeticChecker + : public Checker<check::PreStmt<BinaryOperator>, + check::PreStmt<ArraySubscriptExpr>> { + const BugType BT{this, + "Pointer arithmetic on polymorphic objects is undefined"}; + +protected: + class PtrCastVisitor : public BugReporterVisitor { + public: + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int X = 0; + ID.AddPointer(&X); + } + PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) override; + }; + + void checkTypedExpr(const Expr *E, CheckerContext &C) const; + +public: + void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; + void checkPreStmt(const ArraySubscriptExpr *B, CheckerContext &C) const; +}; +} // namespace + +void PolymorphicPtrArithmeticChecker::checkPreStmt(const BinaryOperator *B, + CheckerContext &C) const { + if (!B->isAdditiveOp()) + return; + + bool IsLHSPtr = B->getLHS()->getType()->isAnyPointerType(); + bool IsRHSPtr = B->getRHS()->getType()->isAnyPointerType(); + if (!IsLHSPtr && !IsRHSPtr) + return; + + const Expr *E = IsLHSPtr ? B->getLHS() : B->getRHS(); + + checkTypedExpr(E, C); +} + +void PolymorphicPtrArithmeticChecker::checkPreStmt(const ArraySubscriptExpr *B, + CheckerContext &C) const { + bool IsLHSPtr = B->getLHS()->getType()->isAnyPointerType(); + bool IsRHSPtr = B->getRHS()->getType()->isAnyPointerType(); + if (!IsLHSPtr && !IsRHSPtr) + return; + + const Expr *E = IsLHSPtr ? B->getLHS() : B->getRHS(); + + checkTypedExpr(E, C); +} + +void PolymorphicPtrArithmeticChecker::checkTypedExpr(const Expr *E, + CheckerContext &C) const { + const MemRegion *MR = C.getSVal(E).getAsRegion(); + if (!MR) + return; + + const auto *BaseClassRegion = MR->getAs<TypedValueRegion>(); + const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>(); + if (!BaseClassRegion || !DerivedClassRegion) + return; + + const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl(); + const auto *DerivedClass = + DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl(); + if (!BaseClass || !DerivedClass) + return; + + if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition()) + return; + + if (!DerivedClass->isDerivedFrom(BaseClass)) + return; + + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + + SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + + QualType SourceType = BaseClassRegion->getValueType(); + QualType TargetType = + DerivedClassRegion->getSymbol()->getType()->getPointeeType(); + + OS << "Doing pointer arithmetic with '" << TargetType.getAsString() + << "' objects as their base class '" + << SourceType.getAsString(C.getASTContext().getPrintingPolicy()) ---------------- NagyDonat wrote:
What's the reason for using the printing policy on just one of the two `getAsString()` calls? https://github.com/llvm/llvm-project/pull/82977 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits