1 //===- UnsafeBufferUsage.h - Replace pointers with modern C++ ---*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an analysis that aids replacing buffer accesses through 10 // raw pointers with safer C++ abstractions such as containers and views/spans. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H 15 #define LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H 16 17 #include "clang/AST/Decl.h" 18 #include "clang/AST/Stmt.h" 19 #include "llvm/Support/Debug.h" 20 21 namespace clang { 22 23 using VarGrpTy = std::vector<const VarDecl *>; 24 using VarGrpRef = ArrayRef<const VarDecl *>; 25 26 class VariableGroupsManager { 27 public: 28 VariableGroupsManager() = default; 29 virtual ~VariableGroupsManager() = default; 30 /// Returns the set of variables (including `Var`) that need to be fixed 31 /// together in one step. 32 /// 33 /// `Var` must be a variable that needs fix (so it must be in a group). 34 /// `HasParm` is an optional argument that will be set to true if the set of 35 /// variables, where `Var` is in, contains parameters. 36 virtual VarGrpRef getGroupOfVar(const VarDecl *Var, 37 bool *HasParm = nullptr) const =0; 38 39 /// Returns the non-empty group of variables that include parameters of the 40 /// analyzing function, if such a group exists. An empty group, otherwise. 41 virtual VarGrpRef getGroupOfParms() const =0; 42 }; 43 44 /// The interface that lets the caller handle unsafe buffer usage analysis 45 /// results by overriding this class's handle... methods. 46 class UnsafeBufferUsageHandler { 47 #ifndef NDEBUG 48 public: 49 // A self-debugging facility that you can use to notify the user when 50 // suggestions or fixits are incomplete. 51 // Uses std::function to avoid computing the message when it won't 52 // actually be displayed. 53 using DebugNote = std::pair<SourceLocation, std::string>; 54 using DebugNoteList = std::vector<DebugNote>; 55 using DebugNoteByVar = std::map<const VarDecl *, DebugNoteList>; 56 DebugNoteByVar DebugNotesByVar; 57 #endif 58 59 public: 60 UnsafeBufferUsageHandler() = default; 61 virtual ~UnsafeBufferUsageHandler() = default; 62 63 /// This analyses produces large fixits that are organized into lists 64 /// of primitive fixits (individual insertions/removals/replacements). 65 using FixItList = llvm::SmallVectorImpl<FixItHint>; 66 67 /// Invoked when an unsafe operation over raw pointers is found. 68 virtual void handleUnsafeOperation(const Stmt *Operation, 69 bool IsRelatedToDecl) = 0; 70 71 /// Invoked when a fix is suggested against a variable. This function groups 72 /// all variables that must be fixed together (i.e their types must be changed 73 /// to the same target type to prevent type mismatches) into a single fixit. 74 /// 75 /// `D` is the declaration of the callable under analysis that owns `Variable` 76 /// and all of its group mates. 77 virtual void handleUnsafeVariableGroup(const VarDecl *Variable, 78 const VariableGroupsManager &VarGrpMgr, 79 FixItList &&Fixes, const Decl *D) = 0; 80 81 #ifndef NDEBUG 82 public: areDebugNotesRequested()83 bool areDebugNotesRequested() { 84 DEBUG_WITH_TYPE("SafeBuffers", return true); 85 return false; 86 } 87 addDebugNoteForVar(const VarDecl * VD,SourceLocation Loc,std::string Text)88 void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, 89 std::string Text) { 90 if (areDebugNotesRequested()) 91 DebugNotesByVar[VD].push_back(std::make_pair(Loc, Text)); 92 } 93 clearDebugNotes()94 void clearDebugNotes() { 95 if (areDebugNotesRequested()) 96 DebugNotesByVar.clear(); 97 } 98 #endif 99 100 public: 101 /// Returns a reference to the `Preprocessor`: 102 virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0; 103 104 virtual std::string 105 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, 106 StringRef WSSuffix = "") const = 0; 107 }; 108 109 // This function invokes the analysis and allows the caller to react to it 110 // through the handler class. 111 void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, 112 bool EmitSuggestions); 113 114 namespace internal { 115 // Tests if any two `FixItHint`s in `FixIts` conflict. Two `FixItHint`s 116 // conflict if they have overlapping source ranges. 117 bool anyConflict(const llvm::SmallVectorImpl<FixItHint> &FixIts, 118 const SourceManager &SM); 119 } // namespace internal 120 } // end namespace clang 121 122 #endif /* LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H */ 123