fix(qlog): list a hidden stream's records without spreading call arguments (#2860)

* fix(qlog): list a hidden stream's records without spreading call arguments

When an explicit declaration matched a stream's derived total, the
decoder pushed every contribution ordinal with a spread call. A stream
with more than ~125k STREAM frames exceeded the engine's argument limit,
so a valid capture within the input budget failed with RangeError
instead of listing the records as incomplete. Push the ordinals in a
loop.

* fix(comparison): recheck historical calls-only changes (#2223)

* fix(comparison): preserve incomplete function call evidence

Keep missing, unknown, partial and unresolved call relationships unknown in function comparisons and reconstruction claims. Aggregate IDA caller and callee coverage without overwriting uncertainty.

Validate with 144 focused tests, typecheck/lint, docs checks and test discovery. Real providers were not verified; the full headless IDA session suite requires unavailable Windows native controls.

* fix(comparison): recheck historical calls-only changes

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>

* fix(ci): isolate Linux Hopper process fixture inventory

* fix(android): make DEX descriptor pattern portable

---------

Co-authored-by: Lucien <164857476+dakjdakd@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-14 03:05:34 +08:00
1 parent 02095cd74a
commit 39f96d7188
2 files changed
+18 -3

No files matched your search

+15
View File
@@ -186,6 +186,21 @@ it("excludes structural auth material and explicit normalized values without gue
expect(traces[0]?.incomplete_fact_records).toContain(2);
});
it("omits a hidden derived total for a stream with more contributions than call arguments allow", () => {
const events = Array.from({ length: 130 }, (_, index) =>
event(
Array.from({ length: 1_000 }, (_, offset) =>
frame(index * 1_000 + offset, 1),
),
),
);
const { traces } = facts(capture(events), ["130000"]);
expect(traces[0]?.streams).toEqual([]);
expect(traces[0]?.incomplete_fact_records).toEqual(
Array.from({ length: 130 }, (_, ordinal) => ordinal),
);
});
it("hides marked ancestor keys and safe derived sums while still validating hidden subtrees", () => {
const text = capture([event([frame(0, 3), frame(3, 4)])]);
expect(facts(text, ["7"]).traces[0]?.streams).toEqual([]);
+3 -3
View File
@@ -95,10 +95,10 @@ export const decodeQlogCapture = (
...stream.reported_final_sizes,
...stream.covered_ranges.flatMap((r) => [r.start, r.end]),
];
// A stream can have more contributions than call arguments allow.
if (numericValues.some(excluded))
fact.incomplete_fact_records.push(
...stream.contributions.map((c) => c.record_ordinal),
);
for (const contribution of stream.contributions)
fact.incomplete_fact_records.push(contribution.record_ordinal);
else fact.streams.push(stream);
}
fact.incomplete_fact_records = [...new Set(fact.incomplete_fact_records)];