LCOV - code coverage report
Current view: top level - gcc/cp - cp-ubsan.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 141 142 99.3 %
Date: 2020-03-28 11:57:23 Functions: 11 11 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* UndefinedBehaviorSanitizer, undefined behavior detector.
       2                 :            :    Copyright (C) 2014-2020 Free Software Foundation, Inc.
       3                 :            :    Contributed by Jakub Jelinek <jakub@redhat.com>
       4                 :            : 
       5                 :            : This file is part of GCC.
       6                 :            : 
       7                 :            : GCC is free software; you can redistribute it and/or modify it under
       8                 :            : the terms of the GNU General Public License as published by the Free
       9                 :            : Software Foundation; either version 3, or (at your option) any later
      10                 :            : version.
      11                 :            : 
      12                 :            : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13                 :            : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14                 :            : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15                 :            : 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                 :            : #include "config.h"
      22                 :            : #include "system.h"
      23                 :            : #include "coretypes.h"
      24                 :            : #include "cp-tree.h"
      25                 :            : #include "ubsan.h"
      26                 :            : #include "stringpool.h"
      27                 :            : #include "attribs.h"
      28                 :            : #include "asan.h"
      29                 :            : 
      30                 :            : /* Test if we should instrument vptr access.  */
      31                 :            : 
      32                 :            : static bool
      33                 :      11557 : cp_ubsan_instrument_vptr_p (tree type)
      34                 :            : {
      35                 :      11557 :   if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
      36                 :            :     return false;
      37                 :            : 
      38                 :      11361 :   if (!sanitize_flags_p (SANITIZE_VPTR))
      39                 :            :     return false;
      40                 :            : 
      41                 :      11361 :   if (current_function_decl == NULL_TREE)
      42                 :            :     return false;
      43                 :            : 
      44                 :      11361 :   if (type)
      45                 :            :     {
      46                 :       5322 :       type = TYPE_MAIN_VARIANT (type);
      47                 :      10644 :       if (!CLASS_TYPE_P (type) || !CLASSTYPE_VTABLES (type))
      48                 :       3294 :         return false;
      49                 :            :     }
      50                 :            : 
      51                 :            :   return true;
      52                 :            : }
      53                 :            : 
      54                 :            : /* Helper function for
      55                 :            :    cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
      56                 :            :    Instrument vptr access.  */
      57                 :            : 
      58                 :            : static tree
      59                 :       2028 : cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr,
      60                 :            :                           enum ubsan_null_ckind ckind)
      61                 :            : {
      62                 :       2028 :   type = TYPE_MAIN_VARIANT (type);
      63                 :       2028 :   const char *mangled = mangle_type_string (type);
      64                 :       2028 :   hashval_t str_hash1 = htab_hash_string (mangled);
      65                 :       2028 :   hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0);
      66                 :       2028 :   tree str_hash = wide_int_to_tree (uint64_type_node,
      67                 :       4056 :                                     wi::uhwi (((uint64_t) str_hash1 << 32)
      68                 :       2028 :                                               | str_hash2, 64));
      69                 :       2028 :   if (!is_addr)
      70                 :        577 :     op = build_fold_addr_expr_loc (loc, op);
      71                 :       2028 :   op = save_expr (op);
      72                 :       4056 :   tree vptr = fold_build3_loc (loc, COMPONENT_REF,
      73                 :       2028 :                                TREE_TYPE (TYPE_VFIELD (type)),
      74                 :            :                                build_fold_indirect_ref_loc (loc, op),
      75                 :       2028 :                                TYPE_VFIELD (type), NULL_TREE);
      76                 :       2028 :   vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr);
      77                 :       2028 :   vptr = fold_convert_loc (loc, uint64_type_node, vptr);
      78                 :       2028 :   if (ckind == UBSAN_DOWNCAST_POINTER)
      79                 :            :     {
      80                 :        228 :       tree cond = build2_loc (loc, NE_EXPR, boolean_type_node, op,
      81                 :        114 :                               build_zero_cst (TREE_TYPE (op)));
      82                 :            :       /* This is a compiler generated comparison, don't emit
      83                 :            :          e.g. -Wnonnull-compare warning for it.  */
      84                 :        114 :       TREE_NO_WARNING (cond) = 1;
      85                 :        228 :       vptr = build3_loc (loc, COND_EXPR, uint64_type_node, cond,
      86                 :        114 :                          vptr, build_int_cst (uint64_type_node, 0));
      87                 :            :     }
      88                 :       2028 :   tree ti_decl = get_tinfo_decl (type);
      89                 :       2028 :   mark_used (ti_decl);
      90                 :       2028 :   tree ptype = build_pointer_type (type);
      91                 :       2028 :   tree call
      92                 :       2028 :     = build_call_expr_internal_loc (loc, IFN_UBSAN_VPTR,
      93                 :            :                                     void_type_node, 5, op, vptr, str_hash,
      94                 :            :                                     build_address (ti_decl),
      95                 :            :                                     build_int_cst (ptype, ckind));
      96                 :       2028 :   TREE_SIDE_EFFECTS (call) = 1;
      97                 :       2028 :   return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
      98                 :            : }
      99                 :            : 
     100                 :            : /* Helper function for
     101                 :            :    cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
     102                 :            :    Instrument vptr access if it should be instrumented, otherwise return
     103                 :            :    NULL_TREE.  */
     104                 :            : 
     105                 :            : static tree
     106                 :       3379 : cp_ubsan_maybe_instrument_vptr (location_t loc, tree op, tree type,
     107                 :            :                                 bool is_addr, enum ubsan_null_ckind ckind)
     108                 :            : {
     109                 :       3379 :   if (!cp_ubsan_instrument_vptr_p (type))
     110                 :            :     return NULL_TREE;
     111                 :       1451 :   return cp_ubsan_instrument_vptr (loc, op, type, is_addr, ckind);
     112                 :            : }
     113                 :            : 
     114                 :            : /* Instrument a member call (but not constructor call) if needed.  */
     115                 :            : 
     116                 :            : void
     117                 :       3201 : cp_ubsan_maybe_instrument_member_call (tree stmt)
     118                 :            : {
     119                 :       3201 :   if (call_expr_nargs (stmt) == 0)
     120                 :            :     return;
     121                 :       3201 :   tree *opp = &CALL_EXPR_ARG (stmt, 0);
     122                 :       3201 :   tree op = *opp;
     123                 :       3201 :   if (op == error_mark_node
     124                 :       6402 :       || !INDIRECT_TYPE_P (TREE_TYPE (op)))
     125                 :            :     return;
     126                 :       5123 :   while (TREE_CODE (op) == COMPOUND_EXPR)
     127                 :            :     {
     128                 :       1922 :       opp = &TREE_OPERAND (op, 1);
     129                 :       1922 :       op = *opp;
     130                 :            :     }
     131                 :       3201 :   op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
     132                 :       3201 :                                        TREE_TYPE (TREE_TYPE (op)),
     133                 :            :                                        true, UBSAN_MEMBER_CALL);
     134                 :       3201 :   if (op)
     135                 :       1273 :     *opp = op;
     136                 :            : }
     137                 :            : 
     138                 :            : /* Data passed to cp_ubsan_check_member_access_r.  */
     139                 :            : 
     140                 :            : struct cp_ubsan_check_member_access_data
     141                 :            : {
     142                 :            :   hash_set<tree> *pset;
     143                 :            :   bool is_addr;
     144                 :            : };
     145                 :            : 
     146                 :            : static tree cp_ubsan_check_member_access_r (tree *, int *, void *);
     147                 :            : 
     148                 :            : /* Instrument a member access.  */
     149                 :            : 
     150                 :            : static bool
     151                 :       6206 : cp_ubsan_maybe_instrument_member_access
     152                 :            :      (tree stmt, cp_ubsan_check_member_access_data *ucmd)
     153                 :            : {
     154                 :       6206 :   if (DECL_ARTIFICIAL (TREE_OPERAND (stmt, 1)))
     155                 :            :     return false;
     156                 :            : 
     157                 :       1943 :   tree base = TREE_OPERAND (stmt, 0);
     158                 :       1943 :   if (!cp_ubsan_instrument_vptr_p (TREE_TYPE (base)))
     159                 :            :     return false;
     160                 :            : 
     161                 :        577 :   cp_walk_tree (&base, cp_ubsan_check_member_access_r, ucmd, ucmd->pset);
     162                 :            : 
     163                 :        577 :   base = cp_ubsan_instrument_vptr (EXPR_LOCATION (stmt), base,
     164                 :        577 :                                    TREE_TYPE (base), false,
     165                 :            :                                    UBSAN_MEMBER_ACCESS);
     166                 :        577 :   TREE_OPERAND (stmt, 0)
     167                 :       1154 :     = build_fold_indirect_ref_loc (EXPR_LOCATION (stmt), base);
     168                 :        577 :   return true;
     169                 :            : }
     170                 :            : 
     171                 :            : /* Attempt to instrument member accesses inside of the function.
     172                 :            :    cp_ubsan_maybe_instrument_member_access should be called on COMPONENT_REFs
     173                 :            :    in the GENERIC IL, but only when the field is actually accessed, not
     174                 :            :    merely when it's address is taken.  Therefore we track in is_addr field
     175                 :            :    whether in the current context we are processing address taken
     176                 :            :    handled components or not.  E.g. for &x->y[w->z] we want to call
     177                 :            :    cp_ubsan_maybe_instrument_member_access on *w.z COMPONENT_REF, but
     178                 :            :    not on *x.y.  */
     179                 :            : 
     180                 :            : static tree
     181                 :     176731 : cp_ubsan_check_member_access_r (tree *stmt_p, int *walk_subtrees, void *data)
     182                 :            : {
     183                 :     176731 :   tree stmt = *stmt_p, t;
     184                 :     176731 :   cp_ubsan_check_member_access_data *ucmd
     185                 :            :     = (cp_ubsan_check_member_access_data *) data;
     186                 :     176731 :   switch (TREE_CODE (stmt))
     187                 :            :     {
     188                 :      13877 :     case ADDR_EXPR:
     189                 :      13877 :       t = TREE_OPERAND (stmt, 0);
     190                 :      13877 :       while ((TREE_CODE (t) == MEM_REF || INDIRECT_REF_P (t))
     191                 :      13877 :              && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
     192                 :          0 :         t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
     193                 :      13877 :       if (handled_component_p (t))
     194                 :            :         {
     195                 :       1398 :           *walk_subtrees = 0;
     196                 :       1398 :           ucmd->is_addr = true;
     197                 :       1398 :           cp_walk_tree (&t, cp_ubsan_check_member_access_r,
     198                 :            :                         data, ucmd->pset);
     199                 :       1398 :           ucmd->is_addr = false;
     200                 :            :         }
     201                 :            :       break;
     202                 :       5639 :     case MEM_REF:
     203                 :       5639 :     case INDIRECT_REF:
     204                 :       5639 :       t = TREE_OPERAND (stmt, 0);
     205                 :       5639 :       if (TREE_CODE (t) == ADDR_EXPR)
     206                 :            :         {
     207                 :         29 :           *walk_subtrees = 0;
     208                 :         29 :           t = TREE_OPERAND (t, 0);
     209                 :         29 :           cp_walk_tree (&t, cp_ubsan_check_member_access_r, data, ucmd->pset);
     210                 :            :         }
     211                 :            :       break;
     212                 :       7809 :     case COMPONENT_REF:
     213                 :       7809 :       if (!ucmd->is_addr && cp_ubsan_maybe_instrument_member_access (stmt, ucmd))
     214                 :            :         {
     215                 :        577 :           *walk_subtrees = 0;
     216                 :        577 :           break;
     217                 :            :         }
     218                 :            :       /* FALLTHRU */
     219                 :     156638 :     default:
     220                 :     156638 :       if (ucmd->is_addr && handled_component_p (stmt))
     221                 :            :         {
     222                 :       1648 :           int i, len = TREE_OPERAND_LENGTH (stmt);
     223                 :       1648 :           *walk_subtrees = 0;
     224                 :       1648 :           if (!handled_component_p (TREE_OPERAND (stmt, 0)))
     225                 :       1398 :             ucmd->is_addr = false;
     226                 :       6637 :           for (i = 0; i < len; i++)
     227                 :            :             {
     228                 :       4989 :               cp_walk_tree (&TREE_OPERAND (stmt, i),
     229                 :            :                             cp_ubsan_check_member_access_r, data, ucmd->pset);
     230                 :       4989 :               ucmd->is_addr = false;
     231                 :            :             }
     232                 :       1648 :           ucmd->is_addr = true;
     233                 :            :         }
     234                 :            :       break;
     235                 :            :     }
     236                 :     176731 :   return NULL_TREE;
     237                 :            : }
     238                 :            : 
     239                 :            : /* Instrument all member accesses inside GENERIC *T_P.  */
     240                 :            : 
     241                 :            : void
     242                 :       5644 : cp_ubsan_instrument_member_accesses (tree *t_p)
     243                 :            : {
     244                 :       5644 :   if (cp_ubsan_instrument_vptr_p (NULL_TREE))
     245                 :            :     {
     246                 :      10896 :       hash_set<tree> pset;
     247                 :       5448 :       cp_ubsan_check_member_access_data ucmd;
     248                 :       5448 :       ucmd.pset = &pset;
     249                 :       5448 :       ucmd.is_addr = false;
     250                 :       5448 :       cp_walk_tree (t_p, cp_ubsan_check_member_access_r, &ucmd, &pset);
     251                 :            :     }
     252                 :       5644 : }
     253                 :            : 
     254                 :            : /* Instrument downcast.  */
     255                 :            : 
     256                 :            : tree
     257                 :        267 : cp_ubsan_maybe_instrument_downcast (location_t loc, tree type,
     258                 :            :                                     tree intype, tree op)
     259                 :            : {
     260                 :        267 :   if (!INDIRECT_TYPE_P (type)
     261                 :        267 :       || !INDIRECT_TYPE_P (intype)
     262                 :        114 :       || !INDIRECT_TYPE_P (TREE_TYPE (op))
     263                 :        114 :       || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
     264                 :        381 :       || !is_properly_derived_from (TREE_TYPE (type), TREE_TYPE (intype)))
     265                 :        153 :     return NULL_TREE;
     266                 :            : 
     267                 :        114 :   return cp_ubsan_maybe_instrument_vptr (loc, op, TREE_TYPE (type), true,
     268                 :        114 :                                          TYPE_PTR_P (type)
     269                 :            :                                          ? UBSAN_DOWNCAST_POINTER
     270                 :        114 :                                          : UBSAN_DOWNCAST_REFERENCE);
     271                 :            : }
     272                 :            : 
     273                 :            : /* Instrument cast to virtual base.  */
     274                 :            : 
     275                 :            : tree
     276                 :         64 : cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
     277                 :            : {
     278                 :         64 :   return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
     279                 :         64 :                                          UBSAN_CAST_TO_VBASE);
     280                 :            : }
     281                 :            : 
     282                 :            : /* Called from initialize_vtbl_ptrs via dfs_walk.  BINFO is the base
     283                 :            :    which we want to initialize the vtable pointer for, DATA is
     284                 :            :    TREE_LIST whose TREE_VALUE is the this ptr expression.  */
     285                 :            : 
     286                 :            : static tree
     287                 :        776 : cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data)
     288                 :            : {
     289                 :       1552 :   if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
     290                 :            :     return dfs_skip_bases;
     291                 :            : 
     292                 :        422 :   if (!BINFO_PRIMARY_P (binfo))
     293                 :            :     {
     294                 :        262 :       tree base_ptr = TREE_VALUE ((tree) data);
     295                 :            : 
     296                 :        262 :       base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1,
     297                 :            :                                   tf_warning_or_error);
     298                 :            : 
     299                 :            :       /* Compute the location of the vtpr.  */
     300                 :        262 :       tree vtbl_ptr
     301                 :        262 :         = build_vfield_ref (cp_build_fold_indirect_ref (base_ptr),
     302                 :        262 :                             TREE_TYPE (binfo));
     303                 :        262 :       gcc_assert (vtbl_ptr != error_mark_node);
     304                 :            : 
     305                 :            :       /* Assign NULL to the vptr.  */
     306                 :        262 :       tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr));
     307                 :        262 :       tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR,
     308                 :            :                                         vtbl, tf_warning_or_error);
     309                 :        262 :       if (vptr_via_virtual_p (binfo))
     310                 :            :         /* If this vptr comes from a virtual base of the complete object, only
     311                 :            :            clear it if we're in charge of virtual bases.  */
     312                 :         30 :         stmt = build_if_in_charge (stmt);
     313                 :        262 :       finish_expr_stmt (stmt);
     314                 :            :     }
     315                 :            : 
     316                 :            :   return NULL_TREE;
     317                 :            : }
     318                 :            : 
     319                 :            : /* Initialize all the vtable pointers in the object pointed to by
     320                 :            :    ADDR to NULL, so that we catch invalid calls to methods before
     321                 :            :    mem-initializers are completed.  */
     322                 :            : 
     323                 :            : void
     324                 :        591 : cp_ubsan_maybe_initialize_vtbl_ptrs (tree addr)
     325                 :            : {
     326                 :        591 :   if (!cp_ubsan_instrument_vptr_p (NULL_TREE))
     327                 :            :     return;
     328                 :            : 
     329                 :        591 :   tree type = TREE_TYPE (TREE_TYPE (addr));
     330                 :        591 :   tree list = build_tree_list (type, addr);
     331                 :            :   /* We cannot rely on the vtable being set up.  We have to indirect via the
     332                 :            :      vtt_parm.  */
     333                 :        591 :   int save_in_base_initializer = in_base_initializer;
     334                 :        591 :   in_base_initializer = 1;
     335                 :            : 
     336                 :            :   /* Walk through the hierarchy, initializing the vptr in each base
     337                 :            :      class to NULL.  */
     338                 :        591 :   dfs_walk_once (TYPE_BINFO (type), cp_ubsan_dfs_initialize_vtbl_ptrs,
     339                 :            :                  NULL, list);
     340                 :            : 
     341                 :        591 :   in_base_initializer = save_in_base_initializer;
     342                 :            : }

Generated by: LCOV version 1.0

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto --enable-host-shared. GCC test suite is run with the built compiler.