From: David Malcolm Date: Tue, 27 Jan 2026 21:36:29 +0000 (-0500) Subject: analyzer: add option -fanalyzer-assume-nothrow [PR122623] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1318516f07453e87814f6246acf567f684ac34f;p=thirdparty%2Fgcc.git analyzer: add option -fanalyzer-assume-nothrow [PR122623] 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. 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 --- diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index cceee101501..3c5dd0849c6 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 0ad321e77f5..1a698f9c6d9 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 c6b22706c7b..1efb19b0776 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 87c0470c3db..8234133131f 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 @@ -12501,6 +12502,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 00000000000..052265d7a7d --- /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 00000000000..78d463c01c7 --- /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); +}