RFC dan proposal mencatat rancangan. Untuk kemampuan yang benar-benar dapat dipakai, lihat matriks kapabilitas runtime dan catatan rilis.
RFC 0002: Memory, Ownership, and Unsafe Boundaries
Status: Accepted
Areas: Appendix G.1, G.3; Appendix H.4, H.5, H.7
Depends on: RFC 0001 for value and error types
Decision: Accepted by the project owner on 2026-10-23. Acceptance approves the design direction; it does not mean implementation or conformance is complete.
Implementation status: Partial. The native runtime now has bounded internal program and per-request arenas, checked allocation accounting including allocator headers, explicit promotion of in-memory CRUD records into the program arena, and cleanup on request completion paths. The allocator unit harness passes normally and under ASan/UBSan; full CRUD/slow-client/timeout smoke passes under ASan/UBSan; and the latest 100,000-request API run retained its CRUD record with 0 KiB sampled RSS growth (10,800 KiB baseline and peak, at 1 KiB ps resolution). The compiler now supports explicit defer direct_call(...) cleanup for lexical scope exits and ?, verified for captured argument order and control flow; the PostgreSQL scope guard uses it for rollback, and HTTP tests verify secret zeroization after success and error returns. This is an explicit cleanup hook, not automatic destruction tied to ownership. These runtime arenas and cleanup hooks do not implement YAZA-level ownership, moves, borrows, destructors, reference counting, length-carrying Text, or end-to-end memory safety. The acceptance criteria below are not met.
Summary
Specify memory-safe ownership for generated native programs and make the current C runtime's trust boundary explicit. Use move semantics for uniquely owned values, checked borrows for temporary access, and reference counting only for explicitly shared immutable values. Runtime request arenas may be used internally as an optimization, but are not a substitute for language ownership.
Motivation
The compiler currently emits C and uses C strings and manual allocation. It has no general ownership checker, destructor semantics, borrow rules, or memory-safe proof boundary. Sanitizers can find some defects but cannot make unsafe behavior impossible.
Proposal
- Trivial scalar values are copied. Heap-owned values have one owner and are moved on assignment/return unless explicitly borrowed.
- Function parameters and receivers state their access: read-only borrow by default for non-trivial values,
editfor exclusive mutable borrow, andmovefor ownership transfer. - A mutable borrow is exclusive for its full lexical lifetime. A value cannot be moved or destroyed while borrowed; the compiler rejects overlapping mutable borrows and use-after-move.
- Shared heap data uses atomic reference counting only through an explicit shared immutable handle. Shared mutable state requires a synchronization type and cannot be accessed through ordinary mutable borrows.
- A shared trait object is written explicitly as
Shared[dyn Trait + Sendable]; trait-object aliases may be introduced only after repeated use demonstrates a need.Sendablemeans the value is safe to transfer/share across tasks under the ownership and synchronization rules. - Cyclic shared ownership is not allowed in the first design. Weak references and cycle collection are deferred.
- Destructors run exactly once when an owned value leaves scope or the final shared reference is released. Destructors cannot throw; fallible cleanup must be an explicit method returning
Result. Textis an immutable pointer-plus-length UTF-8 value;Bytesis a pointer-plus-length byte buffer. APIs use length-aware operations and never infer size with repeatedstrlen. Invalid UTF-8 is rejected at text construction; arbitrary bytes stayBytes.- Indexing and slicing are bounds checked by default. An unchecked operation requires an
unsafeblock and a documented safety justification. unsafeis opt-in per expression, forbidden by default in safe packages, reported byyaza audit, and requires aSAFETY:explanation. FFI declarations are unsafe at the boundary and must define ownership, aliasing, threading, and error behavior.- The native runtime is part of the trusted computing base. Until it is memory-safe by construction or independently validated, YAZA must not claim that safe source guarantees memory safety end-to-end.
Illustrative syntax:
fn name_of(value: &Product) -> Text:
return value.name
fn rename(value: edit Product, name: Text) -> Result[Unit, ValidationError]:
value.name = validate_name(move name)?
return ok(unit)
Runtime allocation policy
The compiler may lower request-scoped temporary objects to an arena only when escape analysis proves that they do not outlive the request. Arena destruction must happen on every success, error, cancellation, and shutdown path. Long-lived values use the ownership rules above. The optimizer must not change observable destructor order.
Security considerations
The model reduces use-after-free, double-free, data-race, and bounds errors only if every safe operation is checked and generated C/runtime helpers uphold the same invariants. A C implementation remains within the security boundary. unsafe cannot be called safe because it carries a comment or lint waiver; independent review and negative tests are required.
Staged implementation
- Pending: Define lifetimes and restrictions in a small subset; add move/borrow diagnostics before adding containers.
- Implement length-aware
TextandBytes, checked slices, and deterministic destruction. - Add immutable shared references and thread-safe synchronization types.
- Partial: The API runtime uses bounded per-request scratch arenas and preserves explicitly retained in-memory records in a separate bounded program arena. Audit or replace memory-sensitive C runtime portions and add fuzzing and sanitizer coverage for all FFI boundaries.
- Partial: Request arenas are reset on handled success, parser-error, auth, CORS, and shutdown paths in the current serial HTTP loop. Cancellation and concurrent request cleanup remain unimplemented.
Acceptance criteria
- A normative ownership chapter and executable conformance tests exist.
- Negative tests reject use-after-move, aliasing mutable borrows, data races through safe APIs, invalid slices, and unsafe code in a safe package.
- Text/Bytes operations preserve embedded NUL for
Bytes, validate UTF-8 forText, and pass fuzz and boundary tests. - Memory-safety claims name the compiler, runtime, FFI, and target assumptions and are reviewed independently.
Open questions
- Should borrows be inferred for read-only parameters or always written explicitly?
- Should atomic reference counting be exposed in source syntax or only through standard-library shared types?
- Which C runtime components must be replaced before any end-to-end memory-safety claim?