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