diff mbox series

warning option for traps (-Wtrap)

Message ID 410be3cb27dcbf531b9e22370303176f137f181e.camel@tugraz.at
State New
Headers show
Series warning option for traps (-Wtrap) | expand

Commit Message

Martin Uecker Oct. 12, 2024, 2:42 p.m. UTC
There is code which should not fail at run-time.  For this,
it is helpful to get a warning when a compiler inserts traps
(e.g. sanitizers, hardbools, __builtin_trap(), etc.).

Having a warning for this also has many other use cases, e.g.
one can use it with some sanitizer to rule out that some
piece of code has certain undefined behavior such as
signed overflow or undefined behavior in left-shifts
(one gets a warning if the optimizer does not prove the
trap is dead and it is emitted). 

Another potential use case could be writing tests.


Bootstrapped and regression tested on x64_84.


    Add warning option that warns when a trap is generated.
    
    This adds a warning option -Wtrap that is emitted in
    expand_builtin_trap.  It can be used to verify that traps
    are generated or - more importantly - are not generated
    under various conditions, e.g. for UBSan with -fsanitize-trap,
    hardbools, etc.
    
    gcc/ChangeLog:
            * common.opt (Wtrap): Add warning.
            * builtins.cc (expand_builtin_trap): Add warning.
            * doc/invoke.texi (Wtrap): Document warning.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/Wtrap.c: New test.

Comments

Richard Biener Oct. 12, 2024, 4:44 p.m. UTC | #1
> Am 12.10.2024 um 16:43 schrieb Martin Uecker <uecker@tugraz.at>:
> 
> 
> There is code which should not fail at run-time.  For this,
> it is helpful to get a warning when a compiler inserts traps
> (e.g. sanitizers, hardbools, __builtin_trap(), etc.).
> 
> Having a warning for this also has many other use cases, e.g.
> one can use it with some sanitizer to rule out that some
> piece of code has certain undefined behavior such as
> signed overflow or undefined behavior in left-shifts
> (one gets a warning if the optimizer does not prove the
> trap is dead and it is emitted).
> 
> Another potential use case could be writing tests.
> 
> 
> Bootstrapped and regression tested on x64_84.
> 
> 
>    Add warning option that warns when a trap is generated.
> 
>    This adds a warning option -Wtrap that is emitted in
>    expand_builtin_trap.  It can be used to verify that traps
>    are generated or - more importantly - are not generated
>    under various conditions, e.g. for UBSan with -fsanitize-trap,
>    hardbools, etc.

Isn’t it better to diagnose with more context from the callers that insert the trap?

>    gcc/ChangeLog:
>            * common.opt (Wtrap): Add warning.
>            * builtins.cc (expand_builtin_trap): Add warning.
>            * doc/invoke.texi (Wtrap): Document warning.
> 
>    gcc/testsuite/ChangeLog:
>            * gcc.dg/Wtrap.c: New test.
> 
> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
> index 37c7c98e5c7..76268f62481 100644
> --- a/gcc/builtins.cc
> +++ b/gcc/builtins.cc
> @@ -5896,6 +5896,14 @@ expand_builtin_assume_aligned (tree exp, rtx target)
> void
> expand_builtin_trap (void)
> {
> +  if (warn_trap)
> +    {
> +      location_t current_location =
> +    linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
> +                          NULL);
> +    warning_at (current_location, OPT_Wtrap, "trap generated");
> +    }
> +
>   if (targetm.have_trap ())
>     {
>       rtx_insn *insn = emit_insn (targetm.gen_trap ());
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 12b25ff486d..1cc4936ebbf 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -812,6 +812,10 @@ Wsystem-headers
> Common Var(warn_system_headers) Warning
> Do not suppress warnings from system headers.
> 
> +Wtrap
> +Common Var(warn_trap) Warning
> +Warn whenever a trap is generated.
> +
> Wtrampolines
> Common Var(warn_trampolines) Warning
> Warn whenever a trampoline is generated.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 575dffd2a2f..68833c4350f 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8784,6 +8784,14 @@ made up of data only and thus requires no special treatment.  But, for
> most targets, it is made up of code and thus requires the stack to be
> made executable in order for the program to work properly.
> 
> +@opindex Wtrap
> +@opindex Wno-trap
> +@item -Wtrap
> +Warn when explicit traps are generated.  Traps may be generated for
> +a variety of reasons, e.g. when using the undefined behavior sanitizer
> +together with @option{-fsanitize-trap=undefined}.
> +
> +
> @opindex Wfloat-equal
> @opindex Wno-float-equal
> @item -Wfloat-equal
> diff --git a/gcc/testsuite/gcc.dg/Wtrap.c b/gcc/testsuite/gcc.dg/Wtrap.c
> new file mode 100644
> index 00000000000..2f2878f9d45
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wtrap.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wtrap" } */
> +
> +void foo(void)
> +{
> +    __builtin_trap();    /* { dg-warning "trap generated" } */
> +}
> +
>
Martin Uecker Oct. 12, 2024, 6:03 p.m. UTC | #2
Am Samstag, dem 12.10.2024 um 18:44 +0200 schrieb Richard Biener:
> 
> > Am 12.10.2024 um 16:43 schrieb Martin Uecker <uecker@tugraz.at>:
> > 
> > 
> > There is code which should not fail at run-time.  For this,
> > it is helpful to get a warning when a compiler inserts traps
> > (e.g. sanitizers, hardbools, __builtin_trap(), etc.).
> > 
> > Having a warning for this also has many other use cases, e.g.
> > one can use it with some sanitizer to rule out that some
> > piece of code has certain undefined behavior such as
> > signed overflow or undefined behavior in left-shifts
> > (one gets a warning if the optimizer does not prove the
> > trap is dead and it is emitted).
> > 
> > Another potential use case could be writing tests.
> > 
> > 
> > Bootstrapped and regression tested on x64_84.
> > 
> > 
> >    Add warning option that warns when a trap is generated.
> > 
> >    This adds a warning option -Wtrap that is emitted in
> >    expand_builtin_trap.  It can be used to verify that traps
> >    are generated or - more importantly - are not generated
> >    under various conditions, e.g. for UBSan with -fsanitize-trap,
> >    hardbools, etc.
> 
> Isn’t it better to diagnose with more context from the callers that insert the trap?

More context would be better.  Should there be additional
arguments when creating the call to the builtin?

Martin


> 
> >    gcc/ChangeLog:
> >            * common.opt (Wtrap): Add warning.
> >            * builtins.cc (expand_builtin_trap): Add warning.
> >            * doc/invoke.texi (Wtrap): Document warning.
> > 
> >    gcc/testsuite/ChangeLog:
> >            * gcc.dg/Wtrap.c: New test.
> > 
> > diff --git a/gcc/builtins.cc b/gcc/builtins.cc
> > index 37c7c98e5c7..76268f62481 100644
> > --- a/gcc/builtins.cc
> > +++ b/gcc/builtins.cc
> > @@ -5896,6 +5896,14 @@ expand_builtin_assume_aligned (tree exp, rtx target)
> > void
> > expand_builtin_trap (void)
> > {
> > +  if (warn_trap)
> > +    {
> > +      location_t current_location =
> > +    linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
> > +                          NULL);
> > +    warning_at (current_location, OPT_Wtrap, "trap generated");
> > +    }
> > +
> >   if (targetm.have_trap ())
> >     {
> >       rtx_insn *insn = emit_insn (targetm.gen_trap ());
> > diff --git a/gcc/common.opt b/gcc/common.opt
> > index 12b25ff486d..1cc4936ebbf 100644
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -812,6 +812,10 @@ Wsystem-headers
> > Common Var(warn_system_headers) Warning
> > Do not suppress warnings from system headers.
> > 
> > +Wtrap
> > +Common Var(warn_trap) Warning
> > +Warn whenever a trap is generated.
> > +
> > Wtrampolines
> > Common Var(warn_trampolines) Warning
> > Warn whenever a trampoline is generated.
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 575dffd2a2f..68833c4350f 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -8784,6 +8784,14 @@ made up of data only and thus requires no special treatment.  But, for
> > most targets, it is made up of code and thus requires the stack to be
> > made executable in order for the program to work properly.
> > 
> > +@opindex Wtrap
> > +@opindex Wno-trap
> > +@item -Wtrap
> > +Warn when explicit traps are generated.  Traps may be generated for
> > +a variety of reasons, e.g. when using the undefined behavior sanitizer
> > +together with @option{-fsanitize-trap=undefined}.
> > +
> > +
> > @opindex Wfloat-equal
> > @opindex Wno-float-equal
> > @item -Wfloat-equal
> > diff --git a/gcc/testsuite/gcc.dg/Wtrap.c b/gcc/testsuite/gcc.dg/Wtrap.c
> > new file mode 100644
> > index 00000000000..2f2878f9d45
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/Wtrap.c
> > @@ -0,0 +1,8 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -Wtrap" } */
> > +
> > +void foo(void)
> > +{
> > +    __builtin_trap();    /* { dg-warning "trap generated" } */
> > +}
> > +
> >
Richard Biener Oct. 13, 2024, 8:56 a.m. UTC | #3
On Sat, 12 Oct 2024, Martin Uecker wrote:

> Am Samstag, dem 12.10.2024 um 18:44 +0200 schrieb Richard Biener:
> > 
> > > Am 12.10.2024 um 16:43 schrieb Martin Uecker <uecker@tugraz.at>:
> > > 
> > > 
> > > There is code which should not fail at run-time.  For this,
> > > it is helpful to get a warning when a compiler inserts traps
> > > (e.g. sanitizers, hardbools, __builtin_trap(), etc.).
> > > 
> > > Having a warning for this also has many other use cases, e.g.
> > > one can use it with some sanitizer to rule out that some
> > > piece of code has certain undefined behavior such as
> > > signed overflow or undefined behavior in left-shifts
> > > (one gets a warning if the optimizer does not prove the
> > > trap is dead and it is emitted).
> > > 
> > > Another potential use case could be writing tests.
> > > 
> > > 
> > > Bootstrapped and regression tested on x64_84.
> > > 
> > > 
> > >    Add warning option that warns when a trap is generated.
> > > 
> > >    This adds a warning option -Wtrap that is emitted in
> > >    expand_builtin_trap.  It can be used to verify that traps
> > >    are generated or - more importantly - are not generated
> > >    under various conditions, e.g. for UBSan with -fsanitize-trap,
> > >    hardbools, etc.
> > 
> > Isn’t it better to diagnose with more context from the callers that insert the trap?
> 
> More context would be better.  Should there be additional
> arguments when creating the call to the builtin?

Why not diagnose when we create the call?  But sure, adding a diagnostic
argument would work, it might also work to distinguish calls we want to
diagnose from those we don't.

Richard.
Martin Uecker Oct. 13, 2024, 9:32 a.m. UTC | #4
Am Sonntag, dem 13.10.2024 um 10:56 +0200 schrieb Richard Biener:
> On Sat, 12 Oct 2024, Martin Uecker wrote:
> 
> > Am Samstag, dem 12.10.2024 um 18:44 +0200 schrieb Richard Biener:
> > > 
> > > > Am 12.10.2024 um 16:43 schrieb Martin Uecker <uecker@tugraz.at>:
> > > > 
> > > > 
> > > > There is code which should not fail at run-time.  For this,
> > > > it is helpful to get a warning when a compiler inserts traps
> > > > (e.g. sanitizers, hardbools, __builtin_trap(), etc.).
> > > > 
> > > > Having a warning for this also has many other use cases, e.g.
> > > > one can use it with some sanitizer to rule out that some
> > > > piece of code has certain undefined behavior such as
> > > > signed overflow or undefined behavior in left-shifts
> > > > (one gets a warning if the optimizer does not prove the
> > > > trap is dead and it is emitted).
> > > > 
> > > > Another potential use case could be writing tests.
> > > > 
> > > > 
> > > > Bootstrapped and regression tested on x64_84.
> > > > 
> > > > 
> > > >    Add warning option that warns when a trap is generated.
> > > > 
> > > >    This adds a warning option -Wtrap that is emitted in
> > > >    expand_builtin_trap.  It can be used to verify that traps
> > > >    are generated or - more importantly - are not generated
> > > >    under various conditions, e.g. for UBSan with -fsanitize-trap,
> > > >    hardbools, etc.
> > > 
> > > Isn’t it better to diagnose with more context from the callers that insert the trap?
> > 
> > More context would be better.  Should there be additional
> > arguments when creating the call to the builtin?
> 
> Why not diagnose when we create the call? 

I agree that having optional warnings for all situation where there
could be run-time UB (or a trap) would be useful.  But having a
generic warning for all such situations would produce many warnings
and also cover cases where we already have more specific warnings.

Doing it when the trap is generated directly gives me somewhat
different information that I sometimes need: Is there a trap left
in the generated binary?

We have a similar warning already for generating trampolines.

Before adding the warning to my local tree, I often looked at the
generated assembly to look for  generated "ud2" instructions.  But this
is painful and gives me even less context.

A practical example from failing to properly take integer
promotions into account (adapted from a old bug in a crypto
library) is:

uint32_t bar(int N, unsigned char key)
{
    unsigned int kappa = key << 24;
    return kappa;
}

which has UB that the warning tells me about and 
where adding a cast is required to eliminate it:
https://godbolt.org/z/osvEsdcqc


>  But sure, adding a diagnostic
> argument would work, it might also work to distinguish calls we want to
> diagnose from those we don't.

Would it be reasonable to approve this patch now and I try
to improve this later?

Martin
Richard Biener Oct. 15, 2024, 9:50 a.m. UTC | #5
On Sun, 13 Oct 2024, Martin Uecker wrote:

> Am Sonntag, dem 13.10.2024 um 10:56 +0200 schrieb Richard Biener:
> > On Sat, 12 Oct 2024, Martin Uecker wrote:
> > 
> > > Am Samstag, dem 12.10.2024 um 18:44 +0200 schrieb Richard Biener:
> > > > 
> > > > > Am 12.10.2024 um 16:43 schrieb Martin Uecker <uecker@tugraz.at>:
> > > > > 
> > > > > 
> > > > > There is code which should not fail at run-time.  For this,
> > > > > it is helpful to get a warning when a compiler inserts traps
> > > > > (e.g. sanitizers, hardbools, __builtin_trap(), etc.).
> > > > > 
> > > > > Having a warning for this also has many other use cases, e.g.
> > > > > one can use it with some sanitizer to rule out that some
> > > > > piece of code has certain undefined behavior such as
> > > > > signed overflow or undefined behavior in left-shifts
> > > > > (one gets a warning if the optimizer does not prove the
> > > > > trap is dead and it is emitted).
> > > > > 
> > > > > Another potential use case could be writing tests.
> > > > > 
> > > > > 
> > > > > Bootstrapped and regression tested on x64_84.
> > > > > 
> > > > > 
> > > > >    Add warning option that warns when a trap is generated.
> > > > > 
> > > > >    This adds a warning option -Wtrap that is emitted in
> > > > >    expand_builtin_trap.  It can be used to verify that traps
> > > > >    are generated or - more importantly - are not generated
> > > > >    under various conditions, e.g. for UBSan with -fsanitize-trap,
> > > > >    hardbools, etc.
> > > > 
> > > > Isn’t it better to diagnose with more context from the callers that insert the trap?
> > > 
> > > More context would be better.  Should there be additional
> > > arguments when creating the call to the builtin?
> > 
> > Why not diagnose when we create the call? 
> 
> I agree that having optional warnings for all situation where there
> could be run-time UB (or a trap) would be useful.  But having a
> generic warning for all such situations would produce many warnings
> and also cover cases where we already have more specific warnings.
> 
> Doing it when the trap is generated directly gives me somewhat
> different information that I sometimes need: Is there a trap left
> in the generated binary?
> 
> We have a similar warning already for generating trampolines.
> 
> Before adding the warning to my local tree, I often looked at the
> generated assembly to look for  generated "ud2" instructions.  But this
> is painful and gives me even less context.
> 
> A practical example from failing to properly take integer
> promotions into account (adapted from a old bug in a crypto
> library) is:
> 
> uint32_t bar(int N, unsigned char key)
> {
>     unsigned int kappa = key << 24;
>     return kappa;
> }
> 
> which has UB that the warning tells me about and 
> where adding a cast is required to eliminate it:
> https://godbolt.org/z/osvEsdcqc
> 
> 
> >  But sure, adding a diagnostic
> > argument would work, it might also work to distinguish calls we want to
> > diagnose from those we don't.
> 
> Would it be reasonable to approve this patch now and I try
> to improve this later?

On the patch itself:

 void
 expand_builtin_trap (void)
 {
+  if (warn_trap)
+    {
+      location_t current_location =
+       linemap_unwind_to_first_non_reserved_loc (line_table, 
input_location,
+                                                 NULL);
+       warning_at (current_location, OPT_Wtrap, "trap generated");
+    }
+
   if (targetm.have_trap ())

this also diagnoses calls the user puts in by calling __builtin_trap (),
the documentation should probably mention this.  I see the only testcase
exercises only this path.  I have doubts -fsanitize-trap with any
sanitizer will ever yield a clean binary, so I wonder about practical
uses besides very small testcases?

Is there any reason to use linemap_unwind_to_first_non_reserved_loc
here?

Thanks,
Richard.
Jakub Jelinek Oct. 15, 2024, 10:15 a.m. UTC | #6
On Tue, Oct 15, 2024 at 11:50:21AM +0200, Richard Biener wrote:
> > Would it be reasonable to approve this patch now and I try
> > to improve this later?
> 
> On the patch itself:
> 
>  void
>  expand_builtin_trap (void)
>  {
> +  if (warn_trap)
> +    {
> +      location_t current_location =

Formatting-wise, = shouldn't be at the end of line.

> +       linemap_unwind_to_first_non_reserved_loc (line_table, 
> input_location,
> +                                                 NULL);
> +       warning_at (current_location, OPT_Wtrap, "trap generated");
> +    }
> +
>    if (targetm.have_trap ())
> 
> this also diagnoses calls the user puts in by calling __builtin_trap (),
> the documentation should probably mention this.  I see the only testcase
> exercises only this path.  I have doubts -fsanitize-trap with any
> sanitizer will ever yield a clean binary, so I wonder about practical
> uses besides very small testcases?

Given that even simple
int foo (int x, int y) { return x + y; }
calls it for -fsanitize=undefined -fsanitize-trap=undefined, and more
importantly, we try not to optimize away sanitizer checks based on VRP and
other optimizations at least to some extent, because VRP and other
optimizations optimize on UB not happening while sanitizers try to catch
the UB, I have serious doubts about the warning.
One would need completely different approach, where we try as much as
possible to prove UB can't happen and only warn if we couldn't prove it
can't.  Still, there would be tons of false positives where things just
aren't inlined and we can't prove UB won't happen, or warnings on dead
code...

	Jakub
Martin Uecker Oct. 15, 2024, 2:53 p.m. UTC | #7
Am Dienstag, dem 15.10.2024 um 12:15 +0200 schrieb Jakub Jelinek:
> On Tue, Oct 15, 2024 at 11:50:21AM +0200, Richard Biener wrote:
> > > Would it be reasonable to approve this patch now and I try
> > > to improve this later?
> > 
> > On the patch itself:
> > 
> >  void
> >  expand_builtin_trap (void)
> >  {
> > +  if (warn_trap)
> > +    {
> > +      location_t current_location =
> 
> Formatting-wise, = shouldn't be at the end of line.
> 
> > +       linemap_unwind_to_first_non_reserved_loc (line_table, 
> > input_location,
> > +                                                 NULL);
> > +       warning_at (current_location, OPT_Wtrap, "trap generated");
> > +    }
> > +
> >    if (targetm.have_trap ())
> > 
> > this also diagnoses calls the user puts in by calling __builtin_trap (),
> > the documentation should probably mention this.  I see the only testcase
> > exercises only this path.  I have doubts -fsanitize-trap with any
> > sanitizer will ever yield a clean binary, so I wonder about practical
> > uses besides very small testcases?
> 
> Given that even simple
> int foo (int x, int y) { return x + y; }
> calls it for -fsanitize=undefined -fsanitize-trap=undefined, and more
> importantly, we try not to optimize away sanitizer checks based on VRP and
> other optimizations at least to some extent, because VRP and other
> optimizations optimize on UB not happening while sanitizers try to catch
> the UB, I have serious doubts about the warning.
> One would need completely different approach, where we try as much as
> possible to prove UB can't happen and only warn if we couldn't prove it
> can't.  Still, there would be tons of false positives where things just
> aren't inlined and we can't prove UB won't happen, or warnings on dead
> code...
> 

It would not be practical with some sanitizers (and sanitizers are also not
the only usecase anyhow). But attached below is the list of emitted warnings
for different sanitizers depending on the optimization level for
BART (https://github.com/mrirecon/bart).  The first number is optimization,
then the number of warnings, and then the number with different warnings
from the same source location (e.g. macros) combined.  The project has
>400 C source files.

For some sanitizers the number is rather low and e.g. shift is something
I was looking at specifically and where I already found this useful.  But
also for  some the others the numbers are low enough to investigate each case. 
For new code, an average number of warnings per file of 10 would also
still seem entirely reasonable, so I think one could eliminate all
integer overflow cases if one wanted to. But also doing this only for
criticial pieces of code (e.g. using #pragma GCC diagnostic ...) would
seem useful.

One also sees that the optimizer actually does remove a lot of traps. That
the total number sometimes goes up with -O2 is mostly likely due to code
duplication, but the unique cases always go down with more optimization.
(except for object-size which does not run fully for -O1 I believe)

I have to admit I did not understand your comment about VRP, but
in my experience we remove UB sanitization based on value ranges, e.g.
in this example for signed overflow.

https://godbolt.org/z/zeMvas3nq

Martin



shift 0 525 31
shift 1 298 19
shift 2 221 19
signed-integer-overflow 0 12212 11350
signed-integer-overflow 1 6310 5913
signed-integer-overflow 2 3803 3172
integer-divide-by-zero 0 332 332
integer-divide-by-zero 1 135 135
integer-divide-by-zero 2 95 95
unreachable 0 0 0
unreachable 1 0 0
unreachable 2 4 4
vla-bound 0 2671 2426
vla-bound 1 1206 1143
vla-bound 2 1024 906
null 0 32041 26739
null 1 8926 7666
null 2 8622 6769
return 0 0 0
return 1 0 0
return 2 4 4
bounds 0 5031 4830
bounds 1 4776 4551
bounds 2 4986 4547
bounds-strict 0 5031 4830
bounds-strict 1 4776 4551
bounds-strict 2 4986 4547
alignment 0 31818 26524
alignment 1 9848 8441
alignment 2 10031 7855
object-size 0 465 453
object-size 1 5928 5491
object-size 2 6013 5366
float-divide-by-zero 0 532 532
float-divide-by-zero 1 430 429
float-divide-by-zero 2 250 245
float-cast-overflow 0 107 98
float-cast-overflow 1 99 91
float-cast-overflow 2 65 59
nonnull-attribute 0 13433 7672
nonnull-attribute 1 5199 3466
nonnull-attribute 2 1085 1005
return-nonnull-attribute 0 0 0
return-nonnull-attribute 1 0 0
return-nonnull-attribute 2 0 0
bool 0 1053 1036
bool 1 988 972
bool 2 371 363
enum 0 0 0
enum 1 0 0
enum 2 4 4
pointer-overflow 0 29095 25298
pointer-overflow 1 17284 16254
pointer-overflow 2 18598 16110
builtin 0 0 0
builtin 1 0 0
builtin 2 4 4
diff mbox series

Patch

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 37c7c98e5c7..76268f62481 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -5896,6 +5896,14 @@  expand_builtin_assume_aligned (tree exp, rtx target)
 void
 expand_builtin_trap (void)
 {
+  if (warn_trap)
+    {
+      location_t current_location =
+	linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
+						  NULL);
+	warning_at (current_location, OPT_Wtrap, "trap generated");
+    }
+
   if (targetm.have_trap ())
     {
       rtx_insn *insn = emit_insn (targetm.gen_trap ());
diff --git a/gcc/common.opt b/gcc/common.opt
index 12b25ff486d..1cc4936ebbf 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -812,6 +812,10 @@  Wsystem-headers
 Common Var(warn_system_headers) Warning
 Do not suppress warnings from system headers.
 
+Wtrap
+Common Var(warn_trap) Warning
+Warn whenever a trap is generated.
+
 Wtrampolines
 Common Var(warn_trampolines) Warning
 Warn whenever a trampoline is generated.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 575dffd2a2f..68833c4350f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8784,6 +8784,14 @@  made up of data only and thus requires no special treatment.  But, for
 most targets, it is made up of code and thus requires the stack to be
 made executable in order for the program to work properly.
 
+@opindex Wtrap
+@opindex Wno-trap
+@item -Wtrap
+Warn when explicit traps are generated.  Traps may be generated for
+a variety of reasons, e.g. when using the undefined behavior sanitizer
+together with @option{-fsanitize-trap=undefined}.
+
+
 @opindex Wfloat-equal
 @opindex Wno-float-equal
 @item -Wfloat-equal
diff --git a/gcc/testsuite/gcc.dg/Wtrap.c b/gcc/testsuite/gcc.dg/Wtrap.c
new file mode 100644
index 00000000000..2f2878f9d45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wtrap.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wtrap" } */
+
+void foo(void)
+{
+	__builtin_trap();	/* { dg-warning "trap generated" } */
+}
+