static void instrument_si_overflow (gimple_stmt_iterator gsi) { gimple stmt = gsi_stmt (gsi); tree_code code = gimple_assign_rhs_code (stmt); tree lhs = gimple_assign_lhs (stmt); tree lhstype = TREE_TYPE (lhs); tree a, b; gimple g; /* If this is not a signed operation, don't instrument anything here. Also punt on bit-fields. */ if (!INTEGRAL_TYPE_P (lhstype) || TYPE_OVERFLOW_WRAPS (lhstype) || GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype)) return; switch (code) { case MINUS_EXPR: case PLUS_EXPR: case MULT_EXPR: /* Transform i = u {+,-,*} 5; into i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5); */ a = gimple_assign_rhs1 (stmt); b = gimple_assign_rhs2 (stmt); g = gimple_build_call_internal (code == PLUS_EXPR ? IFN_UBSAN_CHECK_ADD : code == MINUS_EXPR ? IFN_UBSAN_CHECK_SUB : IFN_UBSAN_CHECK_MUL, 2, a, b); gimple_call_set_lhs (g, lhs); gsi_replace (&gsi, g, false); break; case NEGATE_EXPR: /* Represent i = -u; as i = UBSAN_CHECK_SUB (0, u); */ a = build_int_cst (lhstype, 0); b = gimple_assign_rhs1 (stmt); g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); gimple_call_set_lhs (g, lhs); gsi_replace (&gsi, g, false); break; default: break; } }
static void instrument_member_call (gimple_stmt_iterator *iter) { tree this_parm = gimple_call_arg (gsi_stmt (*iter), 0); tree kind = build_int_cst (unsigned_char_type_node, UBSAN_MEMBER_CALL); gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, this_parm, kind); gimple_set_location (g, gimple_location (gsi_stmt (*iter))); gsi_insert_before (iter, g, GSI_SAME_STMT); }
static void instrument_mem_ref (tree t, gimple_stmt_iterator *iter, bool is_lhs) { enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF; if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) ikind = UBSAN_MEMBER_ACCESS; tree kind = build_int_cst (unsigned_char_type_node, ikind); gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, t, kind); gimple_set_location (g, gimple_location (gsi_stmt (*iter))); gsi_insert_before (iter, g, GSI_SAME_STMT); }
static gcall * build_call_internal (internal_fn fn, tree type, unsigned int nargs, tree *ops) { if (direct_internal_fn_p (fn)) { tree_pair types = direct_internal_fn_types (fn, type, ops); if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH)) return NULL; } return gimple_build_call_internal (fn, nargs, ops[0], ops[1], ops[2]); }
static void use_internal_fn (gcall *call) { /* We'll be inserting another call with the same arguments after the lhs has been set, so prevent any possible coalescing failure from having both values live at once. See PR 71020. */ replace_abnormal_ssa_names (call); unsigned nconds = 0; auto_vec<gimple *, 12> conds; if (can_test_argument_range (call)) { gen_shrink_wrap_conditions (call, conds, &nconds); gcc_assert (nconds != 0); } else gcc_assert (edom_only_function (call)); internal_fn ifn = replacement_internal_fn (call); gcc_assert (ifn != IFN_LAST); /* Construct the new call, with the same arguments as the original one. */ auto_vec <tree, 16> args; unsigned int nargs = gimple_call_num_args (call); for (unsigned int i = 0; i < nargs; ++i) args.safe_push (gimple_call_arg (call, i)); gcall *new_call = gimple_build_call_internal_vec (ifn, args); gimple_set_location (new_call, gimple_location (call)); gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call)); /* Transfer the LHS to the new call. */ tree lhs = gimple_call_lhs (call); gimple_call_set_lhs (new_call, lhs); gimple_call_set_lhs (call, NULL_TREE); SSA_NAME_DEF_STMT (lhs) = new_call; /* Insert the new call. */ gimple_stmt_iterator gsi = gsi_for_stmt (call); gsi_insert_before (&gsi, new_call, GSI_SAME_STMT); if (nconds == 0) { /* Skip the call if LHS == LHS. If we reach here, EDOM is the only valid errno value and it is used iff the result is NaN. */ conds.quick_push (gimple_build_cond (EQ_EXPR, lhs, lhs, NULL_TREE, NULL_TREE)); nconds++; /* Try replacing the original call with a direct assignment to errno, via an internal function. */ if (set_edom_supported_p () && !stmt_ends_bb_p (call)) { gimple_stmt_iterator gsi = gsi_for_stmt (call); gcall *new_call = gimple_build_call_internal (IFN_SET_EDOM, 0); gimple_set_vuse (new_call, gimple_vuse (call)); gimple_set_vdef (new_call, gimple_vdef (call)); SSA_NAME_DEF_STMT (gimple_vdef (new_call)) = new_call; gimple_set_location (new_call, gimple_location (call)); gsi_replace (&gsi, new_call, false); call = new_call; } } shrink_wrap_one_built_in_call_with_conds (call, conds, nconds); }