1 /* Classes for analyzer diagnostics. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 Contributed by David Malcolm <dmalcolm@redhat.com>. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H 22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H 23 24 namespace ana { 25 26 /* Various bundles of information used for generating more precise 27 messages for events within a diagnostic_path, for passing to the 28 various "describe_*" vfuncs of pending_diagnostic. See those 29 for more information. */ 30 31 namespace evdesc { 32 33 struct event_desc 34 { event_descevent_desc35 event_desc (bool colorize) : m_colorize (colorize) {} 36 37 label_text formatted_print (const char *fmt, ...) const 38 ATTRIBUTE_GCC_DIAG(2,3); 39 40 bool m_colorize; 41 }; 42 43 /* For use by pending_diagnostic::describe_state_change. */ 44 45 struct state_change : public event_desc 46 { state_changestate_change47 state_change (bool colorize, 48 tree expr, 49 tree origin, 50 state_machine::state_t old_state, 51 state_machine::state_t new_state, 52 diagnostic_event_id_t event_id, 53 const state_change_event &event) 54 : event_desc (colorize), 55 m_expr (expr), m_origin (origin), 56 m_old_state (old_state), m_new_state (new_state), 57 m_event_id (event_id), m_event (event) 58 {} 59 is_global_pstate_change60 bool is_global_p () const { return m_expr == NULL_TREE; } 61 62 tree m_expr; 63 tree m_origin; 64 state_machine::state_t m_old_state; 65 state_machine::state_t m_new_state; 66 diagnostic_event_id_t m_event_id; 67 const state_change_event &m_event; 68 }; 69 70 /* For use by pending_diagnostic::describe_call_with_state. */ 71 72 struct call_with_state : public event_desc 73 { call_with_statecall_with_state74 call_with_state (bool colorize, 75 tree caller_fndecl, tree callee_fndecl, 76 tree expr, state_machine::state_t state) 77 : event_desc (colorize), 78 m_caller_fndecl (caller_fndecl), 79 m_callee_fndecl (callee_fndecl), 80 m_expr (expr), 81 m_state (state) 82 { 83 } 84 85 tree m_caller_fndecl; 86 tree m_callee_fndecl; 87 tree m_expr; 88 state_machine::state_t m_state; 89 }; 90 91 /* For use by pending_diagnostic::describe_return_of_state. */ 92 93 struct return_of_state : public event_desc 94 { return_of_statereturn_of_state95 return_of_state (bool colorize, 96 tree caller_fndecl, tree callee_fndecl, 97 state_machine::state_t state) 98 : event_desc (colorize), 99 m_caller_fndecl (caller_fndecl), 100 m_callee_fndecl (callee_fndecl), 101 m_state (state) 102 { 103 } 104 105 tree m_caller_fndecl; 106 tree m_callee_fndecl; 107 state_machine::state_t m_state; 108 }; 109 110 /* For use by pending_diagnostic::describe_final_event. */ 111 112 struct final_event : public event_desc 113 { final_eventfinal_event114 final_event (bool colorize, 115 tree expr, state_machine::state_t state) 116 : event_desc (colorize), 117 m_expr (expr), m_state (state) 118 {} 119 120 tree m_expr; 121 state_machine::state_t m_state; 122 }; 123 124 } /* end of namespace evdesc */ 125 126 /* An abstract base class for capturing information about a diagnostic in 127 a form that is ready to emit at a later point (or be rejected). 128 Each kind of diagnostic will have a concrete subclass of 129 pending_diagnostic. 130 131 Normally, gcc diagnostics are emitted using va_list, which can't be 132 portably stored for later use, so we have to use an "emit" virtual 133 function. 134 135 This class also supports comparison, so that multiple pending_diagnostic 136 instances can be de-duplicated. 137 138 As well as emitting a diagnostic, the class has various "precision of 139 wording" virtual functions, for generating descriptions for events 140 within a diagnostic_path. These are optional, but implementing these 141 allows for more precise wordings than the more generic 142 implementation. */ 143 144 class pending_diagnostic 145 { 146 public: ~pending_diagnostic()147 virtual ~pending_diagnostic () {} 148 149 /* Vfunc for emitting the diagnostic. The rich_location will have been 150 populated with a diagnostic_path. 151 Return true if a diagnostic is actually emitted. */ 152 virtual bool emit (rich_location *) = 0; 153 154 /* Hand-coded RTTI: get an ID for the subclass. */ 155 virtual const char *get_kind () const = 0; 156 157 /* Compare for equality with OTHER, which might be of a different 158 subclass. */ 159 equal_p(const pending_diagnostic & other)160 bool equal_p (const pending_diagnostic &other) 161 { 162 /* Check for pointer equality on the IDs from get_kind. */ 163 if (get_kind () != other.get_kind ()) 164 return false; 165 /* Call vfunc now we know they have the same ID: */ 166 return subclass_equal_p (other); 167 } 168 169 /* A vfunc for testing for equality, where we've already 170 checked they have the same ID. See pending_diagnostic_subclass 171 below for a convenience subclass for implementing this. */ 172 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0; 173 174 /* Return true if T1 and T2 are "the same" for the purposes of 175 diagnostic deduplication. */ 176 static bool same_tree_p (tree t1, tree t2); 177 178 /* For greatest precision-of-wording, the various following "describe_*" 179 virtual functions give the pending diagnostic a way to describe events 180 in a diagnostic_path in terms that make sense for that diagnostic. 181 182 In each case, return a non-NULL label_text to give the event a custom 183 description; NULL otherwise (falling back on a more generic 184 description). */ 185 186 /* Precision-of-wording vfunc for describing a critical state change 187 within the diagnostic_path. 188 189 For example, a double-free diagnostic might use the descriptions: 190 - "first 'free' happens here" 191 - "second 'free' happens here" 192 for the pertinent events, whereas a use-after-free might use the 193 descriptions: 194 - "freed here" 195 - "use after free here" 196 Note how in both cases the first event is a "free": the best 197 description to use depends on the diagnostic. */ 198 describe_state_change(const evdesc::state_change &)199 virtual label_text describe_state_change (const evdesc::state_change &) 200 { 201 /* Default no-op implementation. */ 202 return label_text (); 203 } 204 205 /* Precision-of-wording vfunc for describing an interprocedural call 206 carrying critial state for the diagnostic, from caller to callee. 207 208 For example a double-free diagnostic might use: 209 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'" 210 to make it clearer how the freed value moves from caller to 211 callee. */ 212 describe_call_with_state(const evdesc::call_with_state &)213 virtual label_text describe_call_with_state (const evdesc::call_with_state &) 214 { 215 /* Default no-op implementation. */ 216 return label_text (); 217 } 218 219 /* Precision-of-wording vfunc for describing an interprocedural return 220 within the diagnostic_path that carries critial state for the 221 diagnostic, from callee back to caller. 222 223 For example, a deref-of-unchecked-malloc diagnostic might use: 224 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'" 225 to make it clearer how the unchecked value moves from callee 226 back to caller. */ 227 describe_return_of_state(const evdesc::return_of_state &)228 virtual label_text describe_return_of_state (const evdesc::return_of_state &) 229 { 230 /* Default no-op implementation. */ 231 return label_text (); 232 } 233 234 /* Precision-of-wording vfunc for describing the final event within a 235 diagnostic_path. 236 237 For example a double-free diagnostic might use: 238 - "second 'free' here; first 'free' was at (3)" 239 and a use-after-free might use 240 - "use after 'free' here; memory was freed at (2)". */ 241 describe_final_event(const evdesc::final_event &)242 virtual label_text describe_final_event (const evdesc::final_event &) 243 { 244 /* Default no-op implementation. */ 245 return label_text (); 246 } 247 248 /* End of precision-of-wording vfuncs. */ 249 }; 250 251 /* A template to make it easier to make subclasses of pending_diagnostic. 252 253 This uses the curiously-recurring template pattern, to implement 254 pending_diagnostic::subclass_equal_p by casting and calling 255 the operator== 256 257 This assumes that BASE_OTHER has already been checked to have 258 been of the same subclass (which pending_diagnostic::equal_p does). */ 259 260 template <class Subclass> 261 class pending_diagnostic_subclass : public pending_diagnostic 262 { 263 public: subclass_equal_p(const pending_diagnostic & base_other)264 bool subclass_equal_p (const pending_diagnostic &base_other) const 265 FINAL OVERRIDE 266 { 267 const Subclass &other = (const Subclass &)base_other; 268 return *(const Subclass*)this == other; 269 } 270 }; 271 272 } // namespace ana 273 274 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */ 275