diff --git a/.clang-tidy.yml b/.clang-tidy.yml new file mode 100644 index 0000000000..751ffcef52 --- /dev/null +++ b/.clang-tidy.yml @@ -0,0 +1,16 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl +--- +# https://clang.llvm.org/extra/clang-tidy/checks/list.html + +# -clang-analyzer-security.insecureAPI.bzero: for FD_ZERO() (seen on macOS) +# -clang-analyzer-security.ArrayBound: due to false positives with clang-tidy v21.1.0 +Checks: >- + -clang-analyzer-security.insecureAPI.bzero, + -clang-analyzer-optin.performance.Padding, + -clang-analyzer-security.ArrayBound, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -clang-diagnostic-nullability-extension, + misc-const-correctness, + portability-* diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1bf8aee317..d3cbc8038f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -33,7 +33,6 @@ env: MAKEFLAGS: -j 5 CURL_CI: github CURL_TEST_MIN: 1600 - CURL_CLANG_TIDYFLAGS: '-checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-clang-analyzer-valist.Uninitialized' # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.2.1 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com @@ -277,13 +276,15 @@ jobs: -DCURL_DISABLE_LDAP=ON -DUSE_LIBIDN2=OFF -DCURL_USE_LIBSSH2=OFF - name: 'clang-tidy' - install_packages: clang-tidy libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_packages: clang-19 clang-tidy-19 libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev install_steps: skipall mbedtls-latest-intel rustls wolfssl-opensslextra-intel install_steps_brew: gsasl make-custom-target: tidy LDFLAGS: -Wl,-rpath,/home/runner/wolfssl-opensslextra/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/gsasl/lib PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/gsasl/lib/pkgconfig + CC: clang-19 configure: >- + CLANG_TIDY=clang-tidy-19 --with-wolfssl=/home/runner/wolfssl-opensslextra --with-openssl --with-rustls --with-mbedtls=/home/runner/mbedtls --with-gnutls --with-libgsasl --with-librtmp --with-libssh2 --with-libidn2 --enable-ech --with-gssapi --enable-ssls-export --disable-typecheck diff --git a/CMake/Macros.cmake b/CMake/Macros.cmake index ca6330184d..acc4e26f66 100644 --- a/CMake/Macros.cmake +++ b/CMake/Macros.cmake @@ -115,6 +115,10 @@ macro(curl_collect_target_options _target) if(_val) list(APPEND _definitions ${_val}) endif() + get_target_property(_val ${_target} COMPILE_OPTIONS) + if(_val) + list(APPEND _options ${_val}) + endif() get_target_property(_val ${_target} LINK_LIBRARIES) if(_val) foreach(_lib IN LISTS _val) @@ -132,6 +136,7 @@ macro(curl_add_clang_tidy_test_target _target_clang_tidy _target) set(_includes "") set(_definitions "") + set(_options "") # Collect header directories and macro definitions applying to the directory get_directory_property(_val INCLUDE_DIRECTORIES) @@ -142,13 +147,24 @@ macro(curl_add_clang_tidy_test_target _target_clang_tidy _target) if(_val) list(APPEND _definitions ${_val}) endif() + get_directory_property(_val COMPILE_OPTIONS) + if(_val) + list(APPEND _options ${_val}) + endif() unset(_val) # Collect header directories and macro definitions from lib dependencies curl_collect_target_options(${_target}) - list(REMOVE_ITEM _includes "") - string(REPLACE ";" ";-I" _includes ";${_includes}") + set(_includes_tmp ${_includes}) + set(_includes) + foreach(_inc IN LISTS _includes_tmp) + # Avoid empty and '$' items. The latter also + # evaluates to an empty path in this context. + if(_inc AND NOT _inc MATCHES "INSTALL_INTERFACE:") + list(APPEND _includes "-I${_inc}") + endif() + endforeach() list(REMOVE_DUPLICATES _includes) list(REMOVE_ITEM _definitions "") @@ -156,6 +172,12 @@ macro(curl_add_clang_tidy_test_target _target_clang_tidy _target) list(REMOVE_DUPLICATES _definitions) list(SORT _definitions) # Sort like CMake does + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + list(REMOVE_DUPLICATES _options) # Keep the first of duplicates to imitate CMake + else() + set(_options) + endif() + # Assemble source list set(_sources "") foreach(_source IN ITEMS ${ARGN}) @@ -165,14 +187,18 @@ macro(curl_add_clang_tidy_test_target _target_clang_tidy _target) list(APPEND _sources "${_source}") endforeach() + # Pass -clang-diagnostic-unused-function to disable -Wunused-function implied by -Wunused add_custom_target(${_target_clang_tidy} USES_TERMINAL WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMAND ${CMAKE_C_CLANG_TIDY} ${_sources} -- ${_includes} ${_definitions} + COMMAND ${CMAKE_C_CLANG_TIDY} + "--checks=-clang-diagnostic-unused-function" + ${_sources} -- ${_includes} ${_definitions} ${_options} DEPENDS ${_sources}) add_dependencies(tests-clang-tidy ${_target_clang_tidy}) unset(_includes) unset(_definitions) + unset(_options) unset(_sources) endif() endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 60e0e40a5c..23e1099874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,8 +251,6 @@ if(NOT DOS AND NOT AMIGA) option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup" ${_enable_threaded_resolver_default}) endif() -include(PickyWarnings) - if(CYGWIN OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "GNU") set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "_GNU_SOURCE") # Required for accept4(), pipe2(), sendmmsg() list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") # Apply to all feature checks @@ -270,22 +268,21 @@ endif() option(CURL_CLANG_TIDY "Run the build through clang-tidy" OFF) if(CURL_CLANG_TIDY) + find_program(CLANG_TIDY NAMES "clang-tidy" REQUIRED) + if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + set(PICKY_COMPILER OFF) # Do a best effort and skip passing non-clang warning options to clang-tidy. + # This lets through warning options enabled via CURL_WERROR=ON, affecting lib and src. + endif() set(CMAKE_UNITY_BUILD OFF) # clang-tidy is not looking into #included sources, thus not compatible with unity builds. set(CURL_DISABLE_TYPECHECK ON) # to improve performance and avoid potential interference. - set(_tidy_checks "") - list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.bzero") # for FD_ZERO() (seen on macOS) - list(APPEND _tidy_checks "-clang-analyzer-optin.performance.Padding") - list(APPEND _tidy_checks "-clang-analyzer-security.ArrayBound") # false positives with clang-tidy v21.1.0 - list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling") - string(REPLACE ";" "," _tidy_checks "${_tidy_checks}") - find_program(CLANG_TIDY NAMES "clang-tidy" REQUIRED) - set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY}" "-checks=${_tidy_checks}" "-quiet") - unset(_tidy_checks) + set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY}") + list(APPEND CMAKE_C_CLANG_TIDY "--config-file=${PROJECT_SOURCE_DIR}/.clang-tidy.yml") if(CURL_WERROR) list(APPEND CMAKE_C_CLANG_TIDY "--warnings-as-errors=*") endif() if(CURL_CLANG_TIDYFLAGS) - list(APPEND CMAKE_C_CLANG_TIDY ${CURL_CLANG_TIDYFLAGS}) + string(REPLACE " " ";" _tidy_flags_list "${CURL_CLANG_TIDYFLAGS}") + list(APPEND CMAKE_C_CLANG_TIDY ${_tidy_flags_list}) endif() endif() @@ -309,6 +306,8 @@ if(CURL_CODE_COVERAGE) endif() endif() +include(PickyWarnings) + set(CURL_CFLAGS "") # C flags set for libcurl and curl tool (aka public binaries) only option(CURL_DROP_UNUSED "Drop unused code and data from built binaries" OFF) diff --git a/Makefile.am b/Makefile.am index 605215060b..381ec987f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,7 +64,7 @@ CMAKE_DIST = \ tests/cmake/test.c \ tests/cmake/test.sh -EXTRA_DIST = CHANGES.md COPYING RELEASE-NOTES Dockerfile .editorconfig $(CMAKE_DIST) +EXTRA_DIST = CHANGES.md COPYING RELEASE-NOTES Dockerfile .clang-tidy.yml .editorconfig $(CMAKE_DIST) DISTCLEANFILES = buildinfo.txt diff --git a/configure.ac b/configure.ac index ef143acf13..091424cf2e 100644 --- a/configure.ac +++ b/configure.ac @@ -120,6 +120,11 @@ AC_SUBST([AR]) AC_SUBST(libext) +if test -z "$CLANG_TIDY"; then + CLANG_TIDY=clang-tidy +fi +AC_SUBST(CLANG_TIDY) + dnl figure out the libcurl version CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/include/curl/curlver.h` XC_CHECK_PROG_CC @@ -681,6 +686,8 @@ case $host_os in ;; esac +AM_CONDITIONAL(CLANG, test "$compiler_id" = "APPLECLANG" || test "$compiler_id" = "CLANG") + dnl ********************************************************************** dnl Compilation based checks should not be done before this point. dnl ********************************************************************** diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 41d0387473..5d77d4306b 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -49,6 +49,7 @@ When writing code (mostly for generating stuff included in release tarballs) we use a few "build tools" and we make sure that we remain functional with these versions: +- clang-tidy 14.0.0 (2022-03-23), recommended: 19.1.0 or later (2024-09-17) - cmake 3.7 (2016-11-11) - GNU autoconf 2.59 (2003-11-06) - GNU automake 1.7 (2002-09-25) diff --git a/lib/Makefile.am b/lib/Makefile.am index 3887fd8a26..41db1a21ac 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -163,17 +163,18 @@ UNITV_ = $(UNITV_0) $(UNITPROTOS): $(CSOURCES) $(UNIT_V)(cd $(srcdir) && @PERL@ ../scripts/extract-unit-protos $(CSOURCES)) > $(top_builddir)/lib/$(UNITPROTOS) -# disable the tests that are mostly causing false positives -TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet +_tidy_cflags := +TIDYFLAGS := if CURL_WERROR -TIDYFLAGS += --warnings-as-errors=* +TIDYFLAGS += '--warnings-as-errors=*' +endif +if CLANG +_tidy_cflags += $(CFLAGS) endif - -TIDY := clang-tidy tidy: (_csources=`echo ' $(CSOURCES)' | sed -E -e 's/ +$$//' -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \ - $(TIDY) $$_csources $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H) + @CLANG_TIDY@ --config-file=$(top_srcdir)/.clang-tidy.yml $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) $$_csources -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H $(_tidy_cflags)) optiontable: @PERL@ $(srcdir)/optiontable.pl < $(top_srcdir)/include/curl/curl.h > $(srcdir)/easyoptions.c diff --git a/src/Makefile.am b/src/Makefile.am index 50d282f651..96e9401a38 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -215,17 +215,18 @@ all-local: checksrc endif endif -# disable the tests that are mostly causing false positives -TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet +_tidy_cflags := +TIDYFLAGS = if CURL_WERROR -TIDYFLAGS += --warnings-as-errors=* +TIDYFLAGS += '--warnings-as-errors=*' +endif +if CLANG +_tidy_cflags += $(CFLAGS) endif - -TIDY := clang-tidy tidy: $(HUGE) $(CA_EMBED_CSOURCE) (_curl_cfiles=`echo ' $(CURL_CFILES)' | sed -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \ - $(TIDY) $$_curl_cfiles $(curl_cfiles_gen) $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) -DHAVE_CONFIG_H) + @CLANG_TIDY@ --config-file=$(top_srcdir)/.clang-tidy.yml $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) $$_curl_cfiles $(curl_cfiles_gen) -- $(curl_CPPFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) -DHAVE_CONFIG_H $(_tidy_cflags)) listhelp: (cd $(top_srcdir)/docs/cmdline-opts && make listhelp) diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c index b36d113232..01594644fb 100644 --- a/src/tool_parsecfg.c +++ b/src/tool_parsecfg.c @@ -253,6 +253,8 @@ ParameterError parseconfig(const char *filename, int max_recursive, curlx_dyn_free(&pbuf); if(file != stdin) curlx_fclose(file); + /* Silence false positive about failing to close stdin. + NOLINTNEXTLINE(clang-analyzer-unix.Stream) */ if(fileerror) err = PARAM_READ_ERROR; }