vx-lang / vx-lang/Vx

Region ID 4095 is an overloaded 'unset' sentinel — collides with the narrowed slot-0 field (blocks #265)

Open
#267 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug core-lang
Dominant language
Rust
Stars
14
Forks
2
Avg merge
12h 42m
Merged PRs (30d)
61

Description

Blocks hiraditya/Vx.1#265. Small, but it will silently corrupt region comparisons if missed.

4095 — the maximum value of the 12-bit REGION_MASK (0x0FFF, src/borrow.rs:77) — is in use as an unset / not-yet-assigned region sentinel. It is observable in diagnostics:

struct Map { slot : i32, present : i32 }
fn pass<T>(m : &Map) -> &i32 { return &m.slot; }

fn bad(m : &mut Map) -> &i32 {
  let found = pass<i32>(m);
  return found;
}
Error: Failed to deduce types for generic function 'pass':
  Expected Borrow { inner: Struct("Map", None), mem_space: None, is_mut: false, region_id: 4095 },
  got      Borrow { inner: Struct("Map", None), mem_space: None, is_mut: true,  region_id: 4095 }

Both sides carry region_id: 4095 — not a scope depth of 4095, but "no region assigned."

Why it matters for hiraditya/Vx.1#265

hiraditya/Vx.1#265 narrows slot 0's region field from 12 bits to 9 (REGION_MASK_0 = 0x01FF, max 511) to make room for the 3-bit provenance field. After that change:

  • A stored sentinel of 4095 truncates to 4095 & 0x01FF = 511, which is a legal region value in the narrowed field.
  • verify_subtyping_bounds (src/borrow.rs:93) compares regions with <= / ==. A truncated sentinel would compare as an ordinary very-short-lived region rather than being recognised as unset, so an unset return region would silently satisfy or fail subtyping depending on the other operand.
  • The top 3 bits of the old sentinel (4095 >> 9 = 0b111 = 7) land exactly on PROV_MASK, which hiraditya/Vx.1#265 assigns to FromAnyOf. So an unset region would also decode as "derives from any parameter." That happens to be the conservative value, which is lucky — but it is coincidence, not design, and the region half is still wrong.

Fix options

  1. Reserve a sentinel in the narrowed field — e.g. 511 means unset for slot 0, valid depths 0..=510. Cheapest, keeps everything inline, costs one nesting level.
  2. Move the unset marker into Prov — add a Prov value meaning "region not assigned," and stop overloading the region field for it. Cleaner separation; uses one of the reserved 56 slots.
  3. Assign regions eagerly so no sentinel is ever stored. Largest change; removes the class of bug rather than encoding around it.

Option 2 is probably right: the two facts (which parameter, how long) then live in separate fields and neither has to encode "unknown" for the other.

Work

  • Find every producer of the 4095 sentinel (grep 4095 / REGION_MASK in src/borrow.rs, src/gid.rs, and wherever lower_to_type_id assigns regions).
  • Pick an option and document it in borrow_checker_architecture.md §2 alongside the bit layout, so the next person widening or narrowing a field sees it.
  • Add a unit test asserting a just-below-sentinel region (510) and the sentinel itself compare distinctly through verify_subtyping_bounds, in both the 12-bit and narrowed layouts.

Worth doing before hiraditya/Vx.1#265 rather than during — a subtyping check that is wrong only for unset regions in deeply nested code is exactly the kind of bug that survives a test suite and surfaces as an unexplained accept months later.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing every producer of the 4095 sentinel with searches in src/borrow.rs, src/gid.rs, and the code around lower_to_type_id, then read verify_subtyping_bounds and the bit layout in borrow_checker_architecture.md §2. Choose and document the sentinel representation, add coverage for region 510 and the sentinel in both layouts, and confirm the two cases compare distinctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.