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 <dmalcolm@redhat.com>
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.
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)
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;
@item Static Analyzer Options
@gccoptlist{
-fanalyzer
+-fanalyzer-assume-nothrow
-fanalyzer-call-summaries
-fanalyzer-checker=@var{name}
-fno-analyzer-feasibility
@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
--- /dev/null
+/* { 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);
+}
--- /dev/null
+/* 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);
+}