C hands you a pointer and lets you add to it. Nothing travels with the pointer to say how far the addition may go, and the standard says that going past the end of the array is undefined, so the compiler is free to assume it never happens and to optimize on that assumption. Out-of-bounds write has been the first or second entry on the MITRE list of the most dangerous software weaknesses every year from 2021 to 2024, and both Microsoft and the Chromium project have reported that about seventy percent of their serious security bugs are memory safety bugs. cint keeps the thing C does well, which is to look at part of an array without copying it, and takes away the arithmetic that made it dangerous. The window carries its own bounds, and an index outside them is a fault record, not a read of whatever came next.
In C a slice of an array is a pointer and a length that you carry separately and hope to keep in step. p + i is a new pointer with no memory of where the array ended, and p[i] is *(p + i) and asks no questions. The standard permits the pointer to point one past the end and no further; everything beyond that is undefined behavior, which means not an error the program can see but a license for the compiler to do whatever follows from assuming it did not happen. Real-time and embedded code lives on this construction because it is fast and because it copies nothing, and that is the part worth keeping.
In cint an array is owned storage and a view is a window onto it. a[lo..hi] is the elements from lo up to but not including hi, and it is a view, so no element moves. A view is declared with a permission keyword, in for read-only or inout for writable, and what makes it a view rather than an array is exactly that keyword: the same expression with a type and no keyword, I64[4] owned = a[2..6];, is a copy into new storage. The slice is checked when it is made. lo must not exceed hi and both must lie within the array, else the operation named slice.checked faults with E_BOUNDS before any element is touched. The view carries its extent, so len(view) is always right and an index into the view is checked against the view, not against the array behind it. A view may be strided, a[lo..hi by 2], and indexing a rank-2 array with one index gives a view of the row, and the row knows its own length too.
A view is second-class, and that one rule carries most of the safety. It may be a local variable, a parameter, or an argument, and nothing else: it may not be stored in a struct field, an array, a global, an arena or a pool, and it may not be captured by anything that outlives the block it was made in. A function may return a view only if it is derived from one of its own view parameters, and the compiler checks the derivation statically. A view cannot be rebound; assignment to a view variable copies elements into the storage it looks at. The consequence is that a view never outlives the storage it windows, so there is no dangling view, and there is no way to build a structure of views that escape. Where a reference does have to cross scopes, cint uses a generation-checked handle that faults with E_STALE_HANDLE rather than a raw address. One more rule matters for reading a fault record: the indices of a place are evaluated and checked before the right-hand side of an assignment is evaluated, so a bad index faults first and the record names the index, not some later state.
views.ci makes a read-only window of four elements over an array of eight and totals it through a function that takes in I64[] and asks the view for its length. It then makes an owned copy of the same four elements and a writable window over them, writes through the window, and shows that the array changed and the copy did not. The last line asks the four-element window for its element four.
views.ci Run the first Run loads Python, about 12 MB, once
Run views.ci and the three lines it writes before the fault are the point of the first half: a total of 180 through a window that copied nothing, a write through a window that reached the array while the owned copy kept its 30, and a second window made on the fly as an argument. Then middle[4]. The record says E_BOUNDS, names the operation index.checked.i64, gives the operand 4 and the limit 4, and points at line 25, column 26. The limit is the extent of the view, not the eight of the array behind it, which is the whole difference from p[4] in C, where the read would have returned 70 and nobody would have known.
bad_slice.ci makes the mistake one level up. a[3..10] on an array of eight is refused as a slice: slice.checked.i64, operands 3 and 10, limit 8, line 8 column 22, with fault.exact none because there is no exact value to report, only a bound that was crossed. No element was read. Change the 10 to an 8 and run it again, and the tail has five elements.
The other half of this paper is a benchmark, and it is not here. The claim to be tested is that a checked index through a view, after the C compiler has hoisted the checks it can prove, costs little against manual pointer indexing, and the honest form of that claim is a number, measured, whatever it turns out to be. Two things stand in the way today. The compiler that emitted the C on this site refuses the two programs on this page, which is why the lower box says so instead of showing C; the compiler since then compiles both, with the same stdout and the same fault records as the reference, but its C is not on the site yet. And there is no benchmark harness yet. With one, the measurement is the same program three ways, cint through cintc, hand-written C with a pointer, and hand-written C with an explicit length check, built by the same four toolchains, and the numbers go here.
This page describes the rules as specified and as the reference implements them. It makes no claim about compiled performance, and it makes no memory-safety claim for programs that share storage with foreign code, which the specification treats separately and has not yet closed. The vulnerability figures are the publishers' own and are cited for scale, not as a measurement of any particular codebase.
Harriett Little. Slices without copies. integerc.dev, 2026. https://integerc.dev/papers/slices/
Harriett Little
October 2026