Skip to content

Commit 18a141e

Browse files
committed
Simplify install instructions and remove emojis from install script
1 parent 804da69 commit 18a141e

File tree

3 files changed

+51
-146
lines changed

3 files changed

+51
-146
lines changed

README.md

Lines changed: 31 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,48 @@
1-
# Null-Safe Clang: An experimental C/C++ compiler
1+
# Nullsafe C: An experimental C/C++ compiler
22

33
[![Test Null-Safety](https://github.com/cs01/llvm-project/actions/workflows/test-null-safety.yml/badge.svg)](https://github.com/cs01/llvm-project/actions/workflows/test-null-safety.yml)
44

5-
An experimental Clang fork that adds flow-sensitive null safety to C and C++, inspired by modern languages like TypeScript, Kotlin, and Rust.
5+
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.
66

7-
**Try it online:** [Interactive Playground](https://cs01.github.io/llvm-project/) - See null-safety warnings in real-time in your browser!
8-
9-
## What This Adds
10-
11-
This compiler adds two key features to prevent null pointer crashes:
7+
You can annotate your code with `_Nonnull` to presere narrowing.
128

13-
1. Nullable-by-default pointers - All pointers are assumed nullable unless explicitly marked `_Nonnull`
14-
2. Type narrowing - The compiler tracks when you've null-checked a pointer and knows it's safe to use
9+
**Try it online:** [Interactive Playground](https://cs01.github.io/llvm-project/) - See null-safety warnings in real-time in your browser!
1510

16-
In standard C/C++, pointers have no nullability information and the compiler can't tell if a pointer might be null. This compiler treats all unmarked pointers as nullable by default and uses flow-sensitive analysis to track null checks. When you write `if (p)`, the type system understands `p` is non-null in that branch, just like TypeScript, Kotlin, and Rust. This catches null pointer dereferences at compile time instead of crashing at runtime.
11+
It does this by making two changes:
12+
1. All pointers are nullable by default, unless explicitly marked `_Nonnull`. Clang already allows the code to be annotated with `_Nullable` and `_Nonnull`, but this compiler treats all unmarked pointers as nullable by default.
13+
2. 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 understands `p` is non-null in that branch.
1714

1815
## Example
1916

2017
```c
21-
void process(int* data) {
22-
if (data) {
23-
*data = 42; // ✓ OK - strict nullability knows data is non-null here
24-
}
18+
void unsafe(int *data) {
19+
*data = 42; // warning - data might be null!
2520
}
2621

27-
void unsafe(int* data) {
28-
*data = 42; // ⚠️ Warning - data might be null!
22+
void safe(int *data) {
23+
if (data) {
24+
*data = 42; // OK - data is non-null here
25+
}
2926
}
30-
```
31-
32-
Standard Clang/GCC: Both functions compile without warnings.
33-
This fork: The `unsafe` function warns you about the potential null dereference.
3427

35-
This experimental fork of Clang adds flow-sensitive nullability analysis while remaining 100% compatible with standard C. It includes all of Clang's features plus enhanced nullability checking in both the compiler and the `clangd` language server.
28+
void safe_typed(int *_Nonnull data) {
29+
*data = 42; // OK - data is known to be non-null by the compiler
30+
}
3631

37-
By default, strict nullability is enabled and issues warnings. You can promote warnings to errors with `-Werror=nullability`, or disable the feature entirely with `-fno-strict-nullability`.
32+
```
33+
Try it out in the [Interactive Playground](https://cs01.github.io/llvm-project/).
3834
3935
## Installation
4036
41-
### Quick Install (Linux/macOS)
42-
43-
Download and extract the latest release for your platform:
44-
4537
```bash
46-
# Auto-detect your platform and install
4738
curl -fsSL https://raw.githubusercontent.com/cs01/llvm-project/null-safe-c-dev/install.sh | sh
48-
49-
# Or manually download:
50-
# Linux x86_64:
51-
curl -L https://github.com/cs01/llvm-project/releases/latest/download/clang-nullsafe-linux-x86_64.tar.gz | tar xz
52-
53-
# macOS (Intel/Apple Silicon):
54-
curl -L https://github.com/cs01/llvm-project/releases/latest/download/clang-nullsafe-macos-universal.tar.gz | tar xz
55-
56-
# Add to PATH
57-
export PATH="$PWD/bin:$PATH"
58-
clang --version
5939
```
6040

41+
Or download manually from [releases](https://github.com/cs01/llvm-project/releases/latest).
42+
6143
### Windows
6244

63-
Download the Windows release:
64-
```bash
65-
curl -L https://github.com/cs01/llvm-project/releases/latest/download/clang-nullsafe-windows-x86_64.tar.gz -o clang-nullsafe.tar.gz
66-
tar -xzf clang-nullsafe.tar.gz
67-
# Add bin\ directory to your PATH
68-
clang --version
69-
```
45+
Download and extract from [releases](https://github.com/cs01/llvm-project/releases/latest), then add the `bin` directory to your PATH.
7046

7147
### What's Included
7248

@@ -95,12 +71,9 @@ require('lspconfig').clangd.setup({
9571

9672
This gives you real-time null-safety warnings as you type!
9773

74+
## Memory Safety
9875

99-
## Memory Safety in General
100-
101-
Null pointer dereferences are just one category of memory safety bugs. Here's how different approaches compare:
102-
103-
### What Gets Fixed
76+
Do not that this is not a comprehensive solution, since Null pointer dereferences are just one category of memory safety bugs.
10477

10578
| Safety Issue | Standard C | **Null-Safe Clang** (null checking) |
10679
|-------------------------|------------|:-----------------------------------:|
@@ -110,6 +83,7 @@ Null pointer dereferences are just one category of memory safety bugs. Here's ho
11083
| Double-free | ❌ Unsafe | ❌ Unsafe |
11184
| Uninitialized memory | ❌ Unsafe | ❌ Unsafe |
11285

86+
Although this doesn't fix all memory safety issues, it catches Null pointer dereferences for free.
11387

11488
### Why you still might want to try this
11589

@@ -125,22 +99,14 @@ While Null-Safe Clang doesn't solve all memory safety issues, null pointer deref
12599

126100
Basic usage (warnings enabled by default):
127101
```bash
128-
clang mycode.c # Warnings for nullable dereferences
129-
clang -Werror=nullability mycode.c # Treat nullability issues as errors
130-
clang -fno-strict-nullability mycode.c # Turn off nullability checking
102+
# Warnings for nullable dereferences
103+
clang mycode.c
104+
# Treat nullability issues as errors
105+
clang -Werror=nullability mycode.c
106+
# Turn off nullability checking
107+
clang -fno-strict-nullability mycode.c
131108
```
132109

133-
Gradual adoption (per-file or per-function):
134-
```c
135-
// Disable warnings for specific files
136-
#pragma clang diagnostic ignored "-Wnullability"
137-
138-
// Or per-function
139-
#pragma clang diagnostic push
140-
#pragma clang diagnostic ignored "-Wnullability"
141-
void legacy_function(int* p) { ... }
142-
#pragma clang diagnostic pop
143-
```
144110

145111
## Features
146112

@@ -154,70 +120,6 @@ void legacy_function(int* p) { ... }
154120
- Null-safe headers: Annotated C standard library in `clang/nullsafe-headers/`
155121
- IDE integration: `clangd` built from this fork has the same logic and warnings as clang
156122

157-
## How It Works
158-
159-
Strict nullability adds flow-sensitive analysis to Clang's semantic analyzer. When you write `if (p)`, the compiler tracks that `p` is non-null within that branch—just like TypeScript, Swift, or Kotlin do. The difference is we add this to C without changing the language itself.
160-
161-
### Function Call Invalidation
162-
163-
By default, function calls invalidate narrowing because they may have side effects:
164-
165-
```c
166-
void some_function(void);
167-
168-
void example(int* p) {
169-
if (p) {
170-
*p = 1; // OK - p is narrowed to non-null
171-
some_function(); // Invalidates narrowing
172-
*p = 2; // Warning: p is nullable again
173-
}
174-
}
175-
```
176-
177-
This is conservative but safe—functions can modify global state or escaped pointers.
178-
179-
Preserve narrowing with pure functions:
180-
181-
Mark side-effect-free functions with `__attribute__((pure))` or `__attribute__((const))`:
182-
183-
```c
184-
int tolower(int c) __attribute__((const)); // No side effects
185-
186-
void example(char* p) {
187-
if (p) {
188-
tolower(*p); // Pure function - doesn't invalidate
189-
*p = 'x'; // OK - p is still narrowed
190-
}
191-
}
192-
```
193-
194-
The difference:
195-
- `__attribute__((const))`: Only uses its arguments (e.g., `tolower`, `abs`)
196-
- `__attribute__((pure))`: May read globals but doesn't modify anything (e.g., `strlen`)
197-
198-
Many standard library functions already have these attributes in GNU libc headers, so strict nullability automatically recognizes them.
199-
200123
## Null-Safe C Standard Library
201124

202-
Nullability-annotated headers for `string.h`, `stdlib.h`, and `stdio.h` are available in `clang/nullsafe-headers/`. These tell the compiler which functions return nullable pointers and which parameters must be non-null.
203-
204-
```bash
205-
# Compile with null-safe headers
206-
clang -Iclang/nullsafe-headers/include mycode.c
207-
```
208-
209-
```c
210-
#include "string.h"
211-
#include "stdlib.h"
212-
213-
void example(const char* input) {
214-
if (!input) return;
215-
char* copy = malloc(strlen(input) + 1); // malloc returns _Nullable
216-
if (copy) {
217-
strcpy(copy, input); // Both parameters narrowed to non-null
218-
free(copy);
219-
}
220-
}
221-
```
222-
223-
See [`clang/nullsafe-headers/README.md`](clang/nullsafe-headers/README.md) for details.
125+
Nullability-annotated headers for `string.h`, `stdlib.h`, and `stdio.h` are available in `clang/nullsafe-headers/`. See [`clang/nullsafe-headers/README.md`](clang/nullsafe-headers/README.md) for details.

install.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ set -e
77
REPO="cs01/llvm-project"
88
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/null-safe-clang}"
99

10-
echo "🔍 Detecting platform..."
10+
echo "Detecting platform..."
1111
OS=$(uname -s)
1212
ARCH=$(uname -m)
1313

1414
# Determine the correct release file
1515
if [ "$OS" = "Linux" ] && [ "$ARCH" = "x86_64" ]; then
1616
RELEASE_FILE="clang-nullsafe-linux-x86_64.tar.gz"
17-
echo "Detected: Linux x86_64"
17+
echo "Detected: Linux x86_64"
1818
elif [ "$OS" = "Darwin" ]; then
1919
RELEASE_FILE="clang-nullsafe-macos-universal.tar.gz"
20-
echo "Detected: macOS (Universal)"
20+
echo "Detected: macOS (Universal)"
2121
else
22-
echo "Unsupported platform: $OS $ARCH"
22+
echo "Unsupported platform: $OS $ARCH"
2323
echo "Please download manually from:"
2424
echo "https://github.com/$REPO/releases/latest"
2525
exit 1
@@ -28,7 +28,7 @@ fi
2828
# Download URL
2929
URL="https://github.com/$REPO/releases/latest/download/$RELEASE_FILE"
3030

31-
echo "📦 Downloading Null-Safe Clang..."
31+
echo "Downloading Null-Safe Clang..."
3232
echo " $URL"
3333

3434
# Create install directory
@@ -41,13 +41,13 @@ if command -v curl >/dev/null 2>&1; then
4141
elif command -v wget >/dev/null 2>&1; then
4242
wget -O - "$URL" | tar xz --strip-components=0
4343
else
44-
echo "Neither curl nor wget found. Please install one of them."
44+
echo "Neither curl nor wget found. Please install one of them."
4545
exit 1
4646
fi
4747

48-
echo "Installed to: $INSTALL_DIR"
48+
echo "Installed to: $INSTALL_DIR"
4949
echo ""
50-
echo "📝 To use Null-Safe Clang, add this to your shell profile (~/.bashrc, ~/.zshrc, etc.):"
50+
echo "To use Null-Safe Clang, add this to your shell profile (~/.bashrc, ~/.zshrc, etc.):"
5151
echo ""
5252
echo " export PATH=\"$INSTALL_DIR/bin:\$PATH\""
5353
echo ""
@@ -61,5 +61,5 @@ echo ""
6161
echo "Try it out:"
6262
echo " echo 'void f(int* p) { *p = 42; }' | clang -x c - -fsyntax-only"
6363
echo ""
64-
echo "🎮 Try the interactive playground:"
64+
echo "Try the interactive playground:"
6565
echo " https://cs01.github.io/llvm-project/"
Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
// Flow-sensitive null checking catches bugs at compile-time
2-
void safe(int* data) {
3-
if (data) {
4-
*data = 42; // OK - data is non-null here
5-
}
1+
void unsafe(int *data) {
2+
*data = 42; // warning - data might be null!
63
}
74

8-
void unsafe(int* data) {
9-
*data = 42; // warning - data might be null!
10-
}
5+
void safe(int *data) {
6+
if (data) {
7+
*data = 42; // OK - data is non-null here
8+
}
9+
}
10+
11+
void safe_typed(int *_Nonnull data) {
12+
*data = 42; // OK - data is known to be non-null by the compiler
13+
}

0 commit comments

Comments
 (0)