• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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