On Sat, 20 Sep 2025, Martin Uecker wrote:
> Bootstrapped and regression tested on x86_64.
How's it useful when all UBSAN generated traps get a compile-time
diagnostic? Specifically for the testcase you add, how is this
diagnostig useful?
I'd instead have expected path isolation to diagnose inserted traps.
Richard.
>
> Add reason string to compiler emitted traps.
>
> For traps generated by the compiler, add a short string stating
> the reason. This string will be shown with -Wtrap when the trap
> is actually emitted.
>
> gcc/ChangeLog:
> * builtins.cc (expand_builtin_trap): Add string argument.
> (expand_builtin): Add reasons for traps.
> (expand_builtin_object_size): Don't emit message after error.
> * expr.cc (expand_assignment): Add reason for trap.
> * stmt.cc (expand_sjlj_dispatch_table): Add reason for trap.
> * ubsan.cc (ubsan_build_string): New function.
> (ubsan_build_string_ptr): New function.
> (ubsan_trap): New functions.
> (ubsan_source_location): Use ubsan_build_string_ptr.
> (ubsan_type_descriptor): Use ubsan_build_string.
> (ubsan_expand_bounds_ifn): Use ubsan_trap.
> (ubsan_expand_bounds_null): Dito.
> (ubsan_expand_objsize_ifn): Dito.
> (ubsan_expand_ptr_ifn): Dito.
> (instrument_bool_enum_load): Dito.
> (instrument_nonnull_arg): Dito.
> (instrument_nonnull_return): Dito.
> (instrument_builtin): Dito.
> (ubsan_build_overflow_builtin): Add message.
> (ubsan_instrument_float_case): Dito.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/Wtrap-2.c: New test.
>
> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
> index de5c96f3a25..2e3ac9df86d 100644
> --- a/gcc/builtins.cc
> +++ b/gcc/builtins.cc
> @@ -5968,10 +5968,10 @@ expand_builtin_trap_no_msg (void)
> /* Expand a call to __builtin_trap. */
>
> void
> -expand_builtin_trap ()
> +expand_builtin_trap (const char *reason)
> {
> if (warn_trap)
> - warning_at (input_location, OPT_Wtrap, "trap generated");
> + warning_at (input_location, OPT_Wtrap, "trap generated: \"%.99s\"",
> reason);
>
> return expand_builtin_trap_no_msg ();
> }
> @@ -8448,8 +8448,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget,
> machine_mode mode,
> return const0_rtx;
>
> case BUILT_IN_TRAP:
> + expand_builtin_trap ("builtin");
> + return const0_rtx;
> +
> case BUILT_IN_UNREACHABLE_TRAP:
> - expand_builtin_trap ();
> + expand_builtin_trap ("unreachable");
> return const0_rtx;
>
> case BUILT_IN_UNREACHABLE:
> @@ -11554,7 +11557,7 @@ expand_builtin_object_size (tree exp)
> {
> error ("first argument of %qD must be a pointer, second integer
> constant",
> fndecl);
> - expand_builtin_trap ();
> + expand_builtin_trap_no_msg ();
> return const0_rtx;
> }
>
> @@ -11567,7 +11570,7 @@ expand_builtin_object_size (tree exp)
> {
> error ("last argument of %qD is not integer constant between 0 and 3",
> fndecl);
> - expand_builtin_trap ();
> + expand_builtin_trap_no_msg ();
> return const0_rtx;
> }
>
> diff --git a/gcc/builtins.h b/gcc/builtins.h
> index 5a553a9c836..ae4ba4a9b96 100644
> --- a/gcc/builtins.h
> +++ b/gcc/builtins.h
> @@ -129,7 +129,7 @@ extern tree std_build_builtin_va_list (void);
> extern tree std_fn_abi_va_list (tree);
> extern tree std_canonical_va_list_type (tree);
> extern void std_expand_builtin_va_start (tree, rtx);
> -extern void expand_builtin_trap (void);
> +extern void expand_builtin_trap (const char *);
> extern void expand_ifn_atomic_bit_test_and (gcall *);
> extern void expand_ifn_atomic_compare_exchange (gcall *);
> extern void expand_ifn_atomic_op_fetch_cmp_0 (gcall *);
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index 4a699101bb5..c6fc3b25f42 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -6102,7 +6102,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
> user code. Translate this to a trap instead of ICEing. */
> if (TREE_CODE (offset) == INTEGER_CST)
> {
> - expand_builtin_trap ();
> + expand_builtin_trap ("invalid offset");
> to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
> }
> /* Else spill for variable offset to the destination. We expect
> diff --git a/gcc/stmt.cc b/gcc/stmt.cc
> index 7942aa3e484..2e95b207603 100644
> --- a/gcc/stmt.cc
> +++ b/gcc/stmt.cc
> @@ -1393,7 +1393,7 @@ expand_sjlj_dispatch_table (rtx dispatch_index,
> }
>
> /* Dispatching something not handled? Trap! */
> - expand_builtin_trap ();
> + expand_builtin_trap ("dispatch not handled");
>
> reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case);
>
> diff --git a/gcc/testsuite/gcc.dg/Wtrap-2.c b/gcc/testsuite/gcc.dg/Wtrap-2.c
> new file mode 100644
> index 00000000000..ce2e596d947
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wtrap-2.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wtrap -fsanitize=bounds -fsanitize-trap=bounds" } */
> +
> +void foo(int n, char (*buf)[n])
> +{
> + (*buf)[10] = 1; /* { dg-warning "trap generated:
> \"bounds (sanitizer)\"" } */
> +}
> +
> +void bar()
> +{
> + __builtin_unreachable(); /* { dg-warning "trap generated:
> \"unreachable\"" } */
> +}
> +
> diff --git a/gcc/ubsan.cc b/gcc/ubsan.cc
> index 6d748258b1e..801f4c7830e 100644
> --- a/gcc/ubsan.cc
> +++ b/gcc/ubsan.cc
> @@ -303,6 +303,35 @@ ubsan_get_source_location_type (void)
> return ret;
> }
>
> +
> +static tree
> +ubsan_build_string (const char *cstr)
> +{
> + size_t len = strlen (cstr) + 1;
> + tree str = build_string (len, cstr);
> + TREE_TYPE (str) = build_array_type_nelts (char_type_node, len);
> + TREE_READONLY (str) = 1;
> + TREE_STATIC (str) = 1;
> + return str;
> +}
> +
> +static tree
> +ubsan_build_string_ptr (const char *cstr)
> +{
> + return build_fold_addr_expr (ubsan_build_string (cstr));
> +}
> +
> +/* Helper routine that expands a trap with a message. */
> +
> +static gimple *
> +ubsan_trap (const char *cstr)
> +{
> + return gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP_MSG),
> + 1, ubsan_build_string_ptr (cstr));
> +}
> +
> +
> +
> /* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
> type with its fields filled from a location_t LOC. */
>
> @@ -323,12 +352,7 @@ ubsan_source_location (location_t loc)
> else
> {
> /* Fill in the values from LOC. */
> - size_t len = strlen (xloc.file) + 1;
> - str = build_string (len, xloc.file);
> - TREE_TYPE (str) = build_array_type_nelts (char_type_node, len);
> - TREE_READONLY (str) = 1;
> - TREE_STATIC (str) = 1;
> - str = build_fold_addr_expr (str);
> + str = ubsan_build_string_ptr (xloc.file);
> }
> tree ctor = build_constructor_va (type, 3, NULL_TREE, str, NULL_TREE,
> build_int_cst (unsigned_type_node,
> @@ -542,11 +566,7 @@ ubsan_type_descriptor (tree type, enum ubsan_print_style
> pstyle)
>
> /* Create a new VAR_DECL of type descriptor. */
> const char *tmp = pp_formatted_text (&pretty_name);
> - size_t len = strlen (tmp) + 1;
> - tree str = build_string (len, tmp);
> - TREE_TYPE (str) = build_array_type_nelts (char_type_node, len);
> - TREE_READONLY (str) = 1;
> - TREE_STATIC (str) = 1;
> + tree str = ubsan_build_string (tmp);
>
> decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> generate_internal_label ("Lubsan_type"), dtype);
> @@ -786,7 +806,7 @@ ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
> /* Generate __ubsan_handle_out_of_bounds call. */
> *gsi = gsi_after_labels (then_bb);
> if (flag_sanitize_trap & SANITIZE_BOUNDS)
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("bounds (sanitizer)");
> else
> {
> tree data
> @@ -902,7 +922,7 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
> /* Put the ubsan builtin call into the newly created BB. */
> if (flag_sanitize_trap & ((check_align ? SANITIZE_ALIGNMENT + 0 : 0)
> | (check_null ? SANITIZE_NULL + 0 : 0)))
> - g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("alignment / null (sanitizer)");
> else
> {
> enum built_in_function bcode
> @@ -1072,7 +1092,7 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
>
> /* Generate __ubsan_handle_type_mismatch call. */
> if (flag_sanitize_trap & SANITIZE_OBJECT_SIZE)
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("object size (sanitizer)");
> else
> {
> tree data
> @@ -1218,7 +1238,7 @@ ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
>
> /* Put the ubsan builtin call into the newly created BB. */
> if (flag_sanitize_trap & SANITIZE_POINTER_OVERFLOW)
> - g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("pointer overflow (sanitizer)");
> else
> {
> enum built_in_function bcode
> @@ -1601,8 +1621,11 @@ ubsan_build_overflow_builtin (tree_code code,
> location_t loc, tree lhstype,
> tree op0, tree op1, tree *datap)
> {
> if (flag_sanitize_trap & SANITIZE_SI_OVERFLOW)
> - return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP),
> 0);
> -
> + {
> + tree reason = ubsan_build_string_ptr ("signed overflow (sanitizer)");
> + return build_call_expr_loc (loc, builtin_decl_explicit
> (BUILT_IN_TRAP_MSG),
> + 1, reason);
> + }
> tree data;
> if (datap && *datap)
> data = *datap;
> @@ -1830,7 +1853,7 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi)
> gsi2 = gsi_after_labels (then_bb);
> if (flag_sanitize_trap & (TREE_CODE (type) == BOOLEAN_TYPE
> ? SANITIZE_BOOL : SANITIZE_ENUM))
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("bool / enum (sanitizer)");
> else
> {
> tree data = ubsan_create_data ("__ubsan_invalid_value_data", 1, &loc,
> @@ -1991,7 +2014,11 @@ ubsan_instrument_float_cast (location_t loc, tree
> type, tree expr)
> return NULL_TREE;
>
> if (flag_sanitize_trap & SANITIZE_FLOAT_CAST)
> - fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + {
> + tree reason = ubsan_build_string_ptr ("float cast (sanitizer)");
> + fn = build_call_expr_loc (loc, builtin_decl_explicit
> (BUILT_IN_TRAP_MSG),
> + 1, reason);
> + }
> else
> {
> location_t *loc_ptr = NULL;
> @@ -2102,7 +2129,7 @@ instrument_nonnull_arg (gimple_stmt_iterator *gsi)
> *gsi = gsi_after_labels (then_bb);
> }
> if (flag_sanitize_trap & SANITIZE_NONNULL_ATTRIBUTE)
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("nonnull (sanitizer)");
> else
> {
> tree data = ubsan_create_data ("__ubsan_nonnull_arg_data",
> @@ -2158,7 +2185,7 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi)
>
> *gsi = gsi_after_labels (then_bb);
> if (flag_sanitize_trap & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("returns nonnull (sanitizer)");
> else
> {
> tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
> @@ -2404,7 +2431,7 @@ instrument_builtin (gimple_stmt_iterator *gsi)
>
> *gsi = gsi_after_labels (then_bb);
> if (flag_sanitize_trap & SANITIZE_BUILTIN)
> - g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + g = ubsan_trap ("builtin (sanitizer)");
> else
> {
> tree t = build_int_cst (unsigned_char_type_node, kind);
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)