Home | History | Annotate | Line # | Download | only in c-family
c-ubsan.cc revision 1.1
      1  1.1  mrg /* UndefinedBehaviorSanitizer, undefined behavior detector.
      2  1.1  mrg    Copyright (C) 2013-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Contributed by Marek Polacek <polacek (at) redhat.com>
      4  1.1  mrg 
      5  1.1  mrg This file is part of GCC.
      6  1.1  mrg 
      7  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      8  1.1  mrg the terms of the GNU General Public License as published by the Free
      9  1.1  mrg Software Foundation; either version 3, or (at your option) any later
     10  1.1  mrg version.
     11  1.1  mrg 
     12  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  1.1  mrg for more details.
     16  1.1  mrg 
     17  1.1  mrg You should have received a copy of the GNU General Public License
     18  1.1  mrg along with GCC; see the file COPYING3.  If not see
     19  1.1  mrg <http://www.gnu.org/licenses/>.  */
     20  1.1  mrg 
     21  1.1  mrg #include "config.h"
     22  1.1  mrg #include "system.h"
     23  1.1  mrg #include "coretypes.h"
     24  1.1  mrg #include "tm.h"
     25  1.1  mrg #include "c-family/c-common.h"
     26  1.1  mrg #include "ubsan.h"
     27  1.1  mrg #include "c-family/c-ubsan.h"
     28  1.1  mrg #include "stor-layout.h"
     29  1.1  mrg #include "builtins.h"
     30  1.1  mrg #include "gimplify.h"
     31  1.1  mrg #include "stringpool.h"
     32  1.1  mrg #include "attribs.h"
     33  1.1  mrg #include "asan.h"
     34  1.1  mrg #include "langhooks.h"
     35  1.1  mrg 
     36  1.1  mrg /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
     37  1.1  mrg    return NULL_TREE.  */
     38  1.1  mrg 
     39  1.1  mrg tree
     40  1.1  mrg ubsan_instrument_division (location_t loc, tree op0, tree op1)
     41  1.1  mrg {
     42  1.1  mrg   tree t, tt, x = NULL_TREE;
     43  1.1  mrg   tree type = TREE_TYPE (op0);
     44  1.1  mrg   enum sanitize_code flag = SANITIZE_DIVIDE;
     45  1.1  mrg 
     46  1.1  mrg   /* At this point both operands should have the same type,
     47  1.1  mrg      because they are already converted to RESULT_TYPE.
     48  1.1  mrg      Use TYPE_MAIN_VARIANT since typedefs can confuse us.  */
     49  1.1  mrg   tree top0 = TYPE_MAIN_VARIANT (type);
     50  1.1  mrg   tree top1 = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
     51  1.1  mrg   gcc_checking_assert (lang_hooks.types_compatible_p (top0, top1));
     52  1.1  mrg 
     53  1.1  mrg   op0 = unshare_expr (op0);
     54  1.1  mrg   op1 = unshare_expr (op1);
     55  1.1  mrg 
     56  1.1  mrg   if (INTEGRAL_TYPE_P (type)
     57  1.1  mrg       && sanitize_flags_p (SANITIZE_DIVIDE))
     58  1.1  mrg     t = fold_build2 (EQ_EXPR, boolean_type_node,
     59  1.1  mrg 		     op1, build_int_cst (type, 0));
     60  1.1  mrg   else if (TREE_CODE (type) == REAL_TYPE
     61  1.1  mrg 	   && sanitize_flags_p (SANITIZE_FLOAT_DIVIDE))
     62  1.1  mrg     {
     63  1.1  mrg       t = fold_build2 (EQ_EXPR, boolean_type_node,
     64  1.1  mrg 		       op1, build_real (type, dconst0));
     65  1.1  mrg       flag = SANITIZE_FLOAT_DIVIDE;
     66  1.1  mrg     }
     67  1.1  mrg   else
     68  1.1  mrg     t = NULL_TREE;
     69  1.1  mrg 
     70  1.1  mrg   /* We check INT_MIN / -1 only for signed types.  */
     71  1.1  mrg   if (INTEGRAL_TYPE_P (type)
     72  1.1  mrg       && sanitize_flags_p (SANITIZE_SI_OVERFLOW)
     73  1.1  mrg       && !TYPE_UNSIGNED (type))
     74  1.1  mrg     {
     75  1.1  mrg       tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1),
     76  1.1  mrg 			build_int_cst (type, -1));
     77  1.1  mrg       x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
     78  1.1  mrg 		       TYPE_MIN_VALUE (type));
     79  1.1  mrg       x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
     80  1.1  mrg       if (t == NULL_TREE || integer_zerop (t))
     81  1.1  mrg 	{
     82  1.1  mrg 	  t = x;
     83  1.1  mrg 	  x = NULL_TREE;
     84  1.1  mrg 	  flag = SANITIZE_SI_OVERFLOW;
     85  1.1  mrg 	}
     86  1.1  mrg       else if (flag_sanitize_undefined_trap_on_error
     87  1.1  mrg 	       || (((flag_sanitize_recover & SANITIZE_DIVIDE) == 0)
     88  1.1  mrg 		   == ((flag_sanitize_recover & SANITIZE_SI_OVERFLOW) == 0)))
     89  1.1  mrg 	{
     90  1.1  mrg 	  t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
     91  1.1  mrg 	  x = NULL_TREE;
     92  1.1  mrg 	}
     93  1.1  mrg       else if (integer_zerop (x))
     94  1.1  mrg 	x = NULL_TREE;
     95  1.1  mrg     }
     96  1.1  mrg   else if (t == NULL_TREE)
     97  1.1  mrg     return NULL_TREE;
     98  1.1  mrg 
     99  1.1  mrg   /* If the condition was folded to 0, no need to instrument
    100  1.1  mrg      this expression.  */
    101  1.1  mrg   if (integer_zerop (t))
    102  1.1  mrg     return NULL_TREE;
    103  1.1  mrg 
    104  1.1  mrg   /* In case we have a SAVE_EXPR in a conditional context, we need to
    105  1.1  mrg      make sure it gets evaluated before the condition.  */
    106  1.1  mrg   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
    107  1.1  mrg   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
    108  1.1  mrg   if (flag_sanitize_undefined_trap_on_error)
    109  1.1  mrg     tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
    110  1.1  mrg   else
    111  1.1  mrg     {
    112  1.1  mrg       tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
    113  1.1  mrg 				     ubsan_type_descriptor (type), NULL_TREE,
    114  1.1  mrg 				     NULL_TREE);
    115  1.1  mrg       data = build_fold_addr_expr_loc (loc, data);
    116  1.1  mrg       enum built_in_function bcode
    117  1.1  mrg 	= (flag_sanitize_recover & flag)
    118  1.1  mrg 	  ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
    119  1.1  mrg 	  : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
    120  1.1  mrg       tt = builtin_decl_explicit (bcode);
    121  1.1  mrg       op0 = unshare_expr (op0);
    122  1.1  mrg       op1 = unshare_expr (op1);
    123  1.1  mrg       tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
    124  1.1  mrg 				ubsan_encode_value (op1));
    125  1.1  mrg       if (x)
    126  1.1  mrg 	{
    127  1.1  mrg 	  bcode = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
    128  1.1  mrg 		  ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
    129  1.1  mrg 		  : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
    130  1.1  mrg 	  tree xt = builtin_decl_explicit (bcode);
    131  1.1  mrg 	  op0 = unshare_expr (op0);
    132  1.1  mrg 	  op1 = unshare_expr (op1);
    133  1.1  mrg 	  xt = build_call_expr_loc (loc, xt, 3, data, ubsan_encode_value (op0),
    134  1.1  mrg 				    ubsan_encode_value (op1));
    135  1.1  mrg 	  x = fold_build3 (COND_EXPR, void_type_node, x, xt, void_node);
    136  1.1  mrg 	}
    137  1.1  mrg     }
    138  1.1  mrg   t = fold_build3 (COND_EXPR, void_type_node, t, tt, x ? x : void_node);
    139  1.1  mrg 
    140  1.1  mrg   return t;
    141  1.1  mrg }
    142  1.1  mrg 
    143  1.1  mrg /* Instrument left and right shifts.  */
    144  1.1  mrg 
    145  1.1  mrg tree
    146  1.1  mrg ubsan_instrument_shift (location_t loc, enum tree_code code,
    147  1.1  mrg 			tree op0, tree op1)
    148  1.1  mrg {
    149  1.1  mrg   tree t, tt = NULL_TREE;
    150  1.1  mrg   tree type0 = TREE_TYPE (op0);
    151  1.1  mrg   tree type1 = TREE_TYPE (op1);
    152  1.1  mrg   if (!INTEGRAL_TYPE_P (type0))
    153  1.1  mrg     return NULL_TREE;
    154  1.1  mrg 
    155  1.1  mrg   tree op1_utype = unsigned_type_for (type1);
    156  1.1  mrg   HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
    157  1.1  mrg   tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
    158  1.1  mrg 
    159  1.1  mrg   op0 = unshare_expr (op0);
    160  1.1  mrg   op1 = unshare_expr (op1);
    161  1.1  mrg 
    162  1.1  mrg   t = fold_convert_loc (loc, op1_utype, op1);
    163  1.1  mrg   t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
    164  1.1  mrg 
    165  1.1  mrg   /* If this is not a signed operation, don't perform overflow checks.
    166  1.1  mrg      Also punt on bit-fields.  */
    167  1.1  mrg   if (TYPE_OVERFLOW_WRAPS (type0)
    168  1.1  mrg       || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)),
    169  1.1  mrg 		   TYPE_PRECISION (type0))
    170  1.1  mrg       || !sanitize_flags_p (SANITIZE_SHIFT_BASE)
    171  1.1  mrg       /* In C++20 and later, shifts are well defined except when
    172  1.1  mrg 	 the second operand is not within bounds.  */
    173  1.1  mrg       || cxx_dialect >= cxx20)
    174  1.1  mrg     ;
    175  1.1  mrg 
    176  1.1  mrg   /* For signed x << y, in C99 and later, the following:
    177  1.1  mrg      (unsigned) x >> (uprecm1 - y)
    178  1.1  mrg      if non-zero, is undefined.  */
    179  1.1  mrg   else if (code == LSHIFT_EXPR && flag_isoc99 && cxx_dialect < cxx11)
    180  1.1  mrg     {
    181  1.1  mrg       tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
    182  1.1  mrg 			    fold_convert (op1_utype, unshare_expr (op1)));
    183  1.1  mrg       tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
    184  1.1  mrg       tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
    185  1.1  mrg       tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
    186  1.1  mrg 			build_int_cst (TREE_TYPE (tt), 0));
    187  1.1  mrg     }
    188  1.1  mrg 
    189  1.1  mrg   /* For signed x << y, in C++11 to C++17, the following:
    190  1.1  mrg      x < 0 || ((unsigned) x >> (uprecm1 - y))
    191  1.1  mrg      if > 1, is undefined.  */
    192  1.1  mrg   else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11)
    193  1.1  mrg     {
    194  1.1  mrg       tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
    195  1.1  mrg 			    fold_convert (op1_utype, unshare_expr (op1)));
    196  1.1  mrg       tt = fold_convert_loc (loc, unsigned_type_for (type0),
    197  1.1  mrg 			     unshare_expr (op0));
    198  1.1  mrg       tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
    199  1.1  mrg       tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
    200  1.1  mrg 			build_int_cst (TREE_TYPE (tt), 1));
    201  1.1  mrg       x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0),
    202  1.1  mrg 		       build_int_cst (type0, 0));
    203  1.1  mrg       tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
    204  1.1  mrg     }
    205  1.1  mrg 
    206  1.1  mrg   /* If the condition was folded to 0, no need to instrument
    207  1.1  mrg      this expression.  */
    208  1.1  mrg   if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt)))
    209  1.1  mrg     return NULL_TREE;
    210  1.1  mrg 
    211  1.1  mrg   /* In case we have a SAVE_EXPR in a conditional context, we need to
    212  1.1  mrg      make sure it gets evaluated before the condition.  */
    213  1.1  mrg   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
    214  1.1  mrg   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
    215  1.1  mrg 
    216  1.1  mrg   enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
    217  1.1  mrg   tree else_t = void_node;
    218  1.1  mrg   if (tt)
    219  1.1  mrg     {
    220  1.1  mrg       if (!sanitize_flags_p (SANITIZE_SHIFT_EXPONENT))
    221  1.1  mrg 	{
    222  1.1  mrg 	  t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
    223  1.1  mrg 	  t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
    224  1.1  mrg 	  recover_kind = SANITIZE_SHIFT_BASE;
    225  1.1  mrg 	}
    226  1.1  mrg       else
    227  1.1  mrg 	{
    228  1.1  mrg 	  if (flag_sanitize_undefined_trap_on_error
    229  1.1  mrg 	      || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
    230  1.1  mrg 		  == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
    231  1.1  mrg 	    t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
    232  1.1  mrg 	  else
    233  1.1  mrg 	    else_t = tt;
    234  1.1  mrg 	}
    235  1.1  mrg     }
    236  1.1  mrg 
    237  1.1  mrg   if (flag_sanitize_undefined_trap_on_error)
    238  1.1  mrg     tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
    239  1.1  mrg   else
    240  1.1  mrg     {
    241  1.1  mrg       tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc,
    242  1.1  mrg 				     ubsan_type_descriptor (type0),
    243  1.1  mrg 				     ubsan_type_descriptor (type1), NULL_TREE,
    244  1.1  mrg 				     NULL_TREE);
    245  1.1  mrg       data = build_fold_addr_expr_loc (loc, data);
    246  1.1  mrg 
    247  1.1  mrg       enum built_in_function bcode
    248  1.1  mrg 	= (flag_sanitize_recover & recover_kind)
    249  1.1  mrg 	  ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
    250  1.1  mrg 	  : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
    251  1.1  mrg       tt = builtin_decl_explicit (bcode);
    252  1.1  mrg       op0 = unshare_expr (op0);
    253  1.1  mrg       op1 = unshare_expr (op1);
    254  1.1  mrg       tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
    255  1.1  mrg 				ubsan_encode_value (op1));
    256  1.1  mrg       if (else_t != void_node)
    257  1.1  mrg 	{
    258  1.1  mrg 	  bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
    259  1.1  mrg 		  ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
    260  1.1  mrg 		  : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
    261  1.1  mrg 	  tree else_tt = builtin_decl_explicit (bcode);
    262  1.1  mrg 	  op0 = unshare_expr (op0);
    263  1.1  mrg 	  op1 = unshare_expr (op1);
    264  1.1  mrg 	  else_tt = build_call_expr_loc (loc, else_tt, 3, data,
    265  1.1  mrg 					 ubsan_encode_value (op0),
    266  1.1  mrg 					 ubsan_encode_value (op1));
    267  1.1  mrg 	  else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
    268  1.1  mrg 				else_tt, void_node);
    269  1.1  mrg 	}
    270  1.1  mrg     }
    271  1.1  mrg   t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
    272  1.1  mrg 
    273  1.1  mrg   return t;
    274  1.1  mrg }
    275  1.1  mrg 
    276  1.1  mrg /* Instrument variable length array bound.  */
    277  1.1  mrg 
    278  1.1  mrg tree
    279  1.1  mrg ubsan_instrument_vla (location_t loc, tree size)
    280  1.1  mrg {
    281  1.1  mrg   tree type = TREE_TYPE (size);
    282  1.1  mrg   tree t, tt;
    283  1.1  mrg 
    284  1.1  mrg   t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
    285  1.1  mrg   if (flag_sanitize_undefined_trap_on_error)
    286  1.1  mrg     tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
    287  1.1  mrg   else
    288  1.1  mrg     {
    289  1.1  mrg       tree data = ubsan_create_data ("__ubsan_vla_data", 1, &loc,
    290  1.1  mrg 				     ubsan_type_descriptor (type), NULL_TREE,
    291  1.1  mrg 				     NULL_TREE);
    292  1.1  mrg       data = build_fold_addr_expr_loc (loc, data);
    293  1.1  mrg       enum built_in_function bcode
    294  1.1  mrg 	= (flag_sanitize_recover & SANITIZE_VLA)
    295  1.1  mrg 	  ? BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
    296  1.1  mrg 	  : BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT;
    297  1.1  mrg       tt = builtin_decl_explicit (bcode);
    298  1.1  mrg       tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
    299  1.1  mrg     }
    300  1.1  mrg   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
    301  1.1  mrg 
    302  1.1  mrg   return t;
    303  1.1  mrg }
    304  1.1  mrg 
    305  1.1  mrg /* Instrument missing return in C++ functions returning non-void.  */
    306  1.1  mrg 
    307  1.1  mrg tree
    308  1.1  mrg ubsan_instrument_return (location_t loc)
    309  1.1  mrg {
    310  1.1  mrg   if (flag_sanitize_undefined_trap_on_error)
    311  1.1  mrg     return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
    312  1.1  mrg 
    313  1.1  mrg   tree data = ubsan_create_data ("__ubsan_missing_return_data", 1, &loc,
    314  1.1  mrg 				 NULL_TREE, NULL_TREE);
    315  1.1  mrg   tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN);
    316  1.1  mrg   return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
    317  1.1  mrg }
    318  1.1  mrg 
    319  1.1  mrg /* Instrument array bounds for ARRAY_REFs.  We create special builtin,
    320  1.1  mrg    that gets expanded in the sanopt pass, and make an array dimension
    321  1.1  mrg    of it.  ARRAY is the array, *INDEX is an index to the array.
    322  1.1  mrg    Return NULL_TREE if no instrumentation is emitted.
    323  1.1  mrg    IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR.  */
    324  1.1  mrg 
    325  1.1  mrg tree
    326  1.1  mrg ubsan_instrument_bounds (location_t loc, tree array, tree *index,
    327  1.1  mrg 			 bool ignore_off_by_one)
    328  1.1  mrg {
    329  1.1  mrg   tree type = TREE_TYPE (array);
    330  1.1  mrg   tree domain = TYPE_DOMAIN (type);
    331  1.1  mrg 
    332  1.1  mrg   if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
    333  1.1  mrg     return NULL_TREE;
    334  1.1  mrg 
    335  1.1  mrg   tree bound = TYPE_MAX_VALUE (domain);
    336  1.1  mrg   if (ignore_off_by_one)
    337  1.1  mrg     bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
    338  1.1  mrg 			 build_int_cst (TREE_TYPE (bound), 1));
    339  1.1  mrg 
    340  1.1  mrg   /* Detect flexible array members and suchlike, unless
    341  1.1  mrg      -fsanitize=bounds-strict.  */
    342  1.1  mrg   tree base = get_base_address (array);
    343  1.1  mrg   if (!sanitize_flags_p (SANITIZE_BOUNDS_STRICT)
    344  1.1  mrg       && TREE_CODE (array) == COMPONENT_REF
    345  1.1  mrg       && base && (INDIRECT_REF_P (base) || TREE_CODE (base) == MEM_REF))
    346  1.1  mrg     {
    347  1.1  mrg       tree next = NULL_TREE;
    348  1.1  mrg       tree cref = array;
    349  1.1  mrg 
    350  1.1  mrg       /* Walk all structs/unions.  */
    351  1.1  mrg       while (TREE_CODE (cref) == COMPONENT_REF)
    352  1.1  mrg 	{
    353  1.1  mrg 	  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
    354  1.1  mrg 	    for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
    355  1.1  mrg 		 next && TREE_CODE (next) != FIELD_DECL;
    356  1.1  mrg 		 next = DECL_CHAIN (next))
    357  1.1  mrg 	      ;
    358  1.1  mrg 	  if (next)
    359  1.1  mrg 	    /* Not a last element.  Instrument it.  */
    360  1.1  mrg 	    break;
    361  1.1  mrg 	  /* Ok, this is the last field of the structure/union.  But the
    362  1.1  mrg 	     aggregate containing the field must be the last field too,
    363  1.1  mrg 	     recursively.  */
    364  1.1  mrg 	  cref = TREE_OPERAND (cref, 0);
    365  1.1  mrg 	}
    366  1.1  mrg       if (!next)
    367  1.1  mrg 	/* Don't instrument this flexible array member-like array in non-strict
    368  1.1  mrg 	   -fsanitize=bounds mode.  */
    369  1.1  mrg         return NULL_TREE;
    370  1.1  mrg     }
    371  1.1  mrg 
    372  1.1  mrg   /* Don't emit instrumentation in the most common cases.  */
    373  1.1  mrg   tree idx = NULL_TREE;
    374  1.1  mrg   if (TREE_CODE (*index) == INTEGER_CST)
    375  1.1  mrg     idx = *index;
    376  1.1  mrg   else if (TREE_CODE (*index) == BIT_AND_EXPR
    377  1.1  mrg 	   && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
    378  1.1  mrg     idx = TREE_OPERAND (*index, 1);
    379  1.1  mrg   if (idx
    380  1.1  mrg       && TREE_CODE (bound) == INTEGER_CST
    381  1.1  mrg       && tree_int_cst_sgn (idx) >= 0
    382  1.1  mrg       && tree_int_cst_le (idx, bound))
    383  1.1  mrg     return NULL_TREE;
    384  1.1  mrg 
    385  1.1  mrg   *index = save_expr (*index);
    386  1.1  mrg   /* Create a "(T *) 0" tree node to describe the array type.  */
    387  1.1  mrg   tree zero_with_type = build_int_cst (build_pointer_type (type), 0);
    388  1.1  mrg   return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
    389  1.1  mrg 				       void_type_node, 3, zero_with_type,
    390  1.1  mrg 				       *index, bound);
    391  1.1  mrg }
    392  1.1  mrg 
    393  1.1  mrg /* Return true iff T is an array that was instrumented by SANITIZE_BOUNDS.  */
    394  1.1  mrg 
    395  1.1  mrg bool
    396  1.1  mrg ubsan_array_ref_instrumented_p (const_tree t)
    397  1.1  mrg {
    398  1.1  mrg   if (TREE_CODE (t) != ARRAY_REF)
    399  1.1  mrg     return false;
    400  1.1  mrg 
    401  1.1  mrg   tree op1 = TREE_OPERAND (t, 1);
    402  1.1  mrg   return TREE_CODE (op1) == COMPOUND_EXPR
    403  1.1  mrg 	 && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
    404  1.1  mrg 	 && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
    405  1.1  mrg 	 && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
    406  1.1  mrg }
    407  1.1  mrg 
    408  1.1  mrg /* Instrument an ARRAY_REF, if it hasn't already been instrumented.
    409  1.1  mrg    IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR.  */
    410  1.1  mrg 
    411  1.1  mrg void
    412  1.1  mrg ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
    413  1.1  mrg {
    414  1.1  mrg   if (!ubsan_array_ref_instrumented_p (*expr_p)
    415  1.1  mrg       && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT)
    416  1.1  mrg       && current_function_decl != NULL_TREE)
    417  1.1  mrg     {
    418  1.1  mrg       tree op0 = TREE_OPERAND (*expr_p, 0);
    419  1.1  mrg       tree op1 = TREE_OPERAND (*expr_p, 1);
    420  1.1  mrg       tree e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0, &op1,
    421  1.1  mrg 					ignore_off_by_one);
    422  1.1  mrg       if (e != NULL_TREE)
    423  1.1  mrg 	{
    424  1.1  mrg 	  tree t = copy_node (*expr_p);
    425  1.1  mrg 	  TREE_OPERAND (t, 1) = build2 (COMPOUND_EXPR, TREE_TYPE (op1),
    426  1.1  mrg 					e, op1);
    427  1.1  mrg 	  *expr_p = t;
    428  1.1  mrg 	}
    429  1.1  mrg     }
    430  1.1  mrg }
    431  1.1  mrg 
    432  1.1  mrg static tree
    433  1.1  mrg ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
    434  1.1  mrg 					  enum ubsan_null_ckind ckind)
    435  1.1  mrg {
    436  1.1  mrg   if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
    437  1.1  mrg       || current_function_decl == NULL_TREE)
    438  1.1  mrg     return NULL_TREE;
    439  1.1  mrg 
    440  1.1  mrg   tree type = TREE_TYPE (ptype);
    441  1.1  mrg   tree orig_op = op;
    442  1.1  mrg   bool instrument = false;
    443  1.1  mrg   unsigned int mina = 0;
    444  1.1  mrg 
    445  1.1  mrg   if (sanitize_flags_p (SANITIZE_ALIGNMENT))
    446  1.1  mrg     {
    447  1.1  mrg       mina = min_align_of_type (type);
    448  1.1  mrg       if (mina <= 1)
    449  1.1  mrg 	mina = 0;
    450  1.1  mrg     }
    451  1.1  mrg   while ((TREE_CODE (op) == NOP_EXPR
    452  1.1  mrg 	  || TREE_CODE (op) == NON_LVALUE_EXPR)
    453  1.1  mrg 	 && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
    454  1.1  mrg     op = TREE_OPERAND (op, 0);
    455  1.1  mrg   if (TREE_CODE (op) == NOP_EXPR
    456  1.1  mrg       && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
    457  1.1  mrg     {
    458  1.1  mrg       if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
    459  1.1  mrg 	instrument = true;
    460  1.1  mrg     }
    461  1.1  mrg   else
    462  1.1  mrg     {
    463  1.1  mrg       if (sanitize_flags_p (SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
    464  1.1  mrg 	{
    465  1.1  mrg 	  bool strict_overflow_p = false;
    466  1.1  mrg 	  /* tree_single_nonzero_warnv_p will not return true for non-weak
    467  1.1  mrg 	     non-automatic decls with -fno-delete-null-pointer-checks,
    468  1.1  mrg 	     which is disabled during -fsanitize=null.  We don't want to
    469  1.1  mrg 	     instrument those, just weak vars though.  */
    470  1.1  mrg 	  int save_flag_delete_null_pointer_checks
    471  1.1  mrg 	    = flag_delete_null_pointer_checks;
    472  1.1  mrg 	  flag_delete_null_pointer_checks = 1;
    473  1.1  mrg 	  if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
    474  1.1  mrg 	      || strict_overflow_p)
    475  1.1  mrg 	    instrument = true;
    476  1.1  mrg 	  flag_delete_null_pointer_checks
    477  1.1  mrg 	    = save_flag_delete_null_pointer_checks;
    478  1.1  mrg 	}
    479  1.1  mrg       else if (sanitize_flags_p (SANITIZE_NULL))
    480  1.1  mrg 	instrument = true;
    481  1.1  mrg       if (mina && mina > 1)
    482  1.1  mrg 	{
    483  1.1  mrg 	  if (!POINTER_TYPE_P (TREE_TYPE (op))
    484  1.1  mrg 	      || mina > get_pointer_alignment (op) / BITS_PER_UNIT)
    485  1.1  mrg 	    instrument = true;
    486  1.1  mrg 	}
    487  1.1  mrg     }
    488  1.1  mrg   if (!instrument)
    489  1.1  mrg     return NULL_TREE;
    490  1.1  mrg   op = save_expr (orig_op);
    491  1.1  mrg   gcc_assert (POINTER_TYPE_P (ptype));
    492  1.1  mrg   if (TREE_CODE (ptype) == REFERENCE_TYPE)
    493  1.1  mrg     ptype = build_pointer_type (TREE_TYPE (ptype));
    494  1.1  mrg   tree kind = build_int_cst (ptype, ckind);
    495  1.1  mrg   tree align = build_int_cst (pointer_sized_int_node, mina);
    496  1.1  mrg   tree call
    497  1.1  mrg     = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
    498  1.1  mrg 				    3, op, kind, align);
    499  1.1  mrg   TREE_SIDE_EFFECTS (call) = 1;
    500  1.1  mrg   return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
    501  1.1  mrg }
    502  1.1  mrg 
    503  1.1  mrg /* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
    504  1.1  mrg    type if needed.  */
    505  1.1  mrg 
    506  1.1  mrg void
    507  1.1  mrg ubsan_maybe_instrument_reference (tree *stmt_p)
    508  1.1  mrg {
    509  1.1  mrg   tree stmt = *stmt_p;
    510  1.1  mrg   tree op = stmt;
    511  1.1  mrg   if (TREE_CODE (stmt) == NOP_EXPR)
    512  1.1  mrg     op = TREE_OPERAND (stmt, 0);
    513  1.1  mrg   op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
    514  1.1  mrg 						 TREE_TYPE (stmt),
    515  1.1  mrg 						 UBSAN_REF_BINDING);
    516  1.1  mrg   if (op)
    517  1.1  mrg     {
    518  1.1  mrg       if (TREE_CODE (stmt) == NOP_EXPR)
    519  1.1  mrg 	TREE_OPERAND (stmt, 0) = op;
    520  1.1  mrg       else
    521  1.1  mrg 	*stmt_p = op;
    522  1.1  mrg     }
    523  1.1  mrg }
    524  1.1  mrg 
    525  1.1  mrg /* Instrument a CALL_EXPR to a method if needed.  */
    526  1.1  mrg 
    527  1.1  mrg void
    528  1.1  mrg ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
    529  1.1  mrg {
    530  1.1  mrg   if (call_expr_nargs (stmt) == 0)
    531  1.1  mrg     return;
    532  1.1  mrg   tree op = CALL_EXPR_ARG (stmt, 0);
    533  1.1  mrg   if (op == error_mark_node
    534  1.1  mrg       || !POINTER_TYPE_P (TREE_TYPE (op)))
    535  1.1  mrg     return;
    536  1.1  mrg   op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
    537  1.1  mrg 						 TREE_TYPE (op),
    538  1.1  mrg 						 is_ctor ? UBSAN_CTOR_CALL
    539  1.1  mrg 						 : UBSAN_MEMBER_CALL);
    540  1.1  mrg   if (op)
    541  1.1  mrg     CALL_EXPR_ARG (stmt, 0) = op;
    542  1.1  mrg }
    543