Note: this guide is valid for Clang 12
Clang compiler flags are described by a domain specific language call
TableGen, and LLVM includes a tool
called llvm-tblgen
which parses the definition files, DiagnosticsGroups.td
in particular.
While Clang thankfully provides a -Weverything
option which enables all
warnings, it is strongly recommended by Clang developpers not to use it in production...
However, they (and I) recommend using -Weverything
to identify warnings which
are relevant for your code base and then selectively add them to your standard
warning list.
Clang supports the following warnings which are compatible with GCC:
- the obvious
-Wall
,-Wextra
,-Wpedantic
and-Werror
(Note). -Walloca
,-Wcast-qual
,-Wconversion
,-Wformat=2
,-Wformat-security
,-Wnull-dereference
,-Wstack-protector
,-Wvla
.
Some other warnings are of interest for security:
-Wconversion
: which enables a lot of warnings related to implicit conversions, with some which are particularly interesting:-Wshorten-64-to-32
: warn on 64 bits truncation (size_t
toint
on 64bits Linux for example).
-Warray-bounds
: which does not take an argument, contrary to GCC (enabled by default).-Warray-bounds-pointer-arithmetic
: a more advanced version which takes pointer arithmetic into account.-Wimplicit-fallthrough
: does not take an argument. Note that Clang does not parse comments and only supports[[clang::fallthrough]]
and__attribute__((fallthrough))
annotations.-Wconditional-uninitialized
: warn if a variable may be uninitialized depending on a conditional branch.-Wloop-analysis
: warn about loop variable misuse (double increment, etc.).-Wshift-sign-overflow
: warn when left shift overflows into sign bit.-Wswitch-enum
: warn when a switch statement does not handle all enum values.-Wtautological-constant-in-range-compare
: warn about comparisons which are alwaystrue
orfalse
due to the variables value ranges. Ex:comparison of unsigned expression < 0 is always false
.-Wcomma
: warn about possible comma misuse.-Wassign-enum
: integer constant not in range of enumerated type A.-Wbad-function-cast
: cast from function call of type A to non-matching type B.-Wfloat-equal
: comparing floating point with == or != is unsafe.-Wformat-type-confusion
: format specifies type A but the argument has type B.-Wpointer-arith
: various warnings related to pointer arithmetic.-Widiomatic-parentheses
: using the result of an assignment as a condition without parentheses.-Wunreachable-code-aggressive
: warn about unreachable code.-Wthread-safety
and-Wthread-safety-beta
: warn about potential threading/race condition issues.
Note: You can disable warnings for system includes by using the -isystem
option to specify the paths which will be used for "system" includes (#include <file.h>
).
Clang supports various options for stack based buffer overflow protection and mitigations against control flow attacks:
-fstack-protector-strong
(or-fstack-protector-all)
: enable stack cookies.-fsanitize=safe-stack
: use two stacks ("safe" and "unsafe"), should not impact performance and can be combined with-fstack-protector
Doc, Research.-fsanitize=shadow-call-stack
: stronger protection which specific arch support (currently onlyAarch64
). Doc.-fcf-protection=full|return|branch
: Generate code for Intel CET.-fsanitize=cfi
: ControlFlowIntegrity. Doc.
Other compilation flags:
-
-fPIE
: generate position-independent code (needed for ASLR). -
-fstack-clash-protection
: Insert code to probe each page of stack space as it is allocated to protect from stack-clash style attacks. -
-ftrivial-auto-var-init=pattern
: Auto initialize variables with a random pattern, which can be costly in some cases.=zero
option is only supported with-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
. -
Glibc flags: see GCC page
-
Linker flags: see GCC page
LLVM support of sanitizers is first class, besides AddressSanitizer
, ThreadSanitizer
, LeakSanitizer
and UndefinedBehaviorSanitizer
, which are included in GCC, the following are available:
-fsanitize=memory
: MemorySanitizer is a detector of uninitialized reads.-fsanitize=integer
: advanced analysis of undefined or risky integer behavior using UBSan. Note that this enables detection of legit (per the C langage spec) detection of unsigned integer overflows. Instrumentation can be disabled on functions where overflowing is expected by using__attribute__((no_sanitize("unsigned-integer-overflow")))
. Ditto withunsigned-shift-base
.
Runtime sanitizers are particularly useful when:
- running test suites,
- fuzzing code,
as they may uncover runtime errors which would not necessarily trigger a crash.
While most sanitizers are not intended to be used in production builds, UBSan integer's checker is very interesting, as it will detect integer overflows and abort the program.
The code should be compiled with -fsanitize=integer -fsanitize-minimal-runtime -fno-sanitize-recover
. The performance impact should be reasonable on modern CPUs (~1%). Android enables it in production builds for some libraries.
Clang has a "modern" static analyzer which can be used to analyze whole projects and produce HTML reports of the potential problems identified by the tool.
"It implements path-sensitive, inter-procedural analysis based on symbolic execution technique."
scan-build
is simple to use and can wrap compilation tools such as make
. It
will replace the CC
and CXX
environment variables to analyze your build and produce
the report.
$ scan-build make
The default checkers
are relatively few, and do not really target security, however, "alpha" (which may have many false positives) checkers related to security can be enabled by using the -enable-checker alpha.security
CLI option.
Other interesting checkers:
alpha.core.CastSize
alpha.core.CastToStruct
alpha.core.Conversion
(it is relevant when-Wconversion
is enabled ?)alpha.core.IdenticalExpr
alpha.core.PointerArithm
alpha.core.PointerSub
alpha.core.SizeofPtr
alpha.core.TestAfterDivZero
alpha.unix
, which has a bunch of useful checks
DataFlowSanitizer
can be used to develop your own, application specific, code analyzer.
While fuzzing is out of scope, you should fuzz your code with sanitizers enabled. Options include:
Test files are a great way to understand in detail what is and what is not covered by a specific command line flag.
They are located in the clang/test
directory. For example, the test for -Wshift-count-negative
can be found in clang/test/Sema/warn-shift-negative.c
:
// RUN: %clang_cc1 -fsyntax-only -Wshift-count-negative -fblocks -verify %s
int f(int a) {
const int i = -1;
return a << i; // expected-warning{{shift count is negative}}
}
- https://releases.llvm.org/12.0.0/tools/clang/docs/DiagnosticsReference.html: All Clang warnings listed and "documented".
- https://releases.llvm.org/12.0.0/tools/clang/docs/index.html: Clang documentation
- https://copperhead.co/blog/memory-disclosure-mitigations/: Uses of sanitizers and hardening options in Android CopperheadOs
- https://source.android.com/devices/tech/debug/intsan: Android use of UBSan in production builds to mitigate integer overflows.
- https://security.googleblog.com/2019/05/queue-hardening-enhancements.html: Information about other hardening options in Android
- https://clang-analyzer.llvm.org/: Doc for
scan-build
- https://lld.llvm.org/: The LLVM linker documentation.
- https://blog.quarkslab.com/clang-hardening-cheat-sheet.html: Quarkslab recommnendations for Clang hardening flags.