https://gcc.gnu.org/g:f1318516f07453e87814f6246acf567f684ac34f

commit r16-7080-gf1318516f07453e87814f6246acf567f684ac34f
Author: David Malcolm <[email protected]>
Date:   Tue Jan 27 16:36:29 2026 -0500

    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 <[email protected]>

Diff:
---
 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(+)

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 87c0470c3dbc..8234133131f5 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 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);
+}

Reply via email to