tree ubsan_instrument_bounds (location_t loc, tree array, tree *index, bool ignore_off_by_one) { tree type = TREE_TYPE (array); tree domain = TYPE_DOMAIN (type); if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE) return NULL_TREE; tree bound = TYPE_MAX_VALUE (domain); if (ignore_off_by_one) bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound, build_int_cst (TREE_TYPE (bound), 1)); /* Detect flexible array members and suchlike. */ tree base = get_base_address (array); if (base && (TREE_CODE (base) == INDIRECT_REF || TREE_CODE (base) == MEM_REF)) { tree next = NULL_TREE; tree cref = array; /* Walk all structs/unions. */ while (TREE_CODE (cref) == COMPONENT_REF) { if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE) for (next = DECL_CHAIN (TREE_OPERAND (cref, 1)); next && TREE_CODE (next) != FIELD_DECL; next = DECL_CHAIN (next)) ; if (next) /* Not a last element. Instrument it. */ break; /* Ok, this is the last field of the structure/union. But the aggregate containing the field must be the last field too, recursively. */ cref = TREE_OPERAND (cref, 0); } if (!next) /* Don't instrument this flexible array member-like array in non-strict -fsanitize=bounds mode. */ return NULL_TREE; } *index = save_expr (*index); /* Create a "(T *) 0" tree node to describe the array type. */ tree zero_with_type = build_int_cst (build_pointer_type (type), 0); return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS, void_type_node, 3, zero_with_type, *index, bound); }
static tree cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr, enum ubsan_null_ckind ckind) { type = TYPE_MAIN_VARIANT (type); const char *mangled = mangle_type_string (type); hashval_t str_hash1 = htab_hash_string (mangled); hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0); tree str_hash = wide_int_to_tree (uint64_type_node, wi::uhwi (((uint64_t) str_hash1 << 32) | str_hash2, 64)); if (!is_addr) op = build_fold_addr_expr_loc (loc, op); op = save_expr (op); tree vptr = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)), build_fold_indirect_ref_loc (loc, op), TYPE_VFIELD (type), NULL_TREE); vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr); vptr = fold_convert_loc (loc, uint64_type_node, vptr); if (ckind == UBSAN_DOWNCAST_POINTER) { tree cond = build2_loc (loc, NE_EXPR, boolean_type_node, op, build_zero_cst (TREE_TYPE (op))); /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ TREE_NO_WARNING (cond) = 1; vptr = build3_loc (loc, COND_EXPR, uint64_type_node, cond, vptr, build_int_cst (uint64_type_node, 0)); } tree ti_decl = get_tinfo_decl (type); mark_used (ti_decl); tree ptype = build_pointer_type (type); tree call = build_call_expr_internal_loc (loc, IFN_UBSAN_VPTR, void_type_node, 5, op, vptr, str_hash, build_address (ti_decl), build_int_cst (ptype, ckind)); TREE_SIDE_EFFECTS (call) = 1; return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op); }
static tree ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype, enum ubsan_null_ckind ckind) { if (!do_ubsan_in_current_function ()) return NULL_TREE; tree type = TREE_TYPE (ptype); tree orig_op = op; bool instrument = false; unsigned int mina = 0; if (flag_sanitize & SANITIZE_ALIGNMENT) { mina = min_align_of_type (type); if (mina <= 1) mina = 0; } while ((TREE_CODE (op) == NOP_EXPR || TREE_CODE (op) == NON_LVALUE_EXPR) && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE) op = TREE_OPERAND (op, 0); if (TREE_CODE (op) == NOP_EXPR && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE) { if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op)))) instrument = true; } else { if ((flag_sanitize & SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR) { bool strict_overflow_p = false; /* tree_single_nonzero_warnv_p will not return true for non-weak non-automatic decls with -fno-delete-null-pointer-checks, which is disabled during -fsanitize=null. We don't want to instrument those, just weak vars though. */ int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks; flag_delete_null_pointer_checks = 1; if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p) || strict_overflow_p) instrument = true; flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; } else if (flag_sanitize & SANITIZE_NULL) instrument = true; if (mina && mina > 1) { if (!POINTER_TYPE_P (TREE_TYPE (op)) || mina > get_pointer_alignment (op) / BITS_PER_UNIT) instrument = true; } } if (!instrument) return NULL_TREE; op = save_expr (orig_op); gcc_assert (POINTER_TYPE_P (ptype)); if (TREE_CODE (ptype) == REFERENCE_TYPE) ptype = build_pointer_type (TREE_TYPE (ptype)); tree kind = build_int_cst (ptype, ckind); tree align = build_int_cst (pointer_sized_int_node, mina); tree call = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node, 3, op, kind, align); TREE_SIDE_EFFECTS (call) = 1; return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op); }