1 1.1 mrg /* Copyright (C) 2013-2022 Free Software Foundation, Inc. 2 1.1 mrg 3 1.1 mrg This file is part of GCC. 4 1.1 mrg 5 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 6 1.1 mrg the terms of the GNU General Public License as published by the Free 7 1.1 mrg Software Foundation; either version 3, or (at your option) any later 8 1.1 mrg version. 9 1.1 mrg 10 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 11 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 1.1 mrg for more details. 14 1.1 mrg 15 1.1 mrg You should have received a copy of the GNU General Public License 16 1.1 mrg along with GCC; see the file COPYING3. If not see 17 1.1 mrg <http://www.gnu.org/licenses/>. */ 18 1.1 mrg 19 1.1 mrg /* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers 20 1.1 mrg before using them for virtual method dispatches. */ 21 1.1 mrg 22 1.1 mrg /* This file is part of the vtable security feature implementation. 23 1.1 mrg The vtable security feature is designed to detect when a virtual 24 1.1 mrg call is about to be made through an invalid vtable pointer 25 1.1 mrg (possibly due to data corruption or malicious attacks). The 26 1.1 mrg compiler finds every virtual call, and inserts a verification call 27 1.1 mrg before the virtual call. The verification call takes the actual 28 1.1 mrg vtable pointer value in the object through which the virtual call 29 1.1 mrg is being made, and compares the vtable pointer against a set of all 30 1.1 mrg valid vtable pointers that the object could contain (this set is 31 1.1 mrg based on the declared type of the object). If the pointer is in 32 1.1 mrg the valid set, execution is allowed to continue; otherwise the 33 1.1 mrg program is halted. 34 1.1 mrg 35 1.1 mrg There are several pieces needed in order to make this work: 1. For 36 1.1 mrg every virtual class in the program (i.e. a class that contains 37 1.1 mrg virtual methods), we need to build the set of all possible valid 38 1.1 mrg vtables that an object of that class could point to. This includes 39 1.1 mrg vtables for any class(es) that inherit from the class under 40 1.1 mrg consideration. 2. For every such data set we build up, we need a 41 1.1 mrg way to find and reference the data set. This is complicated by the 42 1.1 mrg fact that the real vtable addresses are not known until runtime, 43 1.1 mrg when the program is loaded into memory, but we need to reference the 44 1.1 mrg sets at compile time when we are inserting verification calls into 45 1.1 mrg the program. 3. We need to find every virtual call in the program, 46 1.1 mrg and insert the verification call (with the appropriate arguments) 47 1.1 mrg before the virtual call. 4. We need some runtime library pieces: 48 1.1 mrg the code to build up the data sets at runtime; the code to actually 49 1.1 mrg perform the verification using the data sets; and some code to set 50 1.1 mrg protections on the data sets, so they themselves do not become 51 1.1 mrg hacker targets. 52 1.1 mrg 53 1.1 mrg To find and reference the set of valid vtable pointers for any given 54 1.1 mrg virtual class, we create a special global variable for each virtual 55 1.1 mrg class. We refer to this as the "vtable map variable" for that 56 1.1 mrg class. The vtable map variable has the type "void *", and is 57 1.1 mrg initialized by the compiler to NULL. At runtime when the set of 58 1.1 mrg valid vtable pointers for a virtual class, e.g. class Foo, is built, 59 1.1 mrg the vtable map variable for class Foo is made to point to the set. 60 1.1 mrg During compile time, when the compiler is inserting verification 61 1.1 mrg calls into the program, it passes the vtable map variable for the 62 1.1 mrg appropriate class to the verification call, so that at runtime the 63 1.1 mrg verification call can find the appropriate data set. 64 1.1 mrg 65 1.1 mrg The actual set of valid vtable pointers for a virtual class, 66 1.1 mrg e.g. class Foo, cannot be built until runtime, when the vtables get 67 1.1 mrg loaded into memory and their addresses are known. But the knowledge 68 1.1 mrg about which vtables belong in which class' hierarchy is only known 69 1.1 mrg at compile time. Therefore at compile time we collect class 70 1.1 mrg hierarchy and vtable information about every virtual class, and we 71 1.1 mrg generate calls to build up the data sets at runtime. To build the 72 1.1 mrg data sets, we call one of the functions we add to the runtime 73 1.1 mrg library, __VLTRegisterPair. __VLTRegisterPair takes two arguments, 74 1.1 mrg a vtable map variable and the address of a vtable. If the vtable 75 1.1 mrg map variable is currently NULL, it creates a new data set (hash 76 1.1 mrg table), makes the vtable map variable point to the new data set, and 77 1.1 mrg inserts the vtable address into the data set. If the vtable map 78 1.1 mrg variable is not NULL, it just inserts the vtable address into the 79 1.1 mrg data set. In order to make sure that our data sets are built before 80 1.1 mrg any verification calls happen, we create a special constructor 81 1.1 mrg initialization function for each compilation unit, give it a very 82 1.1 mrg high initialization priority, and insert all of our calls to 83 1.1 mrg __VLTRegisterPair into our special constructor initialization 84 1.1 mrg function. 85 1.1 mrg 86 1.1 mrg The vtable verification feature is controlled by the flag 87 1.1 mrg '-fvtable-verify='. There are three flavors of this: 88 1.1 mrg '-fvtable-verify=std', '-fvtable-verify=preinit', and 89 1.1 mrg '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is 90 1.1 mrg used, then our constructor initialization function gets put into the 91 1.1 mrg preinit array. This is necessary if there are data sets that need 92 1.1 mrg to be built very early in execution. If the constructor 93 1.1 mrg initialization function gets put into the preinit array, the we also 94 1.1 mrg add calls to __VLTChangePermission at the beginning and end of the 95 1.1 mrg function. The call at the beginning sets the permissions on the 96 1.1 mrg data sets and vtable map variables to read/write, and the one at the 97 1.1 mrg end makes them read-only. If the '-fvtable-verify=std' option is 98 1.1 mrg used, the constructor initialization functions are executed at their 99 1.1 mrg normal time, and the __VLTChangePermission calls are handled 100 1.1 mrg differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc). 101 1.1 mrg The option '-fvtable-verify=none' turns off vtable verification. 102 1.1 mrg 103 1.1 mrg This file contains code for the tree pass that goes through all the 104 1.1 mrg statements in each basic block, looking for virtual calls, and 105 1.1 mrg inserting a call to __VLTVerifyVtablePointer (with appropriate 106 1.1 mrg arguments) before each one. It also contains the hash table 107 1.1 mrg functions for the data structures used for collecting the class 108 1.1 mrg hierarchy data and building/maintaining the vtable map variable data 109 1.1 mrg are defined in gcc/vtable-verify.h. These data structures are 110 1.1 mrg shared with the code in the C++ front end that collects the class 111 1.1 mrg hierarchy & vtable information and generates the vtable map 112 1.1 mrg variables (see cp/vtable-class-hierarchy.cc). This tree pass should 113 1.1 mrg run just before the gimple is converted to RTL. 114 1.1 mrg 115 1.1 mrg Some implementation details for this pass: 116 1.1 mrg 117 1.1 mrg To find all of the virtual calls, we iterate through all the 118 1.1 mrg gimple statements in each basic block, looking for any call 119 1.1 mrg statement with the code "OBJ_TYPE_REF". Once we have found the 120 1.1 mrg virtual call, we need to find the vtable pointer through which the 121 1.1 mrg call is being made, and the type of the object containing the 122 1.1 mrg pointer (to find the appropriate vtable map variable). We then use 123 1.1 mrg these to build a call to __VLTVerifyVtablePointer, passing the 124 1.1 mrg vtable map variable, and the vtable pointer. We insert the 125 1.1 mrg verification call just after the gimple statement that gets the 126 1.1 mrg vtable pointer out of the object, and we update the next 127 1.1 mrg statement to depend on the result returned from 128 1.1 mrg __VLTVerifyVtablePointer (the vtable pointer value), to ensure 129 1.1 mrg subsequent compiler phases don't remove or reorder the call (it's no 130 1.1 mrg good to have the verification occur after the virtual call, for 131 1.1 mrg example). To find the vtable pointer being used (and the type of 132 1.1 mrg the object) we search backwards through the def_stmts chain from the 133 1.1 mrg virtual call (see verify_bb_vtables for more details). */ 134 1.1 mrg 135 1.1 mrg #include "config.h" 136 1.1 mrg #include "system.h" 137 1.1 mrg #include "coretypes.h" 138 1.1 mrg #include "backend.h" 139 1.1 mrg #include "tree.h" 140 1.1 mrg #include "gimple.h" 141 1.1 mrg #include "tree-pass.h" 142 1.1 mrg #include "ssa.h" 143 1.1 mrg #include "gimple-iterator.h" 144 1.1 mrg 145 1.1 mrg #include "vtable-verify.h" 146 1.1 mrg 147 1.1 mrg unsigned num_vtable_map_nodes = 0; 148 1.1 mrg int total_num_virtual_calls = 0; 149 1.1 mrg int total_num_verified_vcalls = 0; 150 1.1 mrg 151 1.1 mrg extern GTY(()) tree verify_vtbl_ptr_fndecl; 152 1.1 mrg tree verify_vtbl_ptr_fndecl = NULL_TREE; 153 1.1 mrg 154 1.1 mrg /* Keep track of whether or not any virtual call were verified. */ 155 1.1 mrg static bool any_verification_calls_generated = false; 156 1.1 mrg 157 1.1 mrg unsigned int vtable_verify_main (void); 158 1.1 mrg 159 1.1 mrg 160 1.1 mrg /* The following few functions are for the vtbl pointer hash table 161 1.1 mrg in the 'registered' field of the struct vtable_map_node. The hash 162 1.1 mrg table keeps track of which vtable pointers have been used in 163 1.1 mrg calls to __VLTRegisterPair with that particular vtable map variable. */ 164 1.1 mrg 165 1.1 mrg /* This function checks to see if a particular VTABLE_DECL and OFFSET are 166 1.1 mrg already in the 'registered' hash table for NODE. */ 167 1.1 mrg 168 1.1 mrg bool 169 1.1 mrg vtbl_map_node_registration_find (struct vtbl_map_node *node, 170 1.1 mrg tree vtable_decl, 171 1.1 mrg unsigned offset) 172 1.1 mrg { 173 1.1 mrg struct vtable_registration key; 174 1.1 mrg struct vtable_registration **slot; 175 1.1 mrg 176 1.1 mrg gcc_assert (node && node->registered); 177 1.1 mrg 178 1.1 mrg key.vtable_decl = vtable_decl; 179 1.1 mrg slot = node->registered->find_slot (&key, NO_INSERT); 180 1.1 mrg 181 1.1 mrg if (slot && (*slot)) 182 1.1 mrg { 183 1.1 mrg unsigned i; 184 1.1 mrg for (i = 0; i < ((*slot)->offsets).length (); ++i) 185 1.1 mrg if ((*slot)->offsets[i] == offset) 186 1.1 mrg return true; 187 1.1 mrg } 188 1.1 mrg 189 1.1 mrg return false; 190 1.1 mrg } 191 1.1 mrg 192 1.1 mrg /* This function inserts VTABLE_DECL and OFFSET into the 'registered' 193 1.1 mrg hash table for NODE. It returns a boolean indicating whether or not 194 1.1 mrg it actually inserted anything. */ 195 1.1 mrg 196 1.1 mrg bool 197 1.1 mrg vtbl_map_node_registration_insert (struct vtbl_map_node *node, 198 1.1 mrg tree vtable_decl, 199 1.1 mrg unsigned offset) 200 1.1 mrg { 201 1.1 mrg struct vtable_registration key; 202 1.1 mrg struct vtable_registration **slot; 203 1.1 mrg bool inserted_something = false; 204 1.1 mrg 205 1.1 mrg if (!node || !node->registered) 206 1.1 mrg return false; 207 1.1 mrg 208 1.1 mrg key.vtable_decl = vtable_decl; 209 1.1 mrg slot = node->registered->find_slot (&key, INSERT); 210 1.1 mrg 211 1.1 mrg if (! *slot) 212 1.1 mrg { 213 1.1 mrg struct vtable_registration *node; 214 1.1 mrg node = XNEW (struct vtable_registration); 215 1.1 mrg node->vtable_decl = vtable_decl; 216 1.1 mrg 217 1.1 mrg (node->offsets).create (10); 218 1.1 mrg (node->offsets).safe_push (offset); 219 1.1 mrg *slot = node; 220 1.1 mrg inserted_something = true; 221 1.1 mrg } 222 1.1 mrg else 223 1.1 mrg { 224 1.1 mrg /* We found the vtable_decl slot; we need to see if it already 225 1.1 mrg contains the offset. If not, we need to add the offset. */ 226 1.1 mrg unsigned i; 227 1.1 mrg bool found = false; 228 1.1 mrg for (i = 0; i < ((*slot)->offsets).length () && !found; ++i) 229 1.1 mrg if ((*slot)->offsets[i] == offset) 230 1.1 mrg found = true; 231 1.1 mrg 232 1.1 mrg if (!found) 233 1.1 mrg { 234 1.1 mrg ((*slot)->offsets).safe_push (offset); 235 1.1 mrg inserted_something = true; 236 1.1 mrg } 237 1.1 mrg } 238 1.1 mrg return inserted_something; 239 1.1 mrg } 240 1.1 mrg 241 1.1 mrg /* Hashtable functions for vtable_registration hashtables. */ 242 1.1 mrg 243 1.1 mrg inline hashval_t 244 1.1 mrg registration_hasher::hash (const vtable_registration *p) 245 1.1 mrg { 246 1.1 mrg const struct vtable_registration *n = (const struct vtable_registration *) p; 247 1.1 mrg return (hashval_t) (DECL_UID (n->vtable_decl)); 248 1.1 mrg } 249 1.1 mrg 250 1.1 mrg inline bool 251 1.1 mrg registration_hasher::equal (const vtable_registration *p1, 252 1.1 mrg const vtable_registration *p2) 253 1.1 mrg { 254 1.1 mrg const struct vtable_registration *n1 = 255 1.1 mrg (const struct vtable_registration *) p1; 256 1.1 mrg const struct vtable_registration *n2 = 257 1.1 mrg (const struct vtable_registration *) p2; 258 1.1 mrg return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl)); 259 1.1 mrg } 260 1.1 mrg 261 1.1 mrg /* End of hashtable functions for "registered" hashtables. */ 262 1.1 mrg 263 1.1 mrg 264 1.1 mrg 265 1.1 mrg /* Hashtable definition and functions for vtbl_map_hash. */ 266 1.1 mrg 267 1.1 mrg struct vtbl_map_hasher : nofree_ptr_hash <struct vtbl_map_node> 268 1.1 mrg { 269 1.1 mrg static inline hashval_t hash (const vtbl_map_node *); 270 1.1 mrg static inline bool equal (const vtbl_map_node *, const vtbl_map_node *); 271 1.1 mrg }; 272 1.1 mrg 273 1.1 mrg /* Returns a hash code for P. */ 274 1.1 mrg 275 1.1 mrg inline hashval_t 276 1.1 mrg vtbl_map_hasher::hash (const vtbl_map_node *p) 277 1.1 mrg { 278 1.1 mrg const struct vtbl_map_node n = *((const struct vtbl_map_node *) p); 279 1.1 mrg return (hashval_t) IDENTIFIER_HASH_VALUE (n.class_name); 280 1.1 mrg } 281 1.1 mrg 282 1.1 mrg /* Returns nonzero if P1 and P2 are equal. */ 283 1.1 mrg 284 1.1 mrg inline bool 285 1.1 mrg vtbl_map_hasher::equal (const vtbl_map_node *p1, const vtbl_map_node *p2) 286 1.1 mrg { 287 1.1 mrg const struct vtbl_map_node n1 = *((const struct vtbl_map_node *) p1); 288 1.1 mrg const struct vtbl_map_node n2 = *((const struct vtbl_map_node *) p2); 289 1.1 mrg return (IDENTIFIER_HASH_VALUE (n1.class_name) == 290 1.1 mrg IDENTIFIER_HASH_VALUE (n2.class_name)); 291 1.1 mrg } 292 1.1 mrg 293 1.1 mrg /* Here are the two structures into which we insert vtable map nodes. 294 1.1 mrg We use two data structures because of the vastly different ways we need 295 1.1 mrg to find the nodes for various tasks (see comments in vtable-verify.h 296 1.1 mrg for more details. */ 297 1.1 mrg 298 1.1 mrg typedef hash_table<vtbl_map_hasher> vtbl_map_table_type; 299 1.1 mrg typedef vtbl_map_table_type::iterator vtbl_map_iterator_type; 300 1.1 mrg 301 1.1 mrg /* Vtable map variable nodes stored in a hash table. */ 302 1.1 mrg static vtbl_map_table_type *vtbl_map_hash; 303 1.1 mrg 304 1.1 mrg /* Vtable map variable nodes stored in a vector. */ 305 1.1 mrg vec<struct vtbl_map_node *> vtbl_map_nodes_vec; 306 1.1 mrg 307 1.1 mrg /* Vector of mangled names for anonymous classes. */ 308 1.1 mrg extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_types; 309 1.1 mrg extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_ids; 310 1.1 mrg vec<tree, va_gc> *vtbl_mangled_name_types; 311 1.1 mrg vec<tree, va_gc> *vtbl_mangled_name_ids; 312 1.1 mrg 313 1.1 mrg /* Look up class_type (a type decl for record types) in the vtbl_mangled_names_* 314 1.1 mrg vectors. This is a linear lookup. Return the associated mangled name for 315 1.1 mrg the class type. This is for handling types from anonymous namespaces, whose 316 1.1 mrg DECL_ASSEMBLER_NAME ends up being "<anon>", which is useless for our 317 1.1 mrg purposes. 318 1.1 mrg 319 1.1 mrg We use two vectors of trees to keep track of the mangled names: One is a 320 1.1 mrg vector of class types and the other is a vector of the mangled names. The 321 1.1 mrg assumption is that these two vectors are kept in perfect lock-step so that 322 1.1 mrg vtbl_mangled_name_ids[i] is the mangled name for 323 1.1 mrg vtbl_mangled_name_types[i]. */ 324 1.1 mrg 325 1.1 mrg static tree 326 1.1 mrg vtbl_find_mangled_name (tree class_type) 327 1.1 mrg { 328 1.1 mrg tree result = NULL_TREE; 329 1.1 mrg unsigned i; 330 1.1 mrg 331 1.1 mrg if (!vtbl_mangled_name_types or !vtbl_mangled_name_ids) 332 1.1 mrg return result; 333 1.1 mrg 334 1.1 mrg if (vtbl_mangled_name_types->length() != vtbl_mangled_name_ids->length()) 335 1.1 mrg return result; 336 1.1 mrg 337 1.1 mrg for (i = 0; i < vtbl_mangled_name_types->length(); ++i) 338 1.1 mrg if ((*vtbl_mangled_name_types)[i] == class_type) 339 1.1 mrg { 340 1.1 mrg result = (*vtbl_mangled_name_ids)[i]; 341 1.1 mrg break; 342 1.1 mrg } 343 1.1 mrg 344 1.1 mrg return result; 345 1.1 mrg } 346 1.1 mrg 347 1.1 mrg /* Store a class type decl and its mangled name, for an anonymous RECORD_TYPE, 348 1.1 mrg in the vtbl_mangled_names vector. Make sure there is not already an 349 1.1 mrg entry for the class type before adding it. */ 350 1.1 mrg 351 1.1 mrg void 352 1.1 mrg vtbl_register_mangled_name (tree class_type, tree mangled_name) 353 1.1 mrg { 354 1.1 mrg if (!vtbl_mangled_name_types) 355 1.1 mrg vec_alloc (vtbl_mangled_name_types, 10); 356 1.1 mrg 357 1.1 mrg if (!vtbl_mangled_name_ids) 358 1.1 mrg vec_alloc (vtbl_mangled_name_ids, 10); 359 1.1 mrg 360 1.1 mrg gcc_assert (vtbl_mangled_name_types->length() == 361 1.1 mrg vtbl_mangled_name_ids->length()); 362 1.1 mrg 363 1.1 mrg 364 1.1 mrg if (vtbl_find_mangled_name (class_type) == NULL_TREE) 365 1.1 mrg { 366 1.1 mrg vec_safe_push (vtbl_mangled_name_types, class_type); 367 1.1 mrg vec_safe_push (vtbl_mangled_name_ids, mangled_name); 368 1.1 mrg } 369 1.1 mrg } 370 1.1 mrg 371 1.1 mrg /* Return vtbl_map node for CLASS_NAME without creating a new one. */ 372 1.1 mrg 373 1.1 mrg struct vtbl_map_node * 374 1.1 mrg vtbl_map_get_node (tree class_type) 375 1.1 mrg { 376 1.1 mrg struct vtbl_map_node key; 377 1.1 mrg struct vtbl_map_node **slot; 378 1.1 mrg 379 1.1 mrg tree class_type_decl; 380 1.1 mrg tree class_name; 381 1.1 mrg unsigned int type_quals; 382 1.1 mrg 383 1.1 mrg if (!vtbl_map_hash) 384 1.1 mrg return NULL; 385 1.1 mrg 386 1.1 mrg gcc_assert (TREE_CODE (class_type) == RECORD_TYPE); 387 1.1 mrg 388 1.1 mrg 389 1.1 mrg /* Find the TYPE_DECL for the class. */ 390 1.1 mrg class_type_decl = TYPE_NAME (class_type); 391 1.1 mrg 392 1.1 mrg /* Verify that there aren't any qualifiers on the type. */ 393 1.1 mrg type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl)); 394 1.1 mrg gcc_assert (type_quals == TYPE_UNQUALIFIED); 395 1.1 mrg 396 1.1 mrg /* Get the mangled name for the unqualified type. */ 397 1.1 mrg gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl)); 398 1.1 mrg class_name = DECL_ASSEMBLER_NAME (class_type_decl); 399 1.1 mrg 400 1.1 mrg if (strstr (IDENTIFIER_POINTER (class_name), "<anon>") != NULL) 401 1.1 mrg class_name = vtbl_find_mangled_name (class_type_decl); 402 1.1 mrg 403 1.1 mrg key.class_name = class_name; 404 1.1 mrg slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, NO_INSERT); 405 1.1 mrg if (!slot) 406 1.1 mrg return NULL; 407 1.1 mrg return *slot; 408 1.1 mrg } 409 1.1 mrg 410 1.1 mrg /* Return vtbl_map node assigned to BASE_CLASS_TYPE. Create new one 411 1.1 mrg when needed. */ 412 1.1 mrg 413 1.1 mrg struct vtbl_map_node * 414 1.1 mrg find_or_create_vtbl_map_node (tree base_class_type) 415 1.1 mrg { 416 1.1 mrg struct vtbl_map_node key; 417 1.1 mrg struct vtbl_map_node *node; 418 1.1 mrg struct vtbl_map_node **slot; 419 1.1 mrg tree class_type_decl; 420 1.1 mrg unsigned int type_quals; 421 1.1 mrg 422 1.1 mrg if (!vtbl_map_hash) 423 1.1 mrg vtbl_map_hash = new vtbl_map_table_type (10); 424 1.1 mrg 425 1.1 mrg /* Find the TYPE_DECL for the class. */ 426 1.1 mrg class_type_decl = TYPE_NAME (base_class_type); 427 1.1 mrg 428 1.1 mrg /* Verify that there aren't any type qualifiers on type. */ 429 1.1 mrg type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl)); 430 1.1 mrg gcc_assert (type_quals == TYPE_UNQUALIFIED); 431 1.1 mrg 432 1.1 mrg gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl)); 433 1.1 mrg key.class_name = DECL_ASSEMBLER_NAME (class_type_decl); 434 1.1 mrg 435 1.1 mrg if (strstr (IDENTIFIER_POINTER (key.class_name), "<anon>") != NULL) 436 1.1 mrg key.class_name = vtbl_find_mangled_name (class_type_decl); 437 1.1 mrg 438 1.1 mrg slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, INSERT); 439 1.1 mrg 440 1.1 mrg if (*slot) 441 1.1 mrg return *slot; 442 1.1 mrg 443 1.1 mrg node = XNEW (struct vtbl_map_node); 444 1.1 mrg node->vtbl_map_decl = NULL_TREE; 445 1.1 mrg node->class_name = key.class_name; 446 1.1 mrg node->uid = num_vtable_map_nodes++; 447 1.1 mrg 448 1.1 mrg node->class_info = XNEW (struct vtv_graph_node); 449 1.1 mrg node->class_info->class_type = base_class_type; 450 1.1 mrg node->class_info->class_uid = node->uid; 451 1.1 mrg node->class_info->num_processed_children = 0; 452 1.1 mrg 453 1.1 mrg (node->class_info->parents).create (4); 454 1.1 mrg (node->class_info->children).create (4); 455 1.1 mrg 456 1.1 mrg node->registered = new register_table_type (16); 457 1.1 mrg 458 1.1 mrg node->is_used = false; 459 1.1 mrg 460 1.1 mrg vtbl_map_nodes_vec.safe_push (node); 461 1.1 mrg gcc_assert (vtbl_map_nodes_vec[node->uid] == node); 462 1.1 mrg 463 1.1 mrg *slot = node; 464 1.1 mrg return node; 465 1.1 mrg } 466 1.1 mrg 467 1.1 mrg /* End of hashtable functions for vtable_map variables hash table. */ 468 1.1 mrg 469 1.1 mrg /* Given a gimple STMT, this function checks to see if the statement 470 1.1 mrg is an assignment, the rhs of which is getting the vtable pointer 471 1.1 mrg value out of an object. (i.e. it's the value we need to verify 472 1.1 mrg because its the vtable pointer that will be used for a virtual 473 1.1 mrg call). */ 474 1.1 mrg 475 1.1 mrg static bool 476 1.1 mrg is_vtable_assignment_stmt (gimple *stmt) 477 1.1 mrg { 478 1.1 mrg 479 1.1 mrg if (gimple_code (stmt) != GIMPLE_ASSIGN) 480 1.1 mrg return false; 481 1.1 mrg else 482 1.1 mrg { 483 1.1 mrg tree lhs = gimple_assign_lhs (stmt); 484 1.1 mrg tree rhs = gimple_assign_rhs1 (stmt); 485 1.1 mrg 486 1.1 mrg if (TREE_CODE (lhs) != SSA_NAME) 487 1.1 mrg return false; 488 1.1 mrg 489 1.1 mrg if (TREE_CODE (rhs) != COMPONENT_REF) 490 1.1 mrg return false; 491 1.1 mrg 492 1.1 mrg if (! (TREE_OPERAND (rhs, 1)) 493 1.1 mrg || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL)) 494 1.1 mrg return false; 495 1.1 mrg 496 1.1 mrg if (! DECL_VIRTUAL_P (TREE_OPERAND (rhs, 1))) 497 1.1 mrg return false; 498 1.1 mrg } 499 1.1 mrg 500 1.1 mrg return true; 501 1.1 mrg } 502 1.1 mrg 503 1.1 mrg /* This function attempts to recover the declared class of an object 504 1.1 mrg that is used in making a virtual call. We try to get the type from 505 1.1 mrg the type cast in the gimple assignment statement that extracts the 506 1.1 mrg vtable pointer from the object (DEF_STMT). The gimple statement 507 1.1 mrg usually looks something like this: 508 1.1 mrg 509 1.1 mrg D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event */ 510 1.1 mrg 511 1.1 mrg static tree 512 1.1 mrg extract_object_class_type (tree rhs) 513 1.1 mrg { 514 1.1 mrg tree result = NULL_TREE; 515 1.1 mrg 516 1.1 mrg /* Try to find and extract the type cast from that stmt. */ 517 1.1 mrg if (TREE_CODE (rhs) == COMPONENT_REF) 518 1.1 mrg { 519 1.1 mrg tree op0 = TREE_OPERAND (rhs, 0); 520 1.1 mrg tree op1 = TREE_OPERAND (rhs, 1); 521 1.1 mrg 522 1.1 mrg if (TREE_CODE (op1) == FIELD_DECL 523 1.1 mrg && DECL_VIRTUAL_P (op1)) 524 1.1 mrg { 525 1.1 mrg if (TREE_CODE (op0) == COMPONENT_REF 526 1.1 mrg && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF 527 1.1 mrg && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE) 528 1.1 mrg result = TREE_TYPE (TREE_OPERAND (op0, 0)); 529 1.1 mrg else 530 1.1 mrg result = TREE_TYPE (op0); 531 1.1 mrg } 532 1.1 mrg else if (TREE_CODE (op0) == COMPONENT_REF) 533 1.1 mrg { 534 1.1 mrg result = extract_object_class_type (op0); 535 1.1 mrg if (result == NULL_TREE 536 1.1 mrg && TREE_CODE (op1) == COMPONENT_REF) 537 1.1 mrg result = extract_object_class_type (op1); 538 1.1 mrg } 539 1.1 mrg } 540 1.1 mrg 541 1.1 mrg return result; 542 1.1 mrg } 543 1.1 mrg 544 1.1 mrg /* This function traces forward through the def-use chain of an SSA 545 1.1 mrg variable to see if it ever gets used in a virtual function call. It 546 1.1 mrg returns a boolean indicating whether or not it found a virtual call in 547 1.1 mrg the use chain. */ 548 1.1 mrg 549 1.1 mrg static bool 550 1.1 mrg var_is_used_for_virtual_call_p (tree lhs, int *mem_ref_depth, 551 1.1 mrg int *recursion_depth) 552 1.1 mrg { 553 1.1 mrg imm_use_iterator imm_iter; 554 1.1 mrg bool found_vcall = false; 555 1.1 mrg use_operand_p use_p; 556 1.1 mrg 557 1.1 mrg if (TREE_CODE (lhs) != SSA_NAME) 558 1.1 mrg return false; 559 1.1 mrg 560 1.1 mrg if (*mem_ref_depth > 2) 561 1.1 mrg return false; 562 1.1 mrg 563 1.1 mrg if (*recursion_depth > 25) 564 1.1 mrg /* If we've recursed this far the chances are pretty good that 565 1.1 mrg we're not going to find what we're looking for, and that we've 566 1.1 mrg gone down a recursion black hole. Time to stop. */ 567 1.1 mrg return false; 568 1.1 mrg 569 1.1 mrg *recursion_depth = *recursion_depth + 1; 570 1.1 mrg 571 1.1 mrg /* Iterate through the immediate uses of the current variable. If 572 1.1 mrg it's a virtual function call, we're done. Otherwise, if there's 573 1.1 mrg an LHS for the use stmt, add the ssa var to the work list 574 1.1 mrg (assuming it's not already in the list and is not a variable 575 1.1 mrg we've already examined. */ 576 1.1 mrg 577 1.1 mrg FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) 578 1.1 mrg { 579 1.1 mrg gimple *stmt2 = USE_STMT (use_p); 580 1.1 mrg 581 1.1 mrg if (is_gimple_call (stmt2)) 582 1.1 mrg { 583 1.1 mrg tree fncall = gimple_call_fn (stmt2); 584 1.1 mrg if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF) 585 1.1 mrg found_vcall = true; 586 1.1 mrg else 587 1.1 mrg return false; 588 1.1 mrg } 589 1.1 mrg else if (gimple_code (stmt2) == GIMPLE_PHI) 590 1.1 mrg { 591 1.1 mrg found_vcall = var_is_used_for_virtual_call_p 592 1.1 mrg (gimple_phi_result (stmt2), 593 1.1 mrg mem_ref_depth, 594 1.1 mrg recursion_depth); 595 1.1 mrg } 596 1.1 mrg else if (is_gimple_assign (stmt2)) 597 1.1 mrg { 598 1.1 mrg tree rhs = gimple_assign_rhs1 (stmt2); 599 1.1 mrg if (TREE_CODE (rhs) == ADDR_EXPR 600 1.1 mrg || TREE_CODE (rhs) == MEM_REF) 601 1.1 mrg *mem_ref_depth = *mem_ref_depth + 1; 602 1.1 mrg 603 1.1 mrg if (TREE_CODE (rhs) == COMPONENT_REF) 604 1.1 mrg { 605 1.1 mrg while (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF) 606 1.1 mrg rhs = TREE_OPERAND (rhs, 0); 607 1.1 mrg 608 1.1 mrg if (TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR 609 1.1 mrg || TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF) 610 1.1 mrg *mem_ref_depth = *mem_ref_depth + 1; 611 1.1 mrg } 612 1.1 mrg 613 1.1 mrg if (*mem_ref_depth < 3) 614 1.1 mrg found_vcall = var_is_used_for_virtual_call_p 615 1.1 mrg (gimple_assign_lhs (stmt2), 616 1.1 mrg mem_ref_depth, 617 1.1 mrg recursion_depth); 618 1.1 mrg } 619 1.1 mrg 620 1.1 mrg else 621 1.1 mrg break; 622 1.1 mrg 623 1.1 mrg if (found_vcall) 624 1.1 mrg return true; 625 1.1 mrg } 626 1.1 mrg 627 1.1 mrg return false; 628 1.1 mrg } 629 1.1 mrg 630 1.1 mrg /* Search through all the statements in a basic block (BB), searching 631 1.1 mrg for virtual method calls. For each virtual method dispatch, find 632 1.1 mrg the vptr value used, and the statically declared type of the 633 1.1 mrg object; retrieve the vtable map variable for the type of the 634 1.1 mrg object; generate a call to __VLTVerifyVtablePointer; and insert the 635 1.1 mrg generated call into the basic block, after the point where the vptr 636 1.1 mrg value is gotten out of the object and before the virtual method 637 1.1 mrg dispatch. Make the virtual method dispatch depend on the return 638 1.1 mrg value from the verification call, so that subsequent optimizations 639 1.1 mrg cannot reorder the two calls. */ 640 1.1 mrg 641 1.1 mrg static void 642 1.1 mrg verify_bb_vtables (basic_block bb) 643 1.1 mrg { 644 1.1 mrg gimple_seq stmts; 645 1.1 mrg gimple *stmt = NULL; 646 1.1 mrg gimple_stmt_iterator gsi_vtbl_assign; 647 1.1 mrg gimple_stmt_iterator gsi_virtual_call; 648 1.1 mrg 649 1.1 mrg stmts = bb_seq (bb); 650 1.1 mrg gsi_virtual_call = gsi_start (stmts); 651 1.1 mrg for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call)) 652 1.1 mrg { 653 1.1 mrg stmt = gsi_stmt (gsi_virtual_call); 654 1.1 mrg 655 1.1 mrg /* Count virtual calls. */ 656 1.1 mrg if (is_gimple_call (stmt)) 657 1.1 mrg { 658 1.1 mrg tree fncall = gimple_call_fn (stmt); 659 1.1 mrg if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF) 660 1.1 mrg total_num_virtual_calls++; 661 1.1 mrg } 662 1.1 mrg 663 1.1 mrg if (is_vtable_assignment_stmt (stmt)) 664 1.1 mrg { 665 1.1 mrg tree lhs = gimple_assign_lhs (stmt); 666 1.1 mrg tree vtbl_var_decl = NULL_TREE; 667 1.1 mrg struct vtbl_map_node *vtable_map_node; 668 1.1 mrg tree vtbl_decl = NULL_TREE; 669 1.1 mrg gcall *call_stmt; 670 1.1 mrg const char *vtable_name = "<unknown>"; 671 1.1 mrg tree tmp0; 672 1.1 mrg bool found; 673 1.1 mrg int mem_ref_depth = 0; 674 1.1 mrg int recursion_depth = 0; 675 1.1 mrg 676 1.1 mrg /* Make sure this vptr field access is for a virtual call. */ 677 1.1 mrg if (!var_is_used_for_virtual_call_p (lhs, &mem_ref_depth, 678 1.1 mrg &recursion_depth)) 679 1.1 mrg continue; 680 1.1 mrg 681 1.1 mrg /* Now we have found the virtual method dispatch and 682 1.1 mrg the preceding access of the _vptr.* field... Next 683 1.1 mrg we need to find the statically declared type of 684 1.1 mrg the object, so we can find and use the right 685 1.1 mrg vtable map variable in the verification call. */ 686 1.1 mrg tree class_type = extract_object_class_type 687 1.1 mrg (gimple_assign_rhs1 (stmt)); 688 1.1 mrg 689 1.1 mrg gsi_vtbl_assign = gsi_for_stmt (stmt); 690 1.1 mrg 691 1.1 mrg if (class_type 692 1.1 mrg && (TREE_CODE (class_type) == RECORD_TYPE) 693 1.1 mrg && TYPE_BINFO (class_type)) 694 1.1 mrg { 695 1.1 mrg /* Get the vtable VAR_DECL for the type. */ 696 1.1 mrg vtbl_var_decl = BINFO_VTABLE (TYPE_BINFO (class_type)); 697 1.1 mrg 698 1.1 mrg if (TREE_CODE (vtbl_var_decl) == POINTER_PLUS_EXPR) 699 1.1 mrg vtbl_var_decl = TREE_OPERAND (TREE_OPERAND (vtbl_var_decl, 0), 700 1.1 mrg 0); 701 1.1 mrg 702 1.1 mrg gcc_assert (vtbl_var_decl); 703 1.1 mrg 704 1.1 mrg vtbl_decl = vtbl_var_decl; 705 1.1 mrg vtable_map_node = vtbl_map_get_node 706 1.1 mrg (TYPE_MAIN_VARIANT (class_type)); 707 1.1 mrg 708 1.1 mrg gcc_assert (verify_vtbl_ptr_fndecl); 709 1.1 mrg 710 1.1 mrg /* Given the vtable pointer for the base class of the 711 1.1 mrg object, build the call to __VLTVerifyVtablePointer to 712 1.1 mrg verify that the object's vtable pointer (contained in 713 1.1 mrg lhs) is in the set of valid vtable pointers for the 714 1.1 mrg base class. */ 715 1.1 mrg 716 1.1 mrg if (vtable_map_node && vtable_map_node->vtbl_map_decl) 717 1.1 mrg { 718 1.1 mrg vtable_map_node->is_used = true; 719 1.1 mrg vtbl_var_decl = vtable_map_node->vtbl_map_decl; 720 1.1 mrg 721 1.1 mrg if (VAR_P (vtbl_decl)) 722 1.1 mrg vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl)); 723 1.1 mrg 724 1.1 mrg /* Call different routines if we are interested in 725 1.1 mrg trace information to debug problems. */ 726 1.1 mrg if (flag_vtv_debug) 727 1.1 mrg { 728 1.1 mrg int len1 = IDENTIFIER_LENGTH 729 1.1 mrg (DECL_NAME (vtbl_var_decl)); 730 1.1 mrg int len2 = strlen (vtable_name); 731 1.1 mrg 732 1.1 mrg call_stmt = gimple_build_call 733 1.1 mrg (verify_vtbl_ptr_fndecl, 4, 734 1.1 mrg build1 (ADDR_EXPR, 735 1.1 mrg TYPE_POINTER_TO 736 1.1 mrg (TREE_TYPE (vtbl_var_decl)), 737 1.1 mrg vtbl_var_decl), 738 1.1 mrg lhs, 739 1.1 mrg build_string_literal 740 1.1 mrg (len1 + 1, 741 1.1 mrg IDENTIFIER_POINTER 742 1.1 mrg (DECL_NAME 743 1.1 mrg (vtbl_var_decl))), 744 1.1 mrg build_string_literal (len2 + 1, 745 1.1 mrg vtable_name)); 746 1.1 mrg } 747 1.1 mrg else 748 1.1 mrg call_stmt = gimple_build_call 749 1.1 mrg (verify_vtbl_ptr_fndecl, 2, 750 1.1 mrg build1 (ADDR_EXPR, 751 1.1 mrg TYPE_POINTER_TO 752 1.1 mrg (TREE_TYPE (vtbl_var_decl)), 753 1.1 mrg vtbl_var_decl), 754 1.1 mrg lhs); 755 1.1 mrg 756 1.1 mrg 757 1.1 mrg /* Create a new SSA_NAME var to hold the call's 758 1.1 mrg return value, and make the call_stmt use the 759 1.1 mrg variable for that purpose. */ 760 1.1 mrg tmp0 = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "VTV"); 761 1.1 mrg gimple_call_set_lhs (call_stmt, tmp0); 762 1.1 mrg update_stmt (call_stmt); 763 1.1 mrg 764 1.1 mrg /* Replace all uses of lhs with tmp0. */ 765 1.1 mrg found = false; 766 1.1 mrg imm_use_iterator iterator; 767 1.1 mrg gimple *use_stmt; 768 1.1 mrg FOR_EACH_IMM_USE_STMT (use_stmt, iterator, lhs) 769 1.1 mrg { 770 1.1 mrg use_operand_p use_p; 771 1.1 mrg if (use_stmt == call_stmt) 772 1.1 mrg continue; 773 1.1 mrg FOR_EACH_IMM_USE_ON_STMT (use_p, iterator) 774 1.1 mrg SET_USE (use_p, tmp0); 775 1.1 mrg update_stmt (use_stmt); 776 1.1 mrg found = true; 777 1.1 mrg } 778 1.1 mrg 779 1.1 mrg gcc_assert (found); 780 1.1 mrg 781 1.1 mrg /* Insert the new verification call just after the 782 1.1 mrg statement that gets the vtable pointer out of the 783 1.1 mrg object. */ 784 1.1 mrg gcc_assert (gsi_stmt (gsi_vtbl_assign) == stmt); 785 1.1 mrg gsi_insert_after (&gsi_vtbl_assign, call_stmt, 786 1.1 mrg GSI_NEW_STMT); 787 1.1 mrg 788 1.1 mrg any_verification_calls_generated = true; 789 1.1 mrg total_num_verified_vcalls++; 790 1.1 mrg } 791 1.1 mrg } 792 1.1 mrg } 793 1.1 mrg } 794 1.1 mrg } 795 1.1 mrg 796 1.1 mrg /* Definition of this optimization pass. */ 797 1.1 mrg 798 1.1 mrg namespace { 799 1.1 mrg 800 1.1 mrg const pass_data pass_data_vtable_verify = 801 1.1 mrg { 802 1.1 mrg GIMPLE_PASS, /* type */ 803 1.1 mrg "vtable-verify", /* name */ 804 1.1 mrg OPTGROUP_NONE, /* optinfo_flags */ 805 1.1 mrg TV_VTABLE_VERIFICATION, /* tv_id */ 806 1.1 mrg ( PROP_cfg | PROP_ssa ), /* properties_required */ 807 1.1 mrg 0, /* properties_provided */ 808 1.1 mrg 0, /* properties_destroyed */ 809 1.1 mrg 0, /* todo_flags_start */ 810 1.1 mrg TODO_update_ssa, /* todo_flags_finish */ 811 1.1 mrg }; 812 1.1 mrg 813 1.1 mrg class pass_vtable_verify : public gimple_opt_pass 814 1.1 mrg { 815 1.1 mrg public: 816 1.1 mrg pass_vtable_verify (gcc::context *ctxt) 817 1.1 mrg : gimple_opt_pass (pass_data_vtable_verify, ctxt) 818 1.1 mrg {} 819 1.1 mrg 820 1.1 mrg /* opt_pass methods: */ 821 1.1 mrg virtual bool gate (function *) { return (flag_vtable_verify); } 822 1.1 mrg virtual unsigned int execute (function *); 823 1.1 mrg 824 1.1 mrg }; // class pass_vtable_verify 825 1.1 mrg 826 1.1 mrg /* Loop through all the basic blocks in the current function, passing them to 827 1.1 mrg verify_bb_vtables, which searches for virtual calls, and inserts 828 1.1 mrg calls to __VLTVerifyVtablePointer. */ 829 1.1 mrg 830 1.1 mrg unsigned int 831 1.1 mrg pass_vtable_verify::execute (function *fun) 832 1.1 mrg { 833 1.1 mrg unsigned int ret = 1; 834 1.1 mrg basic_block bb; 835 1.1 mrg 836 1.1 mrg FOR_ALL_BB_FN (bb, fun) 837 1.1 mrg verify_bb_vtables (bb); 838 1.1 mrg 839 1.1 mrg return ret; 840 1.1 mrg } 841 1.1 mrg 842 1.1 mrg } // anon namespace 843 1.1 mrg 844 1.1 mrg gimple_opt_pass * 845 1.1 mrg make_pass_vtable_verify (gcc::context *ctxt) 846 1.1 mrg { 847 1.1 mrg return new pass_vtable_verify (ctxt); 848 1.1 mrg } 849 1.1 mrg 850 1.1 mrg #include "gt-vtable-verify.h" 851