On Mon, 2026-01-26 at 19:19 -0500, David Malcolm wrote: > As of r16-264-g7a39e0ca0652ff, -fanalyzer assumes that a call to an > external function not marked with attribute "nothrow" could throw an > exception, if -fexceptions is enabled. > > PR analyzer/122623 notes that testing -fanalyzer with GCC 16 on > Fedora > packages turned up some new leak warnings due to -fexceptions being > passed to all C code (for interoperability with C++), due to C > headers > typically not having their entrypoints being marked with "nothrow". > Some of these are false positives. Others are arguably true > positives, > such as the case in the above report, but highly surprising to > end-users, and of dubious value. > > I don't have data on the scale of the problem, but I am worried that > the C++ exception support added in GCC 16 could cause a big > regression > in analyzer signal:noise when compiling C code with distro build > flags. > > To provide a workaround for distro mass analysis runs, this patch > adds a > new option: -fanalyzer-assume-nothrow, which when enabled assumes > that > external functions do not throw exceptions. This may be something of > a > blunt hammer, but may be useful to distros to add to build flags for > C, > to allow the combination "-fexceptions -fanalyzer-assume-nothrow" so > that the generated code supports exception-handling, but the analyzer > ignores it. > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > Successful run of analyzer integration tests on x86_64-pc-linux-gnu > without the option set; I plan to try again with the option set.
I ran the analyzer integration tests with the option enabled, and it seemed to fix some false positives there. > Given the above, I'm thinking of applying this to trunk for GCC 16. Given that, and that I got feedback off-list that this would indeed be useful for using -fanalyzer for mass-scans of Fedora SRPMs, I've gone ahead and pushed the patch to trunk for GCC 16, as r16-7080- gf1318516f07453. Dave > > Thoughts? > > Thanks > Dave > > > gcc/analyzer/ChangeLog: > PR analyzer/122623 > * analyzer.opt (fanalyzer-assume-nothrow): New. > * analyzer.opt.urls: Regenerate. > * region-model.cc (can_throw_p): Bail out if the user > specified > -fanalyzer-assume-nothrow. > > gcc/ChangeLog: > PR analyzer/122623 > * doc/invoke.texi (-fanalyzer-assume-nothrow): New option. > > gcc/testsuite/ChangeLog: > PR analyzer/122623 > * gcc.dg/analyzer/fexceptions-1.c: New test. > * gcc.dg/analyzer/fexceptions-2.c: New test. > > Signed-off-by: David Malcolm <[email protected]> > --- > gcc/analyzer/analyzer.opt | 4 +++ > gcc/analyzer/analyzer.opt.urls | 3 +++ > gcc/analyzer/region-model.cc | 7 +++++ > gcc/doc/invoke.texi | 16 ++++++++++++ > gcc/testsuite/gcc.dg/analyzer/fexceptions-1.c | 23 ++++++++++++++++ > gcc/testsuite/gcc.dg/analyzer/fexceptions-2.c | 26 > +++++++++++++++++++ > 6 files changed, 79 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/analyzer/fexceptions-1.c > create mode 100644 gcc/testsuite/gcc.dg/analyzer/fexceptions-2.c > > diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt > index cceee1015015..3c5dd0849c60 100644 > --- a/gcc/analyzer/analyzer.opt > +++ b/gcc/analyzer/analyzer.opt > @@ -278,6 +278,10 @@ Wanalyzer-too-complex > Common Var(warn_analyzer_too_complex) Init(0) Warning > Warn if the code is too complicated for the analyzer to fully > explore. > > +fanalyzer-assume-nothrow > +Common Var(flag_analyzer_assume_nothrow) Init(0) > +Assume that no function calls can throw exceptions. > + > fanalyzer-checker= > Common Joined RejectNegative Var(flag_analyzer_checker) > Restrict the analyzer to run just the named checker. > diff --git a/gcc/analyzer/analyzer.opt.urls > b/gcc/analyzer/analyzer.opt.urls > index 0ad321e77f57..1a698f9c6d9a 100644 > --- a/gcc/analyzer/analyzer.opt.urls > +++ b/gcc/analyzer/analyzer.opt.urls > @@ -156,6 +156,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index- > Wanalyzer-symbol-too-complex) > Wanalyzer-too-complex > UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-too- > complex) > > +fanalyzer-assume-nothrow > +UrlSuffix(gcc/Static-Analyzer-Options.html#index-fanalyzer-assume- > nothrow) > + > fanalyzer-checker= > UrlSuffix(gcc/Static-Analyzer-Options.html#index-fanalyzer-checker) > > diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region- > model.cc > index c6b22706c7b1..1efb19b07761 100644 > --- a/gcc/analyzer/region-model.cc > +++ b/gcc/analyzer/region-model.cc > @@ -2198,6 +2198,13 @@ can_throw_p (const gcall &call, tree fndecl) > if (!flag_exceptions) > return false; > > + /* Compatibility flag to allow the user to assume external > functions > + never throw exceptions. This may be useful when using the > analyzer > + on C code that is compiled with -fexceptions, but for which the > headers > + haven't yet had "nothrow" attributes systematically added. */ > + if (flag_analyzer_assume_nothrow) > + return false; > + > if (gimple_call_nothrow_p (&call)) > return false; > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index d690305a890a..cad9e993140b 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -483,6 +483,7 @@ Objective-C and Objective-C++ Dialects}. > @item Static Analyzer Options > @gccoptlist{ > -fanalyzer > +-fanalyzer-assume-nothrow > -fanalyzer-call-summaries > -fanalyzer-checker=@var{name} > -fno-analyzer-feasibility > @@ -12430,6 +12431,21 @@ The following options control the analyzer. > > @table @gcctabopt > > +@opindex fanalyzer-assume-nothrow > +@opindex fno-analyzer-assume-nothrow > +@item -fanalyzer-assume-nothrow > +By default, if @option{-fexceptions} is enabled, the analyzer will > assume > +that a call to any function without attribute @code{nothrow} could > throw > +an exception. This can help detect execution paths that leak due to > +exceptions bypassing clean-up code, but could lead to false > positives when > +using headers where the author has not added the @code{nothrow} > attribute. > + > +If @option{-fanalyzer-assume-nothrow} is enabled, then the analyzer > will > +assume that external functions do not throw exceptions. This may be > useful > +for reducing ``noise'' from the analyzer when enabling > +@option{-fexceptions} on C code, but could hide true issues if an > +exception could be raised by something the C code calls. > + > @opindex fanalyzer-call-summaries > @opindex fno-analyzer-call-summaries > @item -fanalyzer-call-summaries > diff --git a/gcc/testsuite/gcc.dg/analyzer/fexceptions-1.c > b/gcc/testsuite/gcc.dg/analyzer/fexceptions-1.c > new file mode 100644 > index 000000000000..052265d7a7d5 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/fexceptions-1.c > @@ -0,0 +1,23 @@ > +/* { dg-additional-options "-fexceptions" } */ > + > +extern void do_something (); > +extern void do_something_nothrow () __attribute__ ((nothrow)); > + > +void test () > +{ > + void *p = __builtin_malloc (1024); > + > + do_something (); /* { dg-warning "leak of 'p'" } */ > + /* { dg-message "if 'do_something' throws an exception\.\.\." > "exception event" { target *-*-* } .-1 } */ > + > + __builtin_free (p); > +} > + > +void test_nothrow () > +{ > + void *p = __builtin_malloc (1024); > + > + do_something_nothrow (); /* { dg-bogus "leak of 'p'" } */ > + > + __builtin_free (p); > +} > diff --git a/gcc/testsuite/gcc.dg/analyzer/fexceptions-2.c > b/gcc/testsuite/gcc.dg/analyzer/fexceptions-2.c > new file mode 100644 > index 000000000000..78d463c01c78 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/fexceptions-2.c > @@ -0,0 +1,26 @@ > +/* Verify that -fanalyzer-assume-nothrow suppresses warnings about > + exceptions being thrown in called function, even those not > + marked with "nothrow". */ > + > +/* { dg-additional-options "-fexceptions -fanalyzer-assume-nothrow" > } */ > + > +extern void do_something (); > +extern void do_something_nothrow () __attribute__ ((nothrow)); > + > +void test () > +{ > + void *p = __builtin_malloc (1024); > + > + do_something (); /* { dg-bogus "leak of 'p'" } */ > + > + __builtin_free (p); > +} > + > +void test_nothrow () > +{ > + void *p = __builtin_malloc (1024); > + > + do_something_nothrow (); /* { dg-bogus "leak of 'p'" } */ > + > + __builtin_free (p); > +}
