Am Montag, dem 22.09.2025 um 11:00 +0200 schrieb Richard Biener:
> 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?
My intention was that this works for all traps the compiler
generates, so this would natually include UBsan generated
traps. I think it would be rather strange to exclude them. The
testcase is not mean to illustrate a use case.
I personally find it useful to better understand what UBsan
does to the code. Clearly, if you simply apply it to a regular
C program compiled with UBsan this will give you a lot of warnings,
and this will not be too useful except maybe for statistics and
overall impact. But in more specific cases it is useful to
better understand whether some error scenario is instrumented and
whether it can actually occur or not.
>
> I'd instead have expected path isolation to diagnose inserted traps.
It will be diagnosed by the patch, if I am not missing anything.
But yes, this should get its own reason string as well.
Martin
>
> 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);
> >