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