julia-script / julia-script/silk
native: a Vector moved through a loop and borrowed afterward reads stale storage
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 48
- Forks
- 0
- Avg merge
- 4h 49m
- Merged PRs (30d)
- 213
Description
Problem
A Vector moved through an effectful helper, assigned back inside a loop, and borrowed after the
loop produces different results across engines.
The program is valid Silk. The bootstrap evaluator and direct WebAssembly read all three appended
bytes. Native LLVM reads stale vector state.
Reproduction
import silk.core { Allocator, OutOfMemoryError, SystemAllocator }
import silk.effects as Effect
import silk.u32 as u32
import silk.u8 as u8
import silk.usize as usize
import silk.vector {
Vector,
append as vectorAppend,
asSlice as vectorAsSlice,
make as vectorMake
}
effect fn push(
buffer: Vector<u8>,
value: u8
) -> Vector<u8> ! OutOfMemoryError ? &mut Allocator {
let mut local = move buffer
let appended = run vectorAppend<u8>(&mut local, value)
return move local
}
effect fn encode() -> usize ! OutOfMemoryError ? &mut Allocator {
let mut bytes = vectorMake<u8>()
let mut index = usize.ZERO
while index < 3 {
let extended = run push(move bytes, u32.toU8(97))
bytes = move extended
index = index + usize.ONE
}
return vectorAsSlice<u8>(&bytes).length
}
effect fn program() -> i32 ! OutOfMemoryError {
let mut allocator = SystemAllocator.make()
let length = run encode() |> Effect.provideMut(&mut allocator)
return usize.toI32(length)
}
effect fn recover(error: OutOfMemoryError) -> i32 { return -1 }
pub fn main() -> i32 {
return run Effect.catchAll(program(), recover)
}
Current result
On current main, the program analyzes without diagnostics.
| Engine | Result |
|---|---|
| Bootstrap evaluator | 3 |
| Direct WebAssembly | 3 |
| Native LLVM | 1 |
The original report observed 0 on native. The exact stale value has changed, but native still
disagrees with the other engines and with the source semantics.
Expected behavior
bytes = move extended updates the loop-carried Vector value. After the loop, borrowing
&bytes must observe the vector returned by the final iteration. Every engine must return 3.
Returning the vector immediately is not a substitute. The important case is a post-loop borrow,
because that is where native lowering currently observes stale state.
Control cases
The regression should also cover:
- appending directly through
&mut bytesinside the loop; - moving the vector through
pushand returning it immediately after the loop; - moving it through
push, then reading bothlengthand one appended element after the loop; - zero, one, and several loop iterations.
All controls and the reproduction must agree across the evaluator, native LLVM, and direct
WebAssembly.
Scope correction
This issue originally bundled a second WebAssembly report about comparing two live owned String
values. That trigger no longer reproduces: both the direct String.copy("abc") comparison and the
normalized-owner comparison now return 42 in the evaluator and direct WebAssembly. This issue
retains only the still-live native loop-carried ownership defect.
Acceptance criteria
- The reproduction returns
3on the evaluator, native LLVM, and direct WebAssembly. - The post-loop borrow observes the value assigned by the final loop iteration.
- Tests assert the returned value, not only successful compilation.
- Mixed iteration counts cover loop entry, back-edge, and exit state.
- Direct-mutation and immediate-return controls continue to work.
- The regression identifies the relevant loop-carried MIR/LLVM value so a stale pre-loop owner
cannot be selected silently.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied reproduction through the bootstrap evaluator, native LLVM, and direct WebAssembly paths, then inspect the loop-carried MIR/LLVM value mentioned in the acceptance criteria. Add regression coverage for zero, one, and several iterations plus the direct-mutation and immediate-return controls; done means every path returns 3 and post-loop reads see the final assignment.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, wasm
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100