Adding clang-tidy checks to OpenSSL
Proposal: Optional clang-tidy Support for the OpenSSL Codebase
I would like to gauge interest (beyond my own) in adding clang-tidy support to the OpenSSL codebase. clang-tidy is a static analysis and linting tool based on Clang that provides a wide range of correctness, security, performance, and readability checks.
https://clang.llvm.org/extra/clang-tidy/
In general, code flagged by linters such as clang-tidy is not necessarily incorrect. For that reason, the intent is not to introduce an overly strict or disruptive ruleset. Instead, the goal is to selectively enable checks that provide actionable feedback and are suitable for OpenSSL’s portability, performance, and security requirements.
clang-tidy is supported by many IDEs and editors, allowing contributors to receive feedback directly in their source view during development.
Summary
This proposal suggests:
Adding a .clang-tidy configuration file to the OpenSSL repository
Adding an optional CI job that runs clang-tidy with a curated set of checks
Documenting how the .clang-tidy configuration is managed and evolved
Documenting how contributors can run clang-tidy locally
Defining a clear strategy for handling false positives and suppressions
The goal is to improve code quality and maintainability incrementally, without introducing undue burden on contributors or reviewers.
Scope and enforcement philosophy
The intent is not to enforce all available clang-tidy checks.
Instead, the proposal is to:
Enable broad check families initially
-
Explicitly blacklist checks that:
currently fail extensively on the existing codebase, and/or
are considered inappropriate for OpenSSL’s coding style or design constraints
Gradually enable additional checks over time, only when accompanied by fixes in the same pull request
This avoids introducing large numbers of pre-existing violations and allows improvements to be reviewed incrementally.
Handling false positives and suppressions
clang-tidy inevitably produces false positives, particularly in macro-heavy, highly portable C code such as OpenSSL.
The proposed approach is:
Prefer configuration-level suppression via .clang-tidy over source code annotations
Use directory-local .clang-tidy files where a check is inappropriate for a specific subtree
Use // NOLINT or // NOLINTNEXTLINE comments sparingly and with justification, only when a false positive cannot reasonably be addressed through configuration
Avoid blanket suppression of entire check families unless there is broad agreement that they are unsuitable
This approach keeps the source code largely free of tool-specific annotations while still allowing practical use of clang-tidy.
Proposed ruleset strategy
Initial configuration:
-
Enable broad families:
clang-analyzer-,
bugprone-,
portability-,
performance-,
readability-,
misc-,
concurrency-,
cert-,
Explicitly disable checks that are incompatible with OpenSSL’s coding standard and/or not clearly beneficial.
The .clang-tidy file would be maintained alongside the codebase and updated as checks are enabled or disabled.
Example: running clang-tidy locally
Example workflow on macOS (requires clang-tidy, bear, and xargs):
./configmake cleanbear -- makefind ssl crypto providers test apps -name '*.c' \ | xargs -P$(sysctl -n hw.ncpu) -n1 \ clang-tidy -p . \ > clang-tidy.out 2>&1Results from a local run
I ran clang-tidy on OpenSSL master (commit: 0755a8ef905800ebc4ee022f880119f3e67b64bc) on macOS, using the ruleset described above.
The following checks produced findings that may be worth considering for future enforcement:
bugprone-implicit-widening-of-multiplication-resultbugprone-macro-parenthesesbugprone-misplaced-widening-castbugprone-narrowing-conversionsbugprone-suspicious-string-comparebugprone-switch-missing-default-casebugprone-too-small-loop-variablecert-err34-cclang-analyzer-deadcode.DeadStoresclang-analyzer-security.ArrayBoundconcurrency-mt-unsafemisc-unused-parametersperformance-no-int-to-ptrreadability-avoid-nested-conditional-operatorreadability-avoid-unconditional-preprocessor-ifreadability-duplicate-includereadability-inconsistent-declaration-parameter-namereadability-magic-numbersreadability-misleading-indentationreadability-non-const-parameterreadability-redundant-castingreadability-redundant-control-flowreadability-redundant-declarationreadability-redundant-preprocessorNot all of these are necessarily appropriate to enforce, but they serve as a starting point for discussion.
Frederik Wedel-Heinen Thu 8 Jan 2026 6:38PM
Here's a PR of your proposed first step :) https://github.com/openssl/openssl/pull/29580
Neil Horman · Fri 2 Jan 2026 2:43PM
Generally speaking, I'd be in favor of something like this, though I think we need to be very careful here how we go about it.
A few notes:
1) clang-tidy doesn't understand our template files (i.e. our perl-ified .in and .inc files). As such it seems we need to be careful to only run this linting on built trees, so we don't run afoul of any diagnostic errors for type definitions we define in generated headers.
2) We will want to be very careful about what lint checks we are willing to enable. for instance, running with only the concurrency-mt-unsafe check on my local tree reports about 150 errors indicating usafe mutithread usage, mostly centering around the getenv, strerror, and exit functions, all of which are defined in posix as MT-SAFE, so there some question in my mind as to what clang-tidy is trying to get us to do there, and what our expectations are.
3) For checks we are willing to enable, we should ensure that any enablement is only done after a run of tidy produces no errors/warnings against that check. Some of these even trivial checks above produce 1000's of errors, and I would hate to enable something like this only to have it ignored because its too much of a lift for people with follow on patches to have to clean up the mess.
I'd be in favor of doing something like:
1) Create a ci job to run clang-tidy on the source tree as part of a pull request
2) Check in a .clang-tidy file that enables 0 checks (i.e. the trivial case)
3) Create a long running issue for anyone interested to scrub the tree of various errors and enable the corresponding check.
It might make for a series of "good first issue", work efforts to expose people to the source tree, but doing broad based tree-wide cleanups.