SnoopStop

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.

18kinds of bug checked
0bytes of code sent to a server
226automated test steps
$0price

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

    1. 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.
    2. 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.
    3. 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.
    4. 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

    BugExampleCWE
    Out-of-bounds read / writea[n], a[-1]125 / 787
    Buffer overflow in a library callstrcpy, strcat, memcpy past the destination120
    Unterminated stringno \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 freefree(p); return p[0];416
    Double or invalid freefree(p); free(p);, freeing a stack array415 / 761
    Value truncation (narrowing)char c = 300;, unsigned char b = x;197
    Integer overflow(lo + hi) / 2, -INT_MIN190
    Division by zeros / n, x % 0369
    Invalid shiftx << 32, -1 << 31335
    Uninitialized variableint x; return x;457
    Function ends without a return valueif (x) return 1; then the end758
    Precondition broken by a callerwrong value passed to a function with a contract–
    Postcondition and loop invariant//@ ensures, //@ invariant–
    assertassert(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, switch and 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): long and size_t are 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.