Safer C.
No rewrite required.

Drop into any codebase today. Your existing C compiles unchanged —
Prism adds defer, orelse, and zero-initialization on top.

prism run main.c
version
v1.1.4
tests
6,035
stars
4
commits
638
deps
0
license
Apache 2.0
defer

Cleanup that can't be forgotten.

Bound to scope, not to every exit path. Runs in reverse order at scope end — whether you return early, fall through, or hit an error branch.

−18lines avg
3bug classes closed
Before
FILE *f = fopen(path, "r");
if (!f) return -1;

int r = parse(f);
if (r < 0) {
    fclose(f); // easy to forget
    return -1;
}

fclose(f);
return r;
After
FILE *f = fopen(path, "r")
    orelse return -1;
defer fclose(f);

return parse(f);
Before
char *buf = malloc(n);
if (buf == NULL) {
    log_error("OOM");
    return -1;
}
// ... 20 more lines
After
char *buf = malloc(n)
    orelse return -1;
orelse

Inline error handling without the noise.

Checks any falsy scalar — null pointer, zero integer, zero return code — inline. No nested if-blocks, no repeated cleanup calls, no diverging error paths. Works with return, break, continue, goto, or a fallback value.

−12lines avg
2bug classes closed
zero-init

No garbage values. Ever.

Every local variable is automatically zeroed at declaration — scalars, pointers, arrays, structs. The entire class of bugs from uninitialized reads is simply closed.

less undefined behavior
1bug class closed
Before
typedef struct {
    int width;
    int height;
    int flags; // garbage
} Config;

Config cfg; // uninitialized
if (cfg.flags & VERBOSE) {
    // undefined behavior
}
After
typedef struct {
    int width;
    int height;
    int flags;
} Config;

Config cfg; // zeroed automatically
if (cfg.flags & VERBOSE) {
    // always safe — flags == 0
}
C (compiles, silent leak)
int process(const char *path) {
    FILE *f = fopen(path, "r");
    if (!f) goto done;
    defer fclose(f); // skipped!
    do_work(f);
done:
    return 0; // f never closed
}
Prism (compile error)
int process(const char *path) {
    FILE *f = fopen(path, "r");
    if (!f) goto done;
    defer fclose(f);
    do_work(f);
done:
    // error: goto 'done' skips over
    // defer fclose(f)
    return 0;
}
safety

Control flow Prism catches.
C doesn't.

CFG analysis runs before any output is emitted. goto jumping over declarations, switch fallthrough skipping active defers, defer in setjmp/vfork/asm functions — all compile errors, not silent bugs.

0runtime overhead
all errors before emission
raw

Opt out. Precisely.

Zero-init has a cost on large buffers. raw skips initialization for a single variable without disabling anything globally.

per-variablegranularity
0global flags needed
// zeroed by default — 64k wasted memset
char buf[65536];
ssize_t n = read(fd, buf, sizeof(buf));

// raw: skip it — read fills it anyway
raw char buf[65536];
ssize_t n = read(fd, buf, sizeof(buf));

6,035 tests. Adversarially.

Not happy-path coverage. Edge cases, degenerate control flow, and patterns specifically designed to break a transpiler.

Prism is fully open source — Apache 2.0 licensed. Read every line, fork it, ship it. No strings.

Real-world codebases

OpenSSL, SQLite, Bash, Curl, GNU Coreutils, and Make — compiled unmodified through Prism. If it compiles and runs correctly there, it compiles and runs correctly everywhere.

Control flow nightmares

Nested loops with break and continue, switch fallthrough into deferred scopes, goto jumping over declarations, statement expressions inside defer bodies, computed goto with active defers. Every combination that could silently misfire.

Typedef disambiguation

Every typedef, enum constant, VLA tag, and parameter shadow — registered at all depths before a single byte of output is emitted. size_t x; and size_t * x; are not the same thing. Prism knows that.

Self-hosting

Prism compiles itself. Stage 1 and Stage 2 transpiled output is byte-for-byte identical — verified by CI on Linux x86_64, macOS x86_64/arm64, Linux arm64, and Linux riscv64. If it couldn't compile itself correctly, it couldn't ship.

GitHub

Built to spec.

Prism has a complete formal specification — every feature, every edge case, every invariant documented and cross-referenced against the test suite.

v1.1.4 · 6,035 tests · fully self-hosting · 14 invariants

Read the spec

Tokenizer, Pass 1 analysis, CFG verification, Pass 2 codegen, all language semantics.

Documentation

Getting started, CLI reference, feature guides, and architecture overview.

Blog — Apr 2026

A pragmatic C

On C's defaults, marginal improvements, and why Prism exists.

Continuous integration across Linux, macOS, and Windows — x86_64, arm64, and riscv64.

65%pass rate
65/100runs passing
6m 48savg run time
2bf9e0dfix 5 bugs, defer body ctrl_state/orelse leak, BOFrame reentsuccess10 Apr 17:43 · 6m 24s
c81cff2fix 3 bugs, volatile member memset UB, HashMap arena leak, cfailure10 Apr 19:13 · 6m 16s
76c3ba1fix 2 bugs, C tag namespace collapse on volatile/VLA lookup,failure10 Apr 19:47 · 6m 23s
6deeb34fix windows testsuccess10 Apr 19:52 · 5m 58s
5c3657bfix 1 bug, paren-wrapped orelse smuggling bypasses Phase 1F success10 Apr 20:09 · 6m 17s
3cc88ebfix 2 bugs, Phase 1D split predicate blind to current-decl osuccess10 Apr 20:42 · 6m 21s
018a0a0fix 1 bug, miscompilation via lexical noreturn shadowingfailure10 Apr 20:57 · 6m 1s
968d8d6windows test fixsuccess10 Apr 21:00 · 6m 12s
320fe44fix 3 bugs, attribute orelse leak, raw struct body leak, rawsuccess11 Apr 10:21 · 5m 33s
490a8c5stmt-expr dispatch in flat-emit loops + _Alignas SUE probe ssuccess11 Apr 15:16 · 5m 40s
76a1612fix 2 bugs, attribute-stealing struct tag scanner, C11 §6.2.success11 Apr 16:44 · 5m 46s
9e71bc1fix 4 bugs, param orelse funcdef bypass, block-scope typedefsuccess11 Apr 18:02 · 5m 34s
61b5fb3fix 2 bugs, ILP32 keyword shift UB, braceless body compound success11 Apr 19:35 · 5m 39s
379c242fix 3 bugs, ILP32 keyword shift UB, braceless compound litersuccess11 Apr 19:53 · 5m 40s
f439990fix 3 bugs, typeof funcptr attribute blindness, missing C23/failure11 Apr 21:22 · 5m 41s
bf2dedafix windows zero init testsuccess11 Apr 21:40 · 6m 19s
5661e79fix 2 bugs, __extension__ for-init zeroinit bypass, __extenssuccess12 Apr 09:12 · 6m 22s
1081ea0fix 4 bugs, defer shadow false positive on block-local declssuccess12 Apr 14:20 · 5m 50s
f7caf27fix 3 bugs, skip_to_semicolon defer validator scope escape, success12 Apr 16:23 · 5m 56s
a45666bfix 3 bugs, enum defer shadow false positive, walk_balanced success12 Apr 17:37 · 6m 27s
f7caf27fix 3 bugs, skip_to_semicolon defer validator scope escape, success12 Apr 17:44 · 5m 51s
864197bfix 3 bugs, enum defer shadow false positive, walk_balanced success12 Apr 17:49 · 5m 43s
792ec8bfix 5 bugs, chained orelse defer control-flow leak, typeof osuccess12 Apr 21:16 · 7m 18s
d0b7f55implement auto staticsuccess13 Apr 18:39 · 6m 33s
89ef391fix 1 bug, auto unreachable noreturn attribute placed post ffailure13 Apr 19:14 · 6m 31s
d60d16afix windows posix shimfailure13 Apr 19:27 · 6m 42s
bc042f2fix windows testssuccess13 Apr 19:47 · 5m 51s
37620c5fix 3 vulns, union = {0} padding infoleak, compound literal failure13 Apr 22:16 · 6m 41s
16bdb29fix windows testsuccess13 Apr 22:27 · 6m 36s
6c12a53fix 3 bugs, -fno-orelse defer-in-paren bypass, widen ann to success14 Apr 12:21 · 6m 31s
17013d6fix 6 bugs, attr noise blindspot in VLA predecessor, _Atomicfailure14 Apr 14:27 · 5m 48s
e11bd95fix 4 bugs, VM func ptr orelse double-eval, #define block cofailure15 Apr 11:33 · 6m 28s
fe20798fix 3 bugs, #define comment strip UAF, realloc double-free, success15 Apr 12:09 · 6m 8s
871c20ffix 2 bugs, _Generic defer body missing SCOPE_GENERIC, stalesuccess16 Apr 07:01 · 6m 41s
345e5d2fix 2 bugs, stmt-expr for-init defer shadow desync, defer kesuccess16 Apr 13:27 · 6m 29s
387b1c6fix 2 bugs, __label__ ctrl_pending leak in Phase 1D, Pass 0 success16 Apr 20:25 · 6m 44s
253266efix 2 bugs, ret_counter desync between __prism_ret_N decl anfailure16 Apr 20:26 · 6m 27s
98423f6fix 3 bugs, typeof VLA with paren/call in dim skipped zeroinfailure16 Apr 21:46 · 6m 54s
7234b51fix macos arm64 test flake, replace fork()+execvp()+system(3success16 Apr 22:31 · 8m 23s
fbcf85afix missed internal versioningsuccess16 Apr 22:39 · 6m 54s
a0632b8bounds checking first passsuccess17 Apr 05:40 · 5m 0s
24d2353fix 4 bugs, offsetof/sizeof subscript wrap silent false negafailure17 Apr 06:04 · 49s
0245cf5fix 2 bugs, bounds-check no-paren sizeof/typeof subscript wrfailure17 Apr 06:27 · 56s
d59bb16fix 1 bug, -fbounds-check preamble used __SIZE_TYPE__ which success17 Apr 07:15 · 6m 20s
e995c02cleanup + fix dead PRISM_TEST_RUNTIME wrapperfailure17 Apr 08:11 · 6m 52s
fcb4918cleanupfailure17 Apr 08:22 · 7m 9s
1a3f08bfix Windows LLP64 bounds-check truncation on MinGW/Clangfailure17 Apr 08:36 · 5m 9s
23a879cfix Windows build: restore signal_temps_unregistersuccess17 Apr 09:04 · 7m 24s
7c33ec4fix 3 bounds-check holes, parenthesized/typedef array + sizefailure17 Apr 09:36 · 3m 28s
a0ce82ffix 3 more bounds-check holes: ((a))[i], int *a[10], staticcfailure17 Apr 09:47 · 5m 22s
720f408fix bounds-check hole: file-scope arrays were never registerfailure17 Apr 11:03 · 3m 10s
502a7acfix bounds-check hole: file-scope arrays were never registerfailure17 Apr 11:53 · 3m 37s
8d9fbe5fix OOB read in p1_mark_uneval_brackets: skip token_pool[0] cancelled17 Apr 11:53 · 2m 34s
9fbaee6test harness: pin 8 MiB pthread stack for CI workerssuccess17 Apr 12:07 · 6m 36s
ad2d5f0defense-in-depth: zero token_pool[0] sentinel on first allocsuccess17 Apr 12:18 · 7m 4s
048c31dbounds-check: close declarator-bracket class of spurious wrasuccess17 Apr 16:42 · 7m 0s
f351461fix 2 bugs: commutative-subscript bounds bypass, const-aggresuccess17 Apr 18:42 · 7m 12s
9eb60edbounds-check: propagate array_rank through typedef chainsfailure17 Apr 19:42 · 7m 1s
cea01b4windows test fixsuccess17 Apr 19:48 · 6m 37s
a749df0fix 6 bugs: struct-body tag lookup for volatile/VLA, typeof/success18 Apr 04:44 · 6m 27s
16d1b2cfix bounds + const orelse: ARRAY_RANK_WRAP_ALL, typedef arrasuccess18 Apr 10:29 · 7m 16s
7becfcafix 8 bugs, skip_one_stmt snap cap, struct field vs typedef,failure18 Apr 11:40 · 45s
34ffac7fix 3 bugs, fold reported-issue regressions into domain testsuccess18 Apr 12:29 · 6m 45s
cf5ad34fix 10 bugs, skip_one_stmt trail snap beyond SOS_IF_MAX and success18 Apr 12:37 · 7m 50s
342e9ccfix 8 issues, C23 float literals verbatim, defer break at ctfailure18 Apr 16:24 · 8m 4s
363aab9fix test failssuccess18 Apr 17:01 · 7m 54s
d159a98fix 8 bugs, defer capture hash restore, braceless defer P1_Isuccess18 Apr 18:42 · 7m 39s
565cf86fix attr orelse desync, emit C23 [[...]] verbatim in Pass 2;success18 Apr 18:52 · 7m 15s
d0dedf6fix 8 bugs, cfg_check_range VLA-before-init ordering and hassuccess18 Apr 19:11 · 7m 44s
2814de3fix 8 bugs, bounds-check: wrapping subscripts in static-storsuccess20 Apr 08:31 · 7m 19s
46d9de0cleanupsuccess20 Apr 09:04 · 6m 48s
732be53cleanup: drop defensive match guards, unify single-char checsuccess20 Apr 11:21 · 7m 36s
dd1f6b6fix raw * x miscompilesuccess20 Apr 14:10 · 7m 36s
7eee1b5prism run -- cli args support, #pragma link <platform> supposuccess22 Apr 09:56 · 6m 51s
1abc7f4fix 4 bugs: bounds-check false-positive on struct-field-arrafailure23 Apr 08:53 · 7m 54s
fda0837windows fixsuccess23 Apr 16:38 · 7m 49s
a4b5717fix: skip scope tree entries for init-in-init braces; fix p1failure23 Apr 16:58 · 7m 12s
bad59cfwindows fixsuccess23 Apr 17:02 · 7m 7s
9868145fix 1 bug, reject parenthesized stmt-expr declaration orelsesuccess25 Apr 12:11 · 7m 47s
6df08b2fix 3 bugs, tokenizer handling for C23 u8 character literalssuccess25 Apr 12:42 · 7m 46s
3d4ca2bfix 3 bugs, alignas typedef precedence and contextual orelsefailure25 Apr 13:34 · 7m 46s
40866fcfix 3 bugs, contextual keyword computed labels, soft labels failure25 Apr 14:03 · 7m 17s
67759ddfix windows cisuccess25 Apr 14:06 · 8m 12s
6b986d3optimizationsfailure26 Apr 16:42 · 7m 13s
7faa0d2fix windowsfailure26 Apr 16:46 · 8m 3s
a45cdb9fix windowsfailure26 Apr 16:55 · 8m 10s
6eb7cc9try fixfailure26 Apr 18:48 · 7m 50s
393fefbfix windows cisuccess27 Apr 12:17 · 5m 47s
1c11949fix windows ci and restore optimizationsfailure27 Apr 12:21 · 8m 7s
23a91ccoptimizationssuccess27 Apr 12:26 · 8m 2s
f9493deadd optimization attributessuccess27 Apr 18:50 · 10m 9s
d914e2cadd optimization attributessuccess27 Apr 18:57 · 10m 12s
48cec3cfix 4 bugs, reject const bare orelse and preserve soft-keywosuccess27 Apr 19:33 · 10m 37s
6fc467dfix 5 bugs, soft-keyword identifier handling issues in parsefailure27 Apr 19:59 · 10m 29s
115d2bafix function declarator handling and MSVC unreachable testssuccess27 Apr 20:44 · 9m 23s
16de944fix typeof on local function declarationssuccess27 Apr 20:58 · 9m 30s
0b3f158fix 85 bugs, 8 bounds-check bypasses + ~62 c23 init-statemenfailure29 Apr 15:02 · 10m 50s
d385352fix windows thread attributesuccess29 Apr 15:06 · 10m 53s
ac53f44cleanup & optimizesuccess29 Apr 16:28 · 9m 56s
e645922fix 7 bugs, accept GNU nested funcs, C23 if/switch-init VLA,success2 May 12:24 · 10m 49s
Linuxx86_64success57s
Linuxarm64success41s
Linuxriscv64success10m 46s
macOSx86_64success1m 1s
macOSarm64success39s
Windowsx86_64success54s

Prism is built and maintained by one person, in the open, for free.

If it saves you time or makes your C safer, sponsoring is how you keep that going. Every sponsor directly funds time on new features, bug fixes, and keeping the test suite green.

Available for consulting work across design, branding, and engineering.

Compiler work, systems programming, C codebase hardening, dev tooling, or a visual identity for your project — send an email.

dawn@dawn.day

Serious inquiries only.