Skip to content

qs parse: stale from-space array pointer in js_dyn_index_set_strict (latent on main; wrong checksum when allocation timing shifts) #11550

Description

@proggeramlug

Summary

benchmarks/packages/qs/parse_nested.ts (qs 6.16.0) holds a stale from-space array pointer across an evacuating minor. The stale use is js_dyn_index_set_strict → js_array_set_f64_extend_strict_impl, called from qs's lib/parse.js. On main it is latent: a plain run happens to print the right checksum. Under a seeded schedule with from-space protection it faults on 5 of 6 seeds. With any runtime change that shifts allocation timing, it becomes a wrong answer on a plain run: a different wrong checksum each run, with no crash.

Reproduce (Linux x86-64, main at c1d93bb, release build)

cd benchmarks/packages && npm ci
PERRY_NO_AUTO_OPTIMIZE=1 PERRY_KEEP_SYMBOLS=1 perry compile qs/parse_nested.ts -o qs_parse_nested
PERRY_GC_PROTECT_FROMSPACE=1 PERRY_GC_PROTECT_FROMSPACE_DEPTH=64 PERRY_GC_SCHEDULE_SEED=7 ./qs_parse_nested 3000 1000
[gc-fromspace-protect] FAULT: signal 11 at 0x3e9972d2dbc
  This address is RETIRED FROM-SPACE. The evacuating minor moved or
  freed the object here and the holder kept the pre-collection address.
  block=0x3e9972c0000 +77244 retired_bytes=84960 retired_by_minor=#24
  last-known object: user_ptr=0x3e9972d2db0 obj_type=3 size=32
#0 perry_runtime::array::indexing::js_array_set_f64_extend_strict_impl
#1 js_dyn_index_set_strict
#2 perry_closure_node_modules_qs_lib_parse_js
#3 perry_closure_node_modules_qs_lib_parse_js
#4 perry_closure_node_modules_qs_lib_parse_js
#5 js_native_call_value
...
#10 perry_fn_qs_parse_nested_ts.op

Seeds 1, 7, 42, 99 and 123 fault; seed 555 completes (1,031 copying minors, 362,457 moved objects).

Wrong answer without the instrument

With a runtime whose allocation timing differs from main's, a plain ./qs_parse_nested 3000 1000 prints a wrong checksum in 9 of 12 runs, and a different one each time. Node 26.5.1 prints checksum fa2bbd09. The branch that showed this is wip/protochain-keyconv. It also fails with its only cache disabled (PERRY_INHERITED_IC=0), and the stale use above is on main. Base main was correct 12 of 12 on the plain run. Any qs instruction-count A/B is untrustworthy until this is fixed, because a timing change can flip the output.

Found while measuring the prototype-chain lane (#10495). The obj_type 3 target and the extend-store frame point at the dynamic-index store path (#10513 / #10694 neighbourhood), not the property path.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions