The REG_* macros wrote through the return-type vector without checking
the allocation, and registered entries whose formatted QN came back NULL.
A shared ruby_seed_signature helper now leaves a failed vector out, so the
signature types as unknown (the fallback ruby_register_method already
uses), and REG_METHOD / REG_SMETHOD skip an entry whose formatted name is
NULL, since a NULL QN would reach strcmp in finalize and in every lookup.
rubylsp_stdlib_seed_survives_alloc_failure seeds a registry from an arena
that cannot allocate. Before: UBSan reported a store to a null pointer and
the run crashed with SEGV at ruby_stdlib_data.c:163. After: every
registered entry carries a name, the registry finalizes, and the Kernel
built-ins with literal names still resolve.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
ruby_const_path recursed once per :: segment and re-formatted the growing
prefix at every level, so an A::B::C path cost one stack frame per segment
and quadratic bytes in the per-file arena. It now follows the scope fields
in a loop: one pass measures the segments, a second copies them right to
left into a single buffer. The result is the same string as before,
including a leading ::Foo and a scope that is not a constant path.
rubylsp_const_path_is_linear pins the arena bytes for an 800 vs a 1,600
segment path (before: 494,520 -> 1,660,520 bytes already at 400 -> 800
segments; after: 136,248 -> 150,848 at 800 -> 1,600) and the exact class
QN for a five-level path and for a rooted ::Top::Inner.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The mixin walk recursed into prepend and include at every level with only
the depth cap of 16 as a bound, so a module that both prepends and
includes the next one doubled the paths per level: a miss on a chain of n
such modules cost 2^n visits (measured 4 -> 20,744 for n = 2..14).
Each lookup is now one walk that carries the fail-closed blocked flag and
a visit stamp. Ruby linearizes ancestors, so a module reached a second
time in one walk was already searched and missed (a hit or a block would
have ended the walk); skipping the repeat keeps every lookup linear in the
ancestors the file declares. Lookup order, hits and the fail-closed rules
are unchanged. The stamps live on the per-file class table, so the walk
allocates nothing.
The walk entries feed CBM_LSP_WORK (seam builds only; product builds
compile it to nothing). rubylsp_mixin_walk_visits_each_module_once pins
linear work for the doubled chain on the instance and the class side
(before: 66 -> 4,098 visits for n = 6 -> 12; after: 14 -> 26) and keeps a
diamond and a prepend-plus-include pair resolving exactly once.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The MSan output handler checked msg[0] before marking the text
initialized, so MSan reported the handler's own read
(tests/test_main.c:2151). Unpoison first, then test for the empty
replay.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The "group shrinks" step of doc_links_md_member_missing_incremental
removed one of two Python `area` methods and expected the closure-repair
route. Since the Python namespace admission on main (merged into this
branch with origin/main), a Python file whose surface changes always
takes the full route (closure_decline reason=python_namespace_changed),
so the step ran FORCED_FULL on every platform; the Windows leg was simply
the first to report it. Nothing here depends on timing: the planner
compares content hashes.
The group now lives in a Ruby file. Ruby has no doc-link scope, so the
lost method reports no removed name and the document re-resolves only
through the ambiguous `path::member` rule, which this step exists to
bind. (A Rust group was tried too: its scope reports the method as a
removed name, so the step passed with the rule removed.)
Test: the step takes closure repair with closure=2 (shapes.rb and
docs/areas.md). With "ambiguous" dropped from doc_row_member_reason it
stays on closure repair with closure=1 and keeps the stale ambiguous row
where the full index has the Areas -> Square.area edge.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>