ReviewOS

zig-utils/zig-js

Intl: construct cached bound accessors without transient generic-bind storage

#648
Closed chris opened this 9 days ago ·
9 days ago

Parents: #475, #641 Related: #640

Problem

Fresh Linux unit evidence after #641 shows Intl.DateTimeFormat resolved state is reclaimed under a bounded precise heap escaping with OutOfMemory. The exact stack is not in DateTimeFormat structural-part storage: it reaches Interpreter.makeBound through intlBoundAccessorFn while reading formatter.format.

The Intl accessor already knows the required cached callable metadata: ECMA-402 specifies an empty name and fixed length, and the formatter instance caches that callable. It nevertheless constructs a full generic Function.prototype.bind result first, reads the implementation name/length, allocates a transient "bound " + name, publishes those generic properties, and then overwrites them with the Intl metadata. Repeated formatter churn makes that avoidable path part of the bounded-heap attack surface.

Required implementation

  • Give bound-function construction an exact metadata path that publishes the final name and length once.
  • Keep generic Function.prototype.bind observable behavior and ordering exact.
  • Use the exact path for Intl NumberFormat/DateTimeFormat format and Collator compare accessors.
  • Preserve per-instance identity caching, hidden property attributes, GC relocation/tracing, and OOM rollback.
  • Do not raise heap limits, reduce witness iterations, or bypass the accessor.

Acceptance

  • Focused tests prove generic bind metadata/coercion behavior is unchanged and Intl accessors retain exact name, length, identity, and call behavior.
  • Allocation-failure coverage proves no partially cached bound accessor is observable.
  • The unchanged 4 MiB DateTimeFormat bounded witness passes on Linux and locally, normally and under TSan.
  • NumberFormat, DateTimeFormat, and Collator unit/Test262 surfaces have zero regressions.
  • Full unit and TSan shards are leak/race free.

CI evidence: run 32365143787, unit shard 0/4, job 96413010000. The failure occurs at src/interpreter.zig:7291 from intlBoundAccessorFn.

9 days ago

Implemented in 7f4557d8. Intl bound accessors now publish one exact hidden cache entry atomically and construct their immutable name/length metadata without generic bind scratch. Local evidence: focused normal and TSan suites passed 2/2 with 0 leaks/races; the unchanged 4 MiB DateTimeFormat witness passed normal and TSan; bind/proxy-ordering probes passed; Test262 Intl subtrees passed NumberFormat 249/249, DateTimeFormat 244/244, Collator 65/65 (558/558). Fresh Linux unit/TSan validation: CI run 32369900898.

9 days ago

Fresh Linux reached past the exact bound-accessor construction and exposed a distinct later allocation boundary in DtfOutput.parts; full stack and renewed acceptance work are tracked by reopened #641. The generic bind scratch path fixed here is no longer on the failure stack. Keeping #648 open until #641 restores the unchanged 4 MiB end-to-end witness and the relevant TSan shard completes.

9 days ago

Closing after #641 restored the unchanged 4 MiB end-to-end witness. Fresh Linux unit shard 1 and TSan unit shard 1 both passed with zero failures/leaks; the transient generic-bind path no longer appears at the allocation boundary. Test262 flips remain 0.

Sign in to comment on this issue.