Nullsafe C adds NULL checks to catch errors at compile-time, not runtime. It is 100% compatible with existing C codebases and can be used incrementally to identify safety issues at compile-time.
You can annotate your code with _Nonnull to presere narrowing.
Try it online: Interactive Playground - See null-safety warnings in real-time in your browser!
It does this by making two changes:
- All pointers are nullable by default, unless explicitly marked
_Nonnull. Clang already allows the code to be annotated with_Nullableand_Nonnull, but this compiler treats all unmarked pointers as nullable by default. - The compiler tracks when you've null-checked a pointer and knows it's safe to use. When you write
if (p), the type system understandspis non-null in that branch.
void unsafe(int *data) {
*data = 42; // warning - data might be null!
}
void safe(int *data) {
if (data) {
*data = 42; // OK - data is non-null here
}
}
void safe_typed(int *_Nonnull data) {
*data = 42; // OK - data is known to be non-null by the compiler
}Try it out in the Interactive Playground.
macOS:
brew install zstd
xcode-select --install # If not already installedcurl -fsSL https://raw.githubusercontent.com/cs01/llvm-project/null-safe-c-dev/install.sh | bashOr download manually from releases.
Builds not available at this time, you must clone and build locally.
Each release includes:
clang- The Null-Safe C compiler with flow-sensitive null checkingclangd- Language server for IDE integration (VSCode, vim, Neovim, Emacs, etc.)
Once installed, configure your editor to use the null-safe clangd:
VSCode:
// settings.json
{
"clangd.path": "/path/to/null-safe-clang/bin/clangd"
}Neovim/vim:
require('lspconfig').clangd.setup({
cmd = { '/path/to/null-safe-clang/bin/clangd' }
})This gives you real-time null-safety warnings as you type!
Do not that this is not a comprehensive solution, since Null pointer dereferences are just one category of memory safety bugs.
| Safety Issue | Standard C | Null-Safe Clang (null checking) |
|---|---|---|
| Null pointer dereferences | ❌ Unsafe | ✅ Fixed |
| Buffer overflows | ❌ Unsafe | ❌ Unsafe |
| Use-after-free | ❌ Unsafe | ❌ Unsafe |
| Double-free | ❌ Unsafe | ❌ Unsafe |
| Uninitialized memory | ❌ Unsafe | ❌ Unsafe |
Although this doesn't fix all memory safety issues, it catches Null pointer dereferences for free.
While Null-Safe Clang doesn't solve all memory safety issues, null pointer dereferences are a significant problem:
- Many memory safety bugs involve null pointer dereferences
- Easier to adopt than rewriting in Rust (100% compatible with existing C code)
- Complements other efforts (combine with
-fbounds-safetyfor buffer safety) - Incremental deployment (warnings by default, can enable per-file)
Basic usage (warnings enabled by default):
# Warnings for nullable dereferences
clang mycode.c
# Treat nullability issues as errors
clang -Werror=nullability mycode.c
# Turn off nullability checking
clang -fno-strict-nullability mycode.c- Nullable-by-default: All pointers are
_Nullableunless marked_Nonnull - Flow-sensitive narrowing:
if (p)provespis non-null in that scope - Early-exit patterns: Understands
return,goto,break,continue - Pointer arithmetic:
q = p + 1preserves narrowing fromp - Type checking through function calls, returns, and assignments
- Works with Typedefs
- Assumes functions have side effects (use
__attribute__((pure))or__attribute__((const))to preserve narrowing) - Null-safe headers: Annotated C standard library in
clang/nullsafe-headers/ - IDE integration:
clangdbuilt from this fork has the same logic and warnings as clang
Nullability-annotated headers for string.h, stdlib.h, and stdio.h are available in clang/nullsafe-headers/. See clang/nullsafe-headers/README.md for details.