Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
77de6f0
chore(quest): claim quest/m3/ts-unsafe/raw-behind-ref.md
kixelated Nov 7, 2026
3478933
feat(ts): translate a raw pointer behind a reference
kixelated Nov 7, 2026
19345e1
style(ts): format
kixelated Nov 7, 2026
0e8bd26
Merge remote-tracking branch 'origin/main' into fix/raw-pointer-refer…
kixelated Nov 7, 2026
71cd733
test(ts): regenerate the census fixture after merging main
kixelated Nov 7, 2026
5a40085
docs(quest): the census at the pin after a raw pointer behind a refer…
kixelated Nov 7, 2026
30e8b12
fix(ts): keep an Arc's value's pointer its one place, and read an enu…
kixelated Nov 7, 2026
437a61a
test(ts): snapshot the Arc pointers' case
kixelated Nov 7, 2026
bce76b5
fix(ts): tell a tag outside every UnsafeCell by the value's layout
kixelated Nov 7, 2026
43b8b2b
Merge remote-tracking branch 'origin/main' into fix/raw-pointer-refer…
kixelated Nov 7, 2026
65927ee
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
0766fe4
chore(ts): regenerate the pointer snapshots for rs.String
kixelated Nov 7, 2026
3a423f4
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
694c6e1
chore(ts): regenerate the pointer snapshots after merging main
kixelated Nov 7, 2026
f45cfbc
quest: recount the census after merging main
kixelated Nov 7, 2026
e58dcda
fix(ts): move a copy out of a pointer from a &mut to an object
kixelated Nov 7, 2026
4af334c
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
0916afe
chore(ts): regenerate the snapshots after merging main
kixelated Nov 7, 2026
9bfcf27
style(ts): format
kixelated Nov 7, 2026
92a40b7
Merge remote-tracking branch 'origin/main' into raw-behind-ref
kixelated Nov 7, 2026
28c5450
fix(ts): copy every value a pointer read moves out, library objects i…
kixelated Nov 7, 2026
925f1bc
fix(ts): copy what a cell or lock holds inline when moving it out
kixelated Nov 7, 2026
d4531da
fix(ts): copy a range's ends and a borrowed cell's value when moving …
kixelated Nov 7, 2026
8955797
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
501e113
fix(ts): refuse moving out a library object whose inline state only i…
kixelated Nov 7, 2026
7362511
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
20c188d
fix(ts): copy a Weak moved out through a pointer as the handle it is
kixelated Nov 7, 2026
f275248
chore(ts): recount the census, name the inline-state alias, format
kixelated Nov 7, 2026
b117c7e
fix(ts): copy a Vec's or VecDeque's storage on a move-out read, clear…
kixelated Nov 7, 2026
0b375b8
chore(ts): format, regenerate the conversions snapshot
kixelated Nov 7, 2026
742b2bd
docs(ts): note storage copies and unfixed offsets from a lone place
kixelated Nov 7, 2026
c77552a
fix(ts): keep a place's accessors on a whole write, refuse unfixed wr…
kixelated Nov 7, 2026
07fda2b
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe/ra…
kixelated Nov 7, 2026
bc03ffc
Merge remote-tracking branch 'origin/main' into iterate-621b
kixelated Nov 7, 2026
e2a5e8c
feat(ts): refuse unsplit collection moves and offsets off a lone place
kixelated Nov 7, 2026
3d5165c
test(ts): refuse a collection's ptr::copy within a Vec
kixelated Nov 7, 2026
44bfc2a
fix(ts): check reads one past a lone place, not the pointer
kixelated Nov 7, 2026
521d901
style(ts): format
kixelated Nov 7, 2026
3312df3
Merge remote-tracking branch 'origin/main' into iterate-621b
kixelated Nov 7, 2026
8ca09a4
fix(ts): check only accessed pointers, and none to a value of no bytes
kixelated Nov 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions quest/m2/ts-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ Decided with the maintainer on 2026-10-27, from a census of the model's 22 publi
- The end-to-end work stays here: the model's roots, its differential harness, and the
`frames.ts` workload. moq writes the binding files `model.toml` names, in its own tree.

The census at the pin on 2026-11-07: 51 refusals. `Timestamp` alone refuses nothing, and
The census at the pin on 2026-11-07: 45 refusals. `Timestamp` alone refuses nothing, and
the [model fixture](/ts/README.md#tests)'s harness runs it against native moq-net at the
pin; each case it adds as a type translates. Every other root reaches the rest of the
model, all of it moq's, for its research quest: kio's `log.rs` reads bytes as its segments
and retires them through crossbeam-epoch, whose tagged pointers and inline closures (36
refusals) translation refuses for good, and smallvec's union over a type parameter and
raw parts (10) wait on [unsafe](/quest/m3/ts-unsafe/README.md), so moq rewrites or drops
refusals) translation refuses for good, and smallvec's union over a type parameter, its
`Array::Item`, and raw parts (5) wait on [unsafe](/quest/m3/ts-unsafe/README.md), so moq rewrites or drops
them, as it does the `unsafe` slice of `model/frame.rs`'s `Filled`.

Decided with the maintainer on 2026-11-04, from a census at the bumped pin
Expand Down
3 changes: 1 addition & 2 deletions quest/m3/ts-unsafe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,10 @@ construct still open at `b3df54b6c`, all in m3:
[#568](https://github.com/moq-dev/rust2/pull/568). `bytes`' `Buf::get_u16` and wider
map to the runtime since [#447](https://github.com/moq-dev/rust2/pull/447).

Census at the moq pin on 2026-11-06: model 82, kio 76, moq-net 409 refusals.
Census at the moq pin on 2026-11-07: model 45, kio 72, moq-net 344 refusals.

Public API: the translator's output.

## Required

- [A raw pointer behind a reference](/quest/m3/ts-unsafe/raw-behind-ref.md) - `&raw const *r` of a value JS copies points where the reference came from
- [UnsafeCell's raw accessors](/quest/m3/ts-unsafe/unsafecell.md) - `UnsafeCell::raw_get`, `from_mut`, and `replace` translate
23 changes: 0 additions & 23 deletions quest/m3/ts-unsafe/raw-behind-ref.md

This file was deleted.

2 changes: 1 addition & 1 deletion ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ crate translation reaches is refused, and so are two versions of one crate it re
| `Vec<T>` | `rs.Vec<T>`: its items, the array `items`, and the capacity std's holds; `rs.vecFrom(items)` makes one of an array with room for exactly them. `rs.ByteVec` of bytes |
| `Cow<[T]>`, `Cow<str>` | `rs.Cow<T>`: the `Vec` it owns, or an `rs.Borrowed` holding the slice it borrows, `rs.Cow<T, rs.ArraySlice<S>>` holding the arrays of a slice of arrays; `rs.ByteCow` for bytes, an `rs.ByteVec` or an `rs.ByteSlice`; `rs.StrCow` for text, the `rs.String` it owns or an `rs.Borrowed` holding the string it borrows, whose text `rs.strCowStr` reads |
| `&T`, `&mut T`, `Box<T>`, `Reverse<T>`, `NonZero<T>`, `AssertUnwindSafe<T>` | the value; a `&mut` to a value JS copies, such as a number, an `Option`, or a reference, or to an `Arc`, a `Waker`, or a `LocalKey`, whose copies share what it points at, is an `rs.Place<T>`, which for what a box holds is the place holding the box |
| `*const T`, `*mut T`, `NonNull<T>` | what a `&mut T` is: the object, an `rs.Slice` of a `[T; N]`'s elements or an `rs.ByteSlice` of a `[u8; N]`'s bytes, which compares by the array or buffer and offset they are at, refused for an array of one, which `array::from_ref`, `from_mut` of a variable, and `Option::as_slice` make of their own, or an `rs.Place<T>` to a value JS copies and to a library type such as a `Vec` or an `Arc`, which into an array, slice, or `Vec` is the `rs.AtIndex` of its element, which `add`, `sub`, `offset`, their wrapping forms, `offset_from`, `ptr::copy`, `write_bytes` of bytes, and `slice::from_raw_parts` move, measure, copy between, set, and view; one to a value in no array is element 0 of an array of one, as in Rust, but a byte variable whose `&raw` the body takes, or that of a reference to it made there, as `&mut b as *mut u8` does, is element 0 of a `Uint8Array` of its own, which its raw, mutable, and shared slices view as they do any other bytes; JS keeps an array of one, and a shared subslice of a byte in no array, which JS copies, apart from what holds it in Rust, so a pointer, slice, copy, or write of bytes the body shows reaching past either, and `offset_from` between pointers the body shows JS keeps in different arrays, are refused, and through a pointer from elsewhere any of these, a raw or mutable slice of a byte in no array, such as a field's, or a read or write past the array JS keeps it in but for a `Vec`'s room up to its capacity, fails at run time; a pointer into an array of values JS keeps as objects is refused, as is comparing pointers to other values JS copies, each a place JS makes of its own; `rs.NULL` for null and `rs.DANGLING` for dangling. `str::as_ptr` points into the text's UTF-8, which JS encodes anew at each call, so a read through it reads what Rust's does and a write, or a mutable slice, through it, which Rust forbids, fails at run time, as do a read before its first byte, such as a substring's pointer moved back into its text's bytes, and `offset_from` between two calls' pointers, each refused where the body shows it. A pointer to a slice cast to one to an array of its elements is the `rs.Slice` or `rs.ByteSlice` of that many from its first, read through only where Rust reads. A `*const ()` is an identity, such as a waker's data, and `rs.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A pointer to a value JS keeps as an object cast to one, by `as` or `cast`, is the same object, which `rs.ptrErase` notes the type of, so a cast back to a pointer to another type fails at run time, and null and dangling stay so, dangling at the alignment of the type it was cast from; one to a value JS copies is the same place where an `Arc`'s or `Rc`'s `into_raw` or `as_ptr` gave it, its value's one place, which `rs.arcErase` checks where the body doesn't show it, and refused where the body shows a borrow's, a new place each borrow, as is casting one to a view of bytes, a new one each borrow, or one of no fixed size. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, the state an `rs` class such as `rs.LazyCell` keeps private included, so a pointer to a part kept as an object, such as a field of a tuple or struct type, is refused wherever the crate may put another object there while a pointer into that memory may still be read, which a write into a fresh allocation, or a variable before any pointer into it is taken, can't, whether by index or through std's iterators over its slots; a read copies what the crate writes into in place |
| `*const T`, `*mut T`, `NonNull<T>` | what a `&mut T` is: the object, an `rs.Slice` of a `[T; N]`'s elements or an `rs.ByteSlice` of a `[u8; N]`'s bytes, which compares by the array or buffer and offset they are at, refused for an array of one, which `array::from_ref`, `from_mut` of a variable, and `Option::as_slice` make of their own, or an `rs.Place<T>` to a value JS copies and to a library type such as a `Vec` or an `Arc`, which into an array, slice, or `Vec` is the `rs.AtIndex` of its element, which `add`, `sub`, `offset`, their wrapping forms, `offset_from`, `ptr::copy`, `write_bytes` of bytes, and `slice::from_raw_parts` move, measure, copy between, set, and view; one to a value in no array is element 0 of an array of one, as in Rust, but a byte variable whose `&raw` the body takes, or that of a reference to it made there, as `&mut b as *mut u8` does, is element 0 of a `Uint8Array` of its own, which its raw, mutable, and shared slices view as they do any other bytes; JS keeps an array of one, and a shared subslice of a byte in no array, which JS copies, apart from what holds it in Rust, so a pointer, slice, copy, or write of bytes the body shows reaching past either, a read or write it shows one past a value in no array, a pointer it shows moved from one by an offset, wrapping or not, or a copy, write, or slice of a count or length, it doesn't fix, and `offset_from` between pointers the body shows JS keeps in different arrays, are refused, and through a pointer from elsewhere any of these, a raw or mutable slice of a byte in no array, such as a field's, or a read or write past the array JS keeps it in but for a `Vec`'s room up to its capacity, fails at run time; a pointer into an array of values JS keeps as objects is refused, as is comparing pointers to other values JS copies, each a place JS makes of its own; `rs.NULL` for null and `rs.DANGLING` for dangling. `str::as_ptr` points into the text's UTF-8, which JS encodes anew at each call, so a read through it reads what Rust's does and a write, or a mutable slice, through it, which Rust forbids, fails at run time, as do a read before its first byte, such as a substring's pointer moved back into its text's bytes, and `offset_from` between two calls' pointers, each refused where the body shows it. A pointer to a slice cast to one to an array of its elements is the `rs.Slice` or `rs.ByteSlice` of that many from its first, read through only where Rust reads. One made from a reference, by `&raw const *r`, `as`, `ptr::from_ref` or `from_mut`, or `NonNull::from`, is where the body shows the reference borrowed, as the `rs.AtIndex` of the element `&v[i]` lends, and else a place of its own: holding the value of a shared reference, which nothing may write while the pointer lives, or an `rs.placeIn` writing a whole value into the object a `&mut` is in place. A `*const ()` is an identity, such as a waker's data, and `rs.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A pointer to a value JS keeps as an object cast to one, by `as` or `cast`, is the same object, which `rs.ptrErase` notes the type of, so a cast back to a pointer to another type fails at run time, and null and dangling stay so, dangling at the alignment of the type it was cast from; one to a value JS copies is the same place where an `Arc`'s or `Rc`'s `into_raw` or `as_ptr` gave it, its value's one place, which `rs.arcErase` checks where the body doesn't show it, and refused where the body shows a borrow's, a new place each borrow, as is casting one to a view of bytes, a new one each borrow, or one of no fixed size. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, the state an `rs` class such as `rs.LazyCell` keeps private included, so a pointer to a part kept as an object, such as a field of a tuple or struct type, is refused wherever the crate may put another object there while a pointer into that memory may still be read, which a write into a fresh allocation, or a variable before any pointer into it is taken, can't, whether by index or through std's iterators over its slots; a read that moves a value out, by `ptr::read`, `replace`, `swap`, or `copy`, copies each object it holds at any depth that the crate writes into in place, a library object such as a `RefCell` or a `Vec<u8>` one object deep, with what a cell, lock, or range holds inline, and one with interior mutability, such as a `Cell`, always; a collection whose JS object keeps its length with its storage, such as a `Vec` of other than bytes, a `VecDeque`, a `String`, a map, or a set, which no copy splits from the original as Rust's read does, and any other library object such as a `LazyCell` or a `Peekable`, whose inline state only its runtime class knows, are refused where the read would copy them |
| `MaybeUninit<T>` | `T`: `undefined` until written, `0` for a byte, or an object whose parts kept as objects are there, holding `undefined`, as `Box::new_uninit` and each of `Box::new_uninit_slice`'s is; a slice's `write_clone_of_slice` clones into its slots without dropping what they held. `Box::new_zeroed`'s holds the value of zero bytes in each part they are one of, such as a number, `false`, `None`, a null pointer, or an enum's variant of a tag or niche of zero, and `undefined` in each part they are none of, such as a reference, for a write to fill before a read |
| `ManuallyDrop<T>` | `T`, which nothing drops but its own `drop`; its `Debug`, comparisons, and constants are refused |
| `union` | an object of slots named by offset, `at0` and `at8`, each holding the field part kept there; fields must overlap in the same type, or in a non-null pointer and an `Option` of it |
Expand Down
20 changes: 3 additions & 17 deletions ts/fixtures/census/census.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
# Census of `census-fixture`

- Refusals: 13
- Refusals: 9
- Function instances: 6
- Generic functions no instance reached, lowered over their type parameters: 1

## By construct

| Count | Construct | First |
| ---: | --- | --- |
| 4 | a raw pointer to `_` behind a reference, which is the object and not where it is kept | fixtures/census/src/lib.rs:9:2 |
| 3 | a cast from `_` to `_`, between a pointer and an integer | fixtures/census/src/lib.rs:9:2 |
| 2 | a cast from a pointer to `_` to one to `_`, which reads the bytes of one type as another | fixtures/census/src/lib.rs:19:12 |
| 2 | a mutable static, which any code may write | fixtures/census/src/lib.rs:38:3 |
Expand All @@ -21,41 +20,28 @@ The type or module each refused type or path belongs to.

| Count | API | First |
| ---: | --- | --- |
| 4 | `u32` | fixtures/census/src/lib.rs:9:2 |
| 3 | `usize` | fixtures/census/src/lib.rs:9:2 |
| 2 | `u64` | fixtures/census/src/lib.rs:19:47 |
| 2 | `u32` | fixtures/census/src/lib.rs:19:12 |
| 2 | `u8` | fixtures/census/src/lib.rs:19:12 |
| 1 | `*const T` | fixtures/census/src/lib.rs:14:2 |
| 1 | `*const bytes::Bytes` | fixtures/census/src/lib.rs:45:2 |
| 1 | `*const u32` | fixtures/census/src/lib.rs:9:2 |
| 1 | `Bits` | fixtures/census/src/lib.rs:28:1 |
| 1 | `bytes::Bytes` | fixtures/census/src/lib.rs:45:2 |
| 1 | `u64` | fixtures/census/src/lib.rs:19:47 |

## By type or path

| Count | Construct | Type or path | First |
| ---: | --- | --- | --- |
| 2 | a raw pointer to `_` behind a reference, which is the object and not where it is kept | `u32` | fixtures/census/src/lib.rs:9:2 |
| 1 | a cast from `_` to `_`, between a pointer and an integer | `*const T`, `usize` | fixtures/census/src/lib.rs:14:2 |
| 1 | a cast from `_` to `_`, between a pointer and an integer | `*const bytes::Bytes`, `usize` | fixtures/census/src/lib.rs:45:2 |
| 1 | a cast from `_` to `_`, between a pointer and an integer | `*const u32`, `usize` | fixtures/census/src/lib.rs:9:2 |
| 1 | a cast from a pointer to `_` to one to `_`, which reads the bytes of one type as another | `u32`, `u8` | fixtures/census/src/lib.rs:19:12 |
| 1 | a cast from a pointer to `_` to one to `_`, which reads the bytes of one type as another | `u64`, `u8` | fixtures/census/src/lib.rs:19:47 |
| 1 | a raw pointer to `_` behind a reference, which is the object and not where it is kept | `bytes::Bytes` | fixtures/census/src/lib.rs:45:2 |
| 1 | a raw pointer to `_` behind a reference, which is the object and not where it is kept | `u64` | fixtures/census/src/lib.rs:19:48 |
| 1 | union `_`, whose fields overlap in `_` and `f64`, which JS keeps apart | `Bits`, `u32` | fixtures/census/src/lib.rs:28:1 |

## Spans

<details><summary>a raw pointer to `_` behind a reference, which is the object and not where it is kept (4)</summary>

- fixtures/census/src/lib.rs:9:2: a raw pointer to `u32` behind a reference, which is the object and not where it is kept
- fixtures/census/src/lib.rs:19:13: a raw pointer to `u32` behind a reference, which is the object and not where it is kept
- fixtures/census/src/lib.rs:19:48: a raw pointer to `u64` behind a reference, which is the object and not where it is kept
- fixtures/census/src/lib.rs:45:2: a raw pointer to `bytes::Bytes` behind a reference, which is the object and not where it is kept

</details>

<details><summary>a cast from `_` to `_`, between a pointer and an integer (3)</summary>

- fixtures/census/src/lib.rs:9:2: a cast from `*const u32` to `usize`, between a pointer and an integer
Expand Down
Loading