SnoopStop Origin
Paste your C or Rust code. For every array access, division and integer operation you get one of two answers: either a mathematical proof that it is safe for every possible input, or the real input that triggers the bug, run and shown to you, together with a patch that has been proved to close it.
This is a trial version. For now it understands part of C: every integer type (char, short,
int, long, unsigned, size_t), arrays of them, strings, loops, conditions, your own functions and
library functions such as strcpy, strcat, strncpy, strlen, memcpy and memset,
pointers (*p, p + i, &a[i], NULL) and malloc / calloc / free.
and struct (s.x, p->x, a[i].x, p->name[i], typedef). Pointers to pointers and fields that hold pointers are not supported yet.
Concurrency and authorization (new): global variables, pthread_mutex_t locks, //@ guarded_by m
(data races), double locking and returning with a lock held; an authorization model declared with //@ grants X if ... /
//@ requires \granted(X). The rules are the ones you declare; the tool proves they hold on every path. Thread interleavings are
not enumerated one by one: code that follows the locking discipline has no race, and a path that breaks it is shown.
Rust (new): integer types, slices (&[T], &mut [T]), arrays ([v; N]), subslices
(&a[i..j]), .len(), for / while, if expressions, as, wrapping_*,
assert! / panic!. It assumes a build with overflow checks on, so overflow counts as a panic. Structs, Vec and iterators are not supported yet,
and automatic patches and "Fix everything" are C only for now.
"Proved" holds only for the properties listed below and assumes this tool works correctly; it has not had an independent audit.
It does not replace a security review.
Origin Pro · preview
Scan a whole project, get an audit report
Pick a folder or several files (.c and .rs). They are analysed one by one in this browser; your code goes nowhere. At the end you download a report with the bugs, the inputs that trigger them and what was proved; open it in your browser and choose "Save as PDF". The report is in Turkish for now.
How it works
- Every risky operation becomes a question. "Can this
a[i]ever fall outside the array?", "Can this divisor be zero?" The questions are written in exact 32-bit machine arithmetic, overflow included. - The Z3 prover answers. If it says "impossible", the property is proved for every possible input. The tool finds the loop invariants it needs (such as
0 <= i <= n) by itself; you can also write your own. - If it says "possible", the counterexample is actually run. The code is executed step by step under C's rules with the input the prover found. If the bug does not really happen, nothing is reported as a bug; you see "not proved" instead of a false alarm.
- Patches are proved too. Each suggested fix is applied and the code is analysed again from scratch. You only see patches that are proved to close the bug and add no new one.
The analysis runs entirely in this tab, with Z3 (MIT licence) compiled to WebAssembly. Your code is never sent to any server. Each proof can be downloaded as an SMT-LIB file and checked again with another solver such as cvc5. The command-line and GitHub versions can, if you choose, ask an AI of your choice (Claude, OpenAI, Gemini or Ollama on your own machine) to suggest missing loop invariants, and every suggestion is proved again by Z3; the tool on this page uses no AI.
What it checks
| Bug | Example | CWE |
|---|---|---|
| Out-of-bounds read / write | a[n], a[-1] | 125 / 787 |
| Buffer overflow in a library call | strcpy, strcat, memcpy past the destination | 120 |
| Unterminated string | no \0 after strncpy, char t[3] = "abc" | 170 |
NULL pointer use (including an unchecked malloc) | p = malloc(n); p[0] = 1; | 476 / 690 |
| Use after free | free(p); return p[0]; | 416 |
Double or invalid free | free(p); free(p);, freeing a stack array | 415 / 761 |
| Value truncation (narrowing) | char c = 300;, unsigned char b = x; | 197 |
| Integer overflow | (lo + hi) / 2, -INT_MIN | 190 |
| Division by zero | s / n, x % 0 | 369 |
| Invalid shift | x << 32, -1 << 3 | 1335 |
| Uninitialized variable | int x; return x; | 457 |
| Function ends without a return value | if (x) return 1; then the end | 758 |
| Precondition broken by a caller | wrong value passed to a function with a contract | – |
| Postcondition and loop invariant | //@ ensures, //@ invariant | – |
assert | assert(n > 0); | 617 |
Writing contracts (optional)
It works without any. If you write what a function assumes and what it guarantees, the tool proves those as well and checks them at every call.
//@ requires 0 <= i && i < n; // the caller must ensure this
//@ ensures \result >= 0; // the function guarantees this
int get(int a[], int n, int i) { ... }
//@ invariant 0 <= i && i <= n; // true on every iteration
for (int i = 0; i < n; i++) { ... }
C does not record the length of an array. In the int a[], int n pattern, n is assumed to be the
length of a, and the result says so. For another relation, write //@ requires len(a) >= m;.
Known limits
- Pointers to pointers (
**p), fields that hold pointers or nested structs, passing structs by value, function pointers,realloc,float,break,switchand library functions not in the list are not supported; it tells you clearly when it meets one. - Pointer parameters are assumed not to be NULL.
malloc, on the other hand, may return NULL, as it really can. - The data model is 64-bit Linux/macOS (LP64):
longandsize_tare 64 bits. Unsigned wrap-around is defined in C, so it is not reported as a bug; the out-of-bounds access it leads to is. - When a property cannot be proved, loops are tried up to a fixed number of iterations; that does not mean "safe".
- The result of a recursive function without a contract is treated as unknown.
- The first analysis downloads the proof engine (about 10 MB compressed); after that it comes from the browser cache.