@@ -507,6 +507,20 @@ include shared.mak
# no-pedantic:
#
# Disable -pedantic compilation.
+#
+# analyzer:
+#
+# Compile with GCC's -fanalyzer, this analysis is much more
+# expensive than other GCC warnings.
+#
+# The set of analysis flags is curated based on known issues
+# and compiler version. Known issues are made into non-fatal
+# warnings (even "no-error" isn't set).
+#
+# no-suppress-analyzer:
+#
+# When using "analyzer" disable the suppression of known
+# -fanalyzer issues.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -72,3 +72,64 @@ DEVELOPER_CFLAGS += -Wno-error=dangling-pointer
endif
GIT_TEST_PERL_FATAL_WARNINGS = YesPlease
+
+# GCC's -fanalyzer mode
+ifeq ($(filter analyzer,$(DEVOPTS)),analyzer)
+
+ifeq ($(filter gcc1,$(COMPILER_FEATURES)),)
+$(error you must be using a new-ish version of GCC for DEVOPTS=analyzer, your \
+$(CC) is not GCC at all!)
+endif
+
+DEVELOPER_CFLAGS += -fanalyzer
+
+## -fanalyzer exists exists as of gcc10, but versions older than gcc12
+## have a lot of false positives.
+ifeq ($(filter gcc12,$(COMPILER_FEATURES)),)
+DEVELOPER_CFLAGS += -Wno-analyzer-double-free
+DEVELOPER_CFLAGS += -Wno-analyzer-free-of-non-heap
+endif
+
+## Helper templates to whitelist existing issues
+define fn_disable_analyzer_tmpl
+$(1).sp $(1).s $(1).o: EXTRA_CPPFLAGS += $(2)
+
+endef
+
+define fn_disable_analyzer
+$(foreach f,$(2),$(call fn_disable_analyzer_tmpl,$(f),$(1)))
+endef
+
+## -Wno-error=analyzer-null-dereference
+$(eval $(call fn_disable_analyzer, \
+ -Wno-error=analyzer-null-dereference, \
+ range-diff \
+))
+## -Wno-error=analyzer-malloc-leak
+$(eval $(call fn_disable_analyzer, \
+ -Wno-error=analyzer-malloc-leak, \
+ fsmonitor-settings \
+))
+## per-GCC version annotations
+### -Wno-error=analyzer-use-of-uninitialized-value: gcc >= 12
+ifneq ($(filter gcc12,$(COMPILER_FEATURES)),)
+$(eval $(call fn_disable_analyzer, \
+ -Wno-error=analyzer-use-of-uninitialized-value, \
+ http-fetch \
+))
+else # gcc < 12
+### -Wno-error=analyzer-null-dereference: gcc == 11
+ifneq ($(filter gcc11,$(COMPILER_FEATURES)),)
+$(eval $(call fn_disable_analyzer, \
+ -Wno-error=analyzer-null-dereference, \
+ merge \
+ xdiff/xemit \
+ reftable/reader \
+))
+else
+$(error Your GCC version is too old for -fanalyze, or you are using \
+gcc10 which has it, but has too many false positives!)
+endif
+endif # gcc < 12
+
+endif
Add an option to compile with GCC's -fanalyzer, which as noted in [1] and [2] has become much more useful in the recently released GCC v12 series. Here we're quieting a few outstanding -fanalyzer issues that require us to use -Wno-error=* on an entire file: * range-diff.c, because it involves loop variables and would be painfully verbose to instrument with the ASSERT_FOR_FANALYZER() macro introduced in the subsequent commit. * http-fetch.c and fsmonitor-settings.c, because those aren't issues where we're referencing NULL, and therefore we can't quiet it with an assert(). For non-GCC compilers I considered wrapping the DEVOPTS logic in: ifneq ($(filter gcc10,$(COMPILER_FEATURES)),) endif Which would make it OK to specify DEVOPTS=analyzer under other compilers, or on older GCC. But then we'd silently ignore the option on those. Let's instead trust the compiler to error out if it doesn't support -fanalyzer. There are various limitations and bugs in the analyzer engine, e.g. I filed [3] for a false positive in builtin/merge-file.c before GCC v12 was released, which was subsequently fixed in GCC 12 trunk in [4], but many other issues remain. 1. https://developers.redhat.com/articles/2022/04/12/state-static-analysis-gcc-12-compiler 2. https://gcc.gnu.org/gcc-12/changes.html 3. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105264 4. https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=a358e4b60815b41e27f3508014ceb592f86b9b45 Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> --- Makefile | 14 ++++++++++++ config.mak.dev | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+)