================ @@ -0,0 +1,482 @@ +//===- CppBoundedBuffers.cpp ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DynamicRecursiveASTVisitor.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "clang/ScalableStaticAnalysis/Analyses/EntityPointerLevel/EntityPointerLevel.h" +#include "clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h" +#include "clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h" +#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h" +#include "clang/ScalableStaticAnalysis/Core/Model/EntityIdTable.h" +#include "clang/ScalableStaticAnalysis/Core/Model/EntityName.h" +#include "clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <map> +#include <string> + +using namespace clang; +using namespace clang::ssaf; + +static constexpr llvm::StringLiteral SkippedRuleId = + "cpp-bounded-buffers-skipped"; + +namespace { + +/// A declarator whose type can carry pointer levels. +bool isCandidateType(QualType T) { + QualType U = T.getNonReferenceType(); + return U->isPointerType() || U->isArrayType(); +} + +std::string spell(QualType T, const ASTContext &Ctx) { + return T.getAsString(Ctx.getPrintingPolicy()); +} + +/// Whether \p T can be re-emitted as written. Anonymous records and lambdas +/// have no usable spelling. +bool isReproducible(QualType T) { + const auto *RT = T->getAs<RecordType>(); + if (!RT) + return true; + const RecordDecl *RD = RT->getDecl(); + if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + if (CXXRD->isLambda()) + return false; + return RD->getIdentifier() || RD->getTypedefNameForAnonDecl(); +} + +std::string cvPrefix(QualType T) { + std::string Prefix; + if (T.isLocalConstQualified()) + Prefix += "const "; + if (T.isLocalVolatileQualified()) + Prefix += "volatile "; + return Prefix; +} + +std::string renderNewType(const ClassifyResult &R, QualType T, + const ASTContext &Ctx) { + if (*R.NewType == BoundedType::Ptr) + return cvPrefix(T) + "bounded_ptr<" + R.InnerSpelling + "> "; + const auto *CAT = Ctx.getAsConstantArrayType(T); + std::string N = std::to_string(CAT->getSize().getZExtValue()); + return "bounded_array<" + R.InnerSpelling + ", " + N + "> "; +} + +/// Whether another declarator in \p D's lexical context shares its type +/// specifier, i.e. \p D is one declarator of a multi-declarator group. +bool sharesTypeSpecifier(const DeclaratorDecl *D) { + const TypeSourceInfo *TSI = D->getTypeSourceInfo(); + const DeclContext *DC = D->getLexicalDeclContext(); + if (!TSI || !DC) + return false; + SourceLocation Begin = TSI->getTypeLoc().getBeginLoc(); + for (const Decl *Sibling : DC->decls()) { + if (Sibling == D) + continue; + const auto *Other = dyn_cast<DeclaratorDecl>(Sibling); + if (Other && Other->getTypeSourceInfo() && + Other->getTypeSourceInfo()->getTypeLoc().getBeginLoc() == Begin) + return true; + } + return false; +} + +bool hasTrailingReturnType(const FunctionDecl *FD) { + const auto *FPT = FD->getType()->getAs<FunctionProtoType>(); + return FPT && FPT->hasTrailingReturn(); +} + +CharSourceRange declTypeRange(const DeclaratorDecl *D) { + if (const TypeSourceInfo *TSI = D->getTypeSourceInfo()) + return CharSourceRange::getTokenRange(TSI->getTypeLoc().getSourceRange()); + return CharSourceRange::getTokenRange(D->getSourceRange()); +} + +/// A leading cv-qualifier keyword (e.g. the `const` in `const char *`) is not +/// covered by the type-loc's begin location; extend \p TypeBegin left over it. +SourceLocation extendOverLeadingQualifiers(SourceLocation TypeBegin, + const ASTContext &Ctx) { + const SourceManager &SM = Ctx.getSourceManager(); + const LangOptions &LangOpts = Ctx.getLangOpts(); + while (std::optional<Token> Prev = Lexer::findPreviousToken( + TypeBegin, SM, LangOpts, /*IncludeComments=*/false)) { + // findPreviousToken lexes raw tokens, so keywords arrive as identifiers. + if (!Prev->is(tok::raw_identifier)) + break; + StringRef Text = Prev->getRawIdentifier(); + if (Text != "const" && Text != "volatile") + break; + TypeBegin = Prev->getLocation(); + } + return TypeBegin; +} + +/// Reverse index from the whole-program reachability result onto entity names, +/// so a declaration in this TU can look up its reachable pointer levels. +class ReachabilityMap { + const std::map<EntityId, EntityPointerLevelSet> &Reachables; + std::map<EntityName, EntityId> NameToId; + +public: + ReachabilityMap(const WPASuite &Suite, + const std::map<EntityId, EntityPointerLevelSet> &Reachables) + : Reachables(Reachables) { + Suite.getIdTable().forEach([this](const EntityName &Name, EntityId Id) { + NameToId.emplace(Name, Id); + }); + } + + llvm::SmallSet<unsigned, 4> levelsFor(std::optional<EntityName> Name) const { + llvm::SmallSet<unsigned, 4> Levels; + if (!Name) + return Levels; + auto NameIt = NameToId.find(*Name); + if (NameIt == NameToId.end()) + return Levels; + auto ReachIt = Reachables.find(NameIt->second); + if (ReachIt == Reachables.end()) + return Levels; + for (const EntityPointerLevel &EPL : ReachIt->second) + Levels.insert(EPL.getPointerLevel()); + return Levels; + } +}; + +struct Candidate { + llvm::SmallSet<unsigned, 4> Levels; + bool AccountedFor = false; +}; + +using DeclLevels = std::map<const Decl *, Candidate>; +using ReturnLevels = std::map<const FunctionDecl *, Candidate>; + +/// Collects the reachable pointer/array declarators and function returns +/// declared in this TU. +class CollectVisitor : public DynamicRecursiveASTVisitor { +public: + CollectVisitor(const ReachabilityMap &Reach, DeclLevels &Decls, + ReturnLevels &Returns) + : Reach(Reach), Decls(Decls), Returns(Returns) {} + + bool VisitVarDecl(VarDecl *D) override { + collect(D, D->getType(), getEntityName(D)); + return true; + } + + bool VisitFieldDecl(FieldDecl *D) override { + collect(D, D->getType(), getEntityName(D)); + return true; + } + + bool VisitFunctionDecl(FunctionDecl *FD) override { + if (!FD->isTemplated() && isCandidateType(FD->getReturnType())) { + llvm::SmallSet<unsigned, 4> Levels = + Reach.levelsFor(getEntityNameForReturn(FD)); ---------------- ziqingluo-90 wrote:
We will solve this problem later when we connect everything for end-to-end. https://github.com/llvm/llvm-project/pull/210457 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
