Safer C.
No rewrite required.

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

version
v1.0.9
tests
4,929
stars
3
commits
569
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));

4,929 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.0.9 · 4,929 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.

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

74%pass rate
74/100runs passing
5m 37savg run time
7f921ffcleanup & de-dupespassing1 Apr 19:02 · 6m 44s
82b2313de-dupe / split validate_deferpassing1 Apr 20:22 · 1m 32s
2ec6a01fix recursion regressionpassing1 Apr 20:56 · 5m 52s
46bb2a5fix 3 bugs, orelse block defer bypass, raw string #if 0 desypassing1 Apr 21:21 · 6m 1s
4650fc8optimize 6 areas, 13.4% less inst in self transpile, bloom fpassing2 Apr 01:03 · 5m 35s
5942783fix 1 bug, __attribute__ bracket orelse queue desynchronizatpassing2 Apr 08:34 · 5m 32s
19032bcfix 1 bug, optimization regression, orelse keyword leak via passing2 Apr 08:51 · 5m 45s
12ff66ffix 2 bugs, O(N²) typeof func-proto scan, init-cast VLA orelpassing2 Apr 09:32 · 5m 42s
6bb82d1fix 2 bugs, stmt-expr goto/return in orelse bypasses defer cpassing2 Apr 10:24 · 5m 11s
4e79cd5fix 3 bugs, scope/block depth confusion over-unwinds defers,passing2 Apr 11:40 · 4m 32s
2b422a8fix 2 bugs, O(D×T) taint propagation to O(T+D×E) edge-based passing2 Apr 12:16 · 5m 18s
27966d9fix 6 bugs: orelse block defer bypass, braceless ctrl-flow ipassing2 Apr 15:48 · 4m 52s
fc098bbfix 6 bugs, orelse block defer bypass, braceless ctrl-flow ipassing2 Apr 15:58 · 4m 55s
3f6e7c3fix 2 bugs, shadowed orelse/defer keywords suppressed by varpassing2 Apr 18:24 · 4m 2s
9dc641dtry skip race test on QEMUpassing2 Apr 18:49 · 5m 18s
d850fabdockerenv to trigger is emulated in testspassing2 Apr 19:00 · 5m 35s
72fcf86fix 1 bug, stmt-expr false positive in defer shadow checkerpassing2 Apr 20:20 · 5m 12s
0ea1478fix 1 bug, emit_type_range stmt-expr bypass in struct bodiespassing2 Apr 20:58 · 5m 15s
75ecedffix 3 bugs, dead const_td_is_array code, braceless switch depassing2 Apr 21:39 · 5m 6s
a850967fix 2 bugs, chained assignment orelse split-brain, block-scopassing2 Apr 23:44 · 5m 15s
8888ae3fix 2 bugs, typeof bit-field in bare orelse, array_size_is_vpassing3 Apr 07:51 · 5m 22s
c2372aafix 3 bugs, VLA param decay false positive, __auto_type orelpassing3 Apr 08:19 · 5m 13s
25cbe72fix 2 bugs, test harness cleanup: param multidim VLA sizeof passing3 Apr 10:42 · 5m 28s
7ff985cfix golf test for GCC, rename all tests to objective names, passing3 Apr 10:58 · 5m 30s
270b1fafix 3 bugs, case/default p1d_ctrl_pending leak bypasses CFG passing3 Apr 15:57 · 5m 24s
0abd764fix 4 bugs, sizeof commutative VLA bypass (stack corruption)passing3 Apr 17:06 · 5m 7s
acf026bfix 7 bugs, VM-type multi-decl split two-pass violation, ctrpassing3 Apr 19:58 · 5m 45s
a945663fix 3 bugs, C23 attr bypasses defer stmt-expr chain check twpassing3 Apr 21:01 · 5m 48s
a5d566efix 2 bugs, typeof parenthesized function name bypasses memspassing3 Apr 21:21 · 4m 21s
690d625test count bumppassing3 Apr 21:24 · 5m 15s
cf274c1fix 1 bug, orelse inside ternary expression only caught by Ppassing3 Apr 22:11 · 5m 49s
5a4243dfix 4 bugs, move ~925 lines of parsing infrastructure from ppassing4 Apr 00:47 · 5m 31s
06c4b4dmove ~447 lines of pure analysis to parse.c, inline p1_add_spassing4 Apr 07:02 · 5m 41s
76c605bcleanuppassing4 Apr 08:05 · 5m 39s
7fa5c85fix 2 bugs, orelse inside ctrl-flow condition parens two-paspassing4 Apr 10:53 · 5m 39s
c4c9311fix 5 bugs, raw*expr misclassified as pointer declaration stpassing4 Apr 14:29 · 5m 27s
8abb51efix 3 bugs, noreturn attr arg poisoning, VLA deref paren adjpassing4 Apr 19:25 · 5m 31s
ea2c1c9gate 3 regression tests behind GNUC_ONLY for Windows CIpassing4 Apr 19:38 · 5m 34s
be1280dprep adding featurespassing5 Apr 07:57 · 5m 20s
8fcca8afix 3 bugs, bare orelse typeof VM double-eval via typeof(RHSpassing5 Apr 11:40 · 5m 0s
0efa5edfix 2 bugs, C23 [[attr]] consumed into defer return-type typpassing5 Apr 13:51 · 5m 19s
2ac2200fix 2 bugs, C23 [[attr]] consumed into defer return-type typpassing5 Apr 14:44 · 4m 45s
40b6fbcfix 2 bugs, _Generic ternary colon confused with associationpassing5 Apr 15:29 · 5m 25s
6e926acfix 6 bugs, is_array_bracket_predecessor VLA hallucination opassing5 Apr 19:11 · 5m 24s
a694cb6fix 5 bugs, _Generic extraction discards trailing expressionpassing6 Apr 06:27 · 5m 4s
edae040fix 5 bugs, raw keyword leak in cast/sizeof/compound-literalpassing6 Apr 11:31 · 5m 37s
e32bdc2fix 5 bugs, MSVC diagnostic push/pop emitting nothing, f128 passing6 Apr 12:57 · 5m 47s
452a220fix 5 bugs, ghost enum defer shadow escape in enclosing scoppassing6 Apr 13:39 · 5m 5s
3410f7dfix 5 bugs, typeof_unqual off-by-one const-stripping, _Generpassing6 Apr 14:29 · 5m 56s
c039946fix Windows CI: use has_zeroing() in typeof_unqual testpassing6 Apr 14:33 · 5m 41s
60fc35efix 5 bugs, _Generic inner-generic prefix drop, _Generic parpassing6 Apr 15:38 · 5m 43s
e51e08bfix 2 bugs, bracket orelse stmt-expr reentrancy state clobbepassing6 Apr 16:24 · 5m 28s
e41533cfix 4 bugs, add formal spec + compliance testspassing6 Apr 17:51 · 3m 5s
6dafccdfix 2 crashes, token_pool[0] OOB in K&R fallback, emit_deferpassing6 Apr 18:40 · 5m 17s
6ca00cefix 1 bug, stmt-expr paren-strip keyword leak; update SPEC.mpassing6 Apr 18:54 · 6m 15s
44ce49afix 2 bugs, typeof_var memset queue reentrancy clobber in stpassing6 Apr 19:26 · 6m 10s
c13effdfix 6 bugs, typeof_var reentry test, RHS ctrl-flow duplicatipassing6 Apr 20:20 · 6m 11s
e966190fix 3 bugs, attr-raw VLA safety bypass, _Generic nested rewrpassing6 Apr 21:13 · 5m 50s
ae8a43ffix 4 bugs, backward goto nested-scope defer loop CFG bypasspassing6 Apr 22:06 · 6m 15s
c92930afix 1 bug, function type erasure in chained typedefs and typpassing6 Apr 22:14 · 5m 23s
f69d460fix 1 bug, _Generic member rewrite blind spots in defer bodipassing6 Apr 22:42 · 6m 3s
1841bdcdrop _generic re-write + spec updatepassing7 Apr 08:35 · 5m 40s
fe50fa9shrink P1FuncEntry and TypedefEntry from 40 to 32 bytes (2 ppassing7 Apr 11:45 · 6m 7s
194f498fix emit_block_body + emit_deferred_range gaps; finish _Genepassing7 Apr 18:23 · 5m 55s
58a4d7efix ObjC @interface/@implementation ivar zero-init; add regrpassing7 Apr 19:40 · 6m 6s
4d4e839fix 3 bugs, ObjC ivar zero-init, protocol/generics angle brapassing7 Apr 21:49 · 5m 56s
17d642aunify emit_block_body + emit_deferred_range into 2-mode emitpassing8 Apr 22:16 · 6m 5s
86a98d8fix 3 bugs, C23 [[attr]] skip in walk_back_skip_attrs on nampassing9 Apr 12:58 · 5m 31s
5299296fix 2 bugs, stmt-expr noise-skip for _Pragma/C23 attrs + typpassing9 Apr 16:03 · 6m 16s
17b40d0fix 2 bugs, C23 attr orelse FIFO queue steal + keyword leak,passing9 Apr 18:11 · 6m 10s
63ab2b4fix 4 bugs, bracket raw leak, bare orelse raw leak, nested tpassing9 Apr 21:45 · 6m 0s
e08fa63msvc test fixpassing9 Apr 21:55 · 6m 2s
86be39afix 6 bugs, constexpr+orelse/const-VLA/register-VLA Phase 1Dpassing10 Apr 05:46 · 6m 5s
ed9fd38fix 3 bugs, defer body ctrl_state leak, typeof/bracket orelspassing10 Apr 10:48 · 6m 5s
ed38b7efix 1 bug, extern decl false positive as nested function witpassing10 Apr 14:53 · 5m 45s
c2b7f68fix 1 bug, stmt-expr in ctrl condition label blindspotpassing10 Apr 15:25 · 6m 5s
b6f83b2fix 1 bug, typeof ctrl-flow keyword rejection gated on -fno-passing10 Apr 16:02 · 5m 32s
2bf9e0dfix 5 bugs, defer body ctrl_state/orelse leak, BOFrame reentpassing10 Apr 17:43 · 6m 24s
c81cff2fix 3 bugs, volatile member memset UB, HashMap arena leak, cpassing10 Apr 19:13 · 6m 16s
76c3ba1fix 2 bugs, C tag namespace collapse on volatile/VLA lookup,passing10 Apr 19:47 · 6m 23s
6deeb34fix windows testpassing10 Apr 19:52 · 5m 58s
5c3657bfix 1 bug, paren-wrapped orelse smuggling bypasses Phase 1F passing10 Apr 20:09 · 6m 17s
3cc88ebfix 2 bugs, Phase 1D split predicate blind to current-decl opassing10 Apr 20:42 · 6m 21s
018a0a0fix 1 bug, miscompilation via lexical noreturn shadowingpassing10 Apr 20:57 · 6m 1s
968d8d6windows test fixpassing10 Apr 21:00 · 6m 12s
320fe44fix 3 bugs, attribute orelse leak, raw struct body leak, rawpassing11 Apr 10:21 · 5m 33s
490a8c5stmt-expr dispatch in flat-emit loops + _Alignas SUE probe spassing11 Apr 15:16 · 5m 40s
76a1612fix 2 bugs, attribute-stealing struct tag scanner, C11 §6.2.passing11 Apr 16:44 · 5m 46s
9e71bc1fix 4 bugs, param orelse funcdef bypass, block-scope typedefpassing11 Apr 18:02 · 5m 34s
61b5fb3fix 2 bugs, ILP32 keyword shift UB, braceless body compound passing11 Apr 19:35 · 5m 39s
379c242fix 3 bugs, ILP32 keyword shift UB, braceless compound literpassing11 Apr 19:53 · 5m 40s
f439990fix 3 bugs, typeof funcptr attribute blindness, missing C23/passing11 Apr 21:22 · 5m 41s
bf2dedafix windows zero init testpassing11 Apr 21:40 · 6m 19s
5661e79fix 2 bugs, __extension__ for-init zeroinit bypass, __extenspassing12 Apr 09:12 · 6m 22s
1081ea0fix 4 bugs, defer shadow false positive on block-local declspassing12 Apr 14:20 · 5m 50s
f7caf27fix 3 bugs, skip_to_semicolon defer validator scope escape, passing12 Apr 16:23 · 5m 56s
a45666bfix 3 bugs, enum defer shadow false positive, walk_balanced passing12 Apr 17:37 · 6m 27s
f7caf27fix 3 bugs, skip_to_semicolon defer validator scope escape, passing12 Apr 17:44 · 5m 51s
864197bfix 3 bugs, enum defer shadow false positive, walk_balanced passing12 Apr 17:49 · 5m 43s
792ec8bfix 5 bugs, chained orelse defer control-flow leak, typeof opassing12 Apr 21:16 · 7m 18s
Linuxx86_64success35s
Linuxarm64success29s
Linuxriscv64success7m 15s
macOSx86_64success32s
macOSarm64success19s
Windowsx86_64success1m 1s

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.