跳转至

Apple IPS static inspection verification — 2026-10-24

Scope

PR #6511 adds portable inspect_apple_ips / inspect-apple-ips over one caller-selected local file. The metadata must identify string bug_type "309"; stackshots and other report kinds remain unsupported. No target is executed, no deep engine starts, and no atos/dSYM lookup is performed. These checks do not qualify live macOS state, symbolication or Mach-O UUID joins.

The source contract preserves integer literals beyond IEEE-754 precision, observed type mismatches and partial coverage. The frame address is derived from its image's base plus its recorded offset, as described in Apple's crash JSON documentation. That documentation does not provide a 64-bit bound for every numeric field; the parser therefore bounds representation cost without truncating values.

Review corrections and ownership

The contributor's 80ad2a02e9c6cbe248d58d78a7a79753bcc09f79 already projects documented JSON members and checks thread/frame/image/register allowances before materializing each row. Unknown members are syntax-checked without retaining their values. Producer controls include a budget error before an invalid next item, wrong-type collections, frame-role cases, and the DEAD10CC decimal near miss. Inline-role assumptions are corrected below. Source inspection alone does not establish the runtime checks below.

Further negative controls expose three remaining boundaries:

  • Two contradictory thread/image coverage reports were accepted by the service. Coverage now agrees with the retained arrays before Evidence is issued. Already cancelled requests also preserve the exact caller reason.
  • A 20,001-digit image base expanded into 512 derived frame addresses despite a small input file. The field reader now owns an 8 MiB default / 64 MiB maximum UTF-16 allowance for recorded decimal/hex fields. Conservative reservations precede conversion and arithmetic. Source BigInts are reused; derived sums are not retained in a cache. Repeated appearances count separately, including a service control using the same object twice.
  • A 20,013-character image architecture appeared 513 times in a 512-frame report. Frames now retain their recorded image_index; architecture, UUID and uuid_unknown belong to the image once. The old per-frame copies and superseded field-access helpers are removed.

Each defect has a failing control before its correction. Raising the integer allowance to 64 MiB preserves the 512-frame decimal facts exactly. The allowance is per call, requires no restart, and is separate from file-size, row, wire and client-buffer limits. Refusal is a typed capacity error without partial success. A refused task is not treated as a completed-task speedup.

Public corpus provenance

Two pinned upstream reports are valid two-object JSON and are used without editing their bytes. Their original generation history has not been verified; these are public repository corpus files, not a claim of fresh OS capture.

Report Repository revision Bytes SHA-256
LLDB multithread-test.ips 16dde0db3ce0b9c5eae14178780cc6db1eec7ac8 16,093 567cadb22af19be798390ab2021ed929fb782c69b2d3b18ff5bb3f39a3741d8c
pycrashreport Monterey report 634dff127fa6d4d3df948a64a3e254fe208a99dc 7,047 7de3d3c3515e2ac1bb6ed4c00b70cb12c1ff6ad4317617d258d58346e00264b7

Three other LLDB inputs (a.out.ips, a.out.inline.ips, no_threadState.ips) contain invalid JSON at their pinned revision. They were not repaired or counted as successful report qualifications. Files remain temporary local verification inputs and are not committed to this repository.

Completed-task comparison

Compare d4930ed57c0b175a632fd8572732b1e88a73cb2f (original IPS behavior with main cc18e9ad provider/API integration repairs) against 135cab1234c3663e839f5fbea6bf833737cd140a. Three alternating pairs of five public CLI tasks complete, 30 tasks total. Every task returns complete coverage. An independent Python JSON/integer oracle checks all ordered images, threads, registers, frame offsets, derived addresses and the then-selected physical-depth roles, as well as process facts and artifact digests. The later source-backed correction below replaces that role assumption; neither public report contains an inline row, so its role expectations remain unchanged. The two public reports contain 3/1 threads, 8/4 images, 30/4 frames and 36/22 retained registers respectively.

Every Evidence field agrees after excluding the changed Evidence ID, the new default allowance parameter and the removed per-frame copies. Before excluding those copies, the oracle verifies each against its owning image. Image facts, uncertainty, other report fields, provenance, coverage and limitations remain equal. Artifact digests are unchanged across all runs.

Complete CLI task Estimated stdout + invocation tokens, before → after Elapsed median s CPU median s Sampled family RSS median MiB
Small synthetic report 934 → 923 2.069 → 1.969 2.309 → 2.212 368.8 → 369.6
LLDB multithread report 6,500 → 5,851 3.180 → 2.878 2.292 → 2.340 370.4 → 373.5
Monterey report 2,377 → 2,309 3.330 → 3.029 2.230 → 2.208 369.6 → 368.8
20,001-digit base / 64 frames 402,476 → 401,783 2.725 → 2.879 2.354 → 2.319 375.1 → 371.8
Long image architecture / 512 frames 1,760,820 → 41,023 3.231 → 2.928 2.468 → 2.261 387.3 → 372.7

The long-image task reduces estimated whole-task context by 97.67% while preserving joined facts. Ordinary reports save less. No latency speedup is claimed: elapsed ranges overlap, including the long-image ranges 2.070–3.381 s before and 2.928–3.633 s after. Small-report ranges reach about 9.2 s in both lanes during shared-host contention. The wide-integer elapsed median rises about 0.154 s, while its CPU and sampled RSS medians decrease slightly. Three pairs do not establish universal performance or maximum-capacity behavior.

Each task uses a fresh Node 24.22.1 CLI/provider process, with CPU affinity 0,1. OS caches were not flushed; these are fresh-process runs with uncontrolled warm filesystem caches, not measured cold-disk runs. No result cache or persistent provider session participates. Warm long-lived process behavior is unmeasured. Tokenx 1.3.0 estimates the entire Evidence stdout and invocation; these are estimates, not billed/model token counts. The analyst already knows the single CLI command, so no discovery, paging or extra lookup call is required. Image metadata is inline in the same result. MCP catalog costs, prompts, framing, rendering and client JSON parsing are unmeasured.

CPU is waited-child user plus system time. RSS is a 50 ms recursive process-family sample; it can double-count shared pages and miss short-lived or unobserved descendants. Token estimation and the oracle run outside the timed command. Later main integrations are outside these pinned timings.

Synthetic recipes: small.ips has one frame/register; wide-integer.ips uses base 10^20000, 64 frames with image offset 1; wide-image-text.ips uses architecture unknown_arch_ plus 20,000 x characters and 512 frames. Their SHA-256 values are respectively 1178a013b86f8a6c11abef633fdee5fefd23e010c4af92710321cb0f369ed857, b455598694d9953031e52450f1a4a6655e16abd683a2cec59e393899883b6994, and 4d3d2f3e4946cbbeed7e14e1f12cd97bd2f119af1b3a33496dd3e8d079c3f999.

Final integration checks

Main cd10ee1f8a8e124be4864e77750a16e76c561809 integration passes 167 selected domain/service/parser/filesystem/CLI/MCP/shared lifecycle checks in 74.312 s (80.355 s waited-child CPU; 1,902.0 MiB sampled family peak). Full npm run check, npm run docs:check and test discovery pass. All 2,324 test files are discovered exactly once. Earlier source selections overlap these checks. Two initial public-error assertions placed remediation at the wrong level; the tests now check the existing top-level error contract. No production error shape was changed to accommodate them.

Both pinned public reports additionally pass through the actual stdio MCP server and SDK client, with the advertised input/output JSON Schemas validated in AJV 2020. The same independent oracle checks their returned facts. The client explicitly admits a 64 MiB receive buffer for the complete tool catalog; this does not qualify every client's default buffer. Target execution and symbolication remain unverified. The 30-task cost table remains pinned to its recorded revisions, without reusing these integration costs as speed evidence.

Integration after PE imports

The following integration includes main 4ef916da03d93729041f79cec0ee243cd2d3097d and the newly merged PE imports tool. The documentation index retains links to both static formats. Full static/docs/discovery gates pass, together with 191 selected checks, including the upstream native-plist cleanup test. The selection takes 49.939 s, 52.461 s waited-child CPU and 2,079.8 MiB sampled family RSS. It overlaps earlier selections and is not a performance comparison.

Previous-head CI run 40058145277 had one functional failure in nativePlistFileCleanup.test.ts, repeated by the aggregate lane; seven other shards were cancelled. Exact main d662fa54a67bf24bd4800d1867231662019d91c6 and actual CI merge 440029745397d78103a623fd1fd91cfa09fc6df5 each reproduce 11 passing / 1 failing cases with identical statuses and normalized failure messages. The failing test and selected producer sources are byte-identical. The subsequent main integration fixes that closing race, and all 12 cleanup cases pass within the 191 checks. Cancelled CI coverage was not executed.

Follow-up string capacity and identity review

Baseline 45a570656cb3b9a7a8bf41302e1f01f8662bc884 and candidate 6fa8083fc6974bc18c7d227ded33db28eb590f03 isolate three further corrections:

  • Retained JSON strings are syntax-checked by the same scanner used for skipped strings, then escaped literals are decoded by the native JSON string parser. Unescaped strings retain the slice fast path. The superseded per-escape fragment array is gone; decoded length is bounded by the selected input's literal length. Malformed escapes and controls still fail before projection.
  • UUID interpretation owns format validation before canonicalization. Both 32 hexadecimal digits and canonical hyphenation are accepted. Malformed nonempty spellings remain in coverage.type_mismatches[].recorded_value, canonical identity stays unknown and coverage becomes partial. Absent UUIDs and the documented all-zero unknown sentinel remain distinct from that malformed-value outcome. The field uses the existing exact-optional contract convention; it does not admit an explicit JavaScript undefined value.
  • metadata.bug_type is literal "309" in the domain and advertised schema. The service rejects unsupported reports from defective/custom ports too.

Seven new cases failed against the earlier production code: four malformed UUID spellings, two unsupported port kinds and a public CLI capacity case. The latter selects a file below the 16 MiB allowance containing 7,500,000 newline escapes. Earlier decoding exhausts a 256 MiB Node old-space limit; the corrected CLI completes with every character verified by length and SHA-256. This is an old-space setting, not a 256 MiB total RSS claim.

The first expanded run passed 182 of 183 cases; the advertised-schema MCP case hit its 30-second test deadline. Its isolated two-case file then passed, and the expanded schema assertions passed again. After switching to the final exact-optional representation, both MCP cases passed once more: actual SDK schemas reject a forged bug_type: "288" and admit the partial result with its exact malformed UUID spelling. check:fast passed. The two public crash reports also passed again through an actual stdio MCP client and Ajv2020.

Twelve further completed CLI tasks used three alternating pairs for the same public LLVM report and a generated 4,000,063-byte report containing 2,000,000 newline escapes (SHA-256 5c4a9282da37091973774bf98c6822caeecbc1d74d7c44cd4eda1937ad05e350). Every complete Evidence field, including IDs, is identical within each case. The escape case explicitly selects an 8 MiB read allowance; both revisions complete under the same default 2 GiB old-space task environment.

Completed task Estimated tokens, both revisions Elapsed seconds, before → after CPU seconds, before → after Peak family RSS MiB, before → after
LLVM public report 5,851 2.071 → 1.970 2.378 → 2.328 365.3 → 366.0
2,000,000 escapes 4,000,703 2.425 → 2.374 2.457 → 2.289 459.3 → 372.1

Values are medians. Escape-case elapsed ranges overlap: 2.120–2.930 seconds before and 2.324–2.424 after, so no elapsed-time improvement is established. Its CPU ranges are 2.318–2.521 versus 2.245–2.297 seconds; sampled peak RSS ranges are 457.4–462.9 versus 371.5–372.9 MiB. The measured dense-escape task reduces median CPU by 6.8% and sampled memory by 19.0%; those observations are specific to this case. LLVM ranges overlap and show no general speed gain. Complete output and estimated tokens are unchanged.

Tokens use tokenx 1.3.0 estimates for the invocation plus all stdout, not model billing. These are known CLI tasks with existing inputs, fresh processes and warm OS caches. Input creation, cold disk, discovery, client parsing, prompts, schemas, MCP envelopes and retries are outside that comparison. The same 50 ms descendant RSS sampling and waited-child CPU limitations above apply. Later main integration is not part of these cost measurements.

Final public MCP workflow and main integration

Main 21a20306b4887ff8e6b614b6ae34a387cfbdf1d8 was integrated in 6d77f265027d34154145e807b1a5c8fd26a1e567. Its static/documentation checks and discovery of all 2,339 test files passed. The combined 183-case selection again reached the in-memory MCP test's 30-second deadline while its other 182 cases passed. Isolated passes did not establish that the setup was robust under the combined run.

The MCP test now exercises the compiled production stdio entrypoint through the existing local-tools fixture, which owns client/transport cleanup and validates the SDK-advertised schemas. It no longer reconstructs the full source server/catalog inside the shared test worker. One public workflow retains all the prior schema, annotation, capacity, register, malformed-UUID and relative-path assertions; the redundant second connection case was consolidated. No test deadline was increased. The same combined selection then passed all 182 cases, including the large escaped-text CLI case and all producer/service regressions. This is stronger public-path verification, not a claimed runtime speedup from a before/after test-suite timing comparison.

Reference and inline review follow-up

Commit 174c7496a2f007a1ef0ab5da0a341b2f801277c3 separates a recorded uint32 lookup from whether it resolves to an object row. An out-of-range or malformed faultingThread reference preserves the lookup, marks coverage partial and leaves row-zero roles unknown. Image lookups use the same owner; unresolved image references preserve image_index and leave the derived address unknown. Negative or oversized integer lookups retain their exact literal in coverage.type_mismatches[].recorded_integer. Reservation happens before retention, and the service counts these literals against the same integer-text allowance even for custom ports. No BigInt conversion is needed for rejected indexes.

The previous comment and guide incorrectly asserted that inline rows share a subsequent physical row's address. Apple's per-frame imageOffset description and the pinned LLDB parser support each row's own base-plus-offset; that parser increments its frame index for every recorded row. REA therefore keeps its existing address derivation, leaves a missing offset unknown and corrects roles to use the recorded row index. The inline flag remains recorded evidence and does not reconstruct a physical stack. This is source-derived validation; LLDB was not executed.

Nine source controls fail before this correction: two in-range-but-unresolved faulting indexes, a reference to a malformed thread row, three rejected integer spellings, the 19-byte rejected-literal allowance, unresolved image coverage and the corrected row-role oracle. A separate differing/missing-inline-offset case already passes before the correction and protects the existing address rule; it is not evidence of a fixed address bug. All 193 selected checks pass afterward, including CLI, filesystem, custom-provider allowance checks and production stdio MCP. The actual SDK validates retained lookup literals against the advertised schema. check:fast, complete formatting, documentation and cached build also pass. Both pinned public reports pass the real stdio SDK/Ajv workflow again (13.510 s elapsed, 14.909 s waited CPU, 907.4 MiB sampled family RSS); the independent integer/JSON oracle checks the CLI comparison below.

Six completed alternating CLI tasks compare the prior actual CI tree acb837583d8346016fd8b46d4fcf1fdf09fb0b06 with the corrected commit on the pinned LLDB multithread report. All full Evidence, including IDs, agrees. Estimated invocation plus full stdout tokens remain 5,851 (tokenx 1.3.0). Elapsed medians are 2.071 -> 1.969 s (ranges 2.071–2.271 / 1.919–2.069), CPU 2.295 -> 2.278 s (2.140–2.471 / 2.231–2.283), and sampled process-family RSS 366.8 -> 367.0 MiB (348.2–370.9 / 348.9–368.4). CPU/memory ranges overlap; this small warm-cache sample does not establish a general speed or memory improvement. Processes are fresh; the OS file cache is warm. Caller input creation, schemas/discovery, prompts, client parsing and MCP transport are not included. The same 50 ms family-RSS limitations apply.

JSON admission and output consistency follow-up

Three later review findings were reproduced with 19 failing controls before the correction (49 other selected checks pass). Broad JavaScript trimming admitted form-feed, vertical-tab, NBSP and BOM around JSON objects; those are not JSON whitespace. The IPS adapter now passes the original body to the lossless parser, and the complete-value boundary permits only space, tab, CR and LF after the value. Twelve controls cover metadata suffixes and body prefixes/suffixes; a positive control retains JSON whitespace around both objects. Caller bytes and artifact identity stay unchanged.

The shared service no longer accepts a reported faulting-thread index without an established retained owner or its corresponding reference mismatch. Unknown or out-of-range recorded indexes remain available with partial coverage; an unrelated mismatch cannot justify the unresolved lookup. The old empty service fixture incorrectly asserted faulting thread zero and now records null. This is output admission, not reinterpretation of provider source JSON.

Classification is now a named discriminated schema: classified requires at least one match and unclassified permits none. The source schema rejects both contradictions. Production SDK/Ajv checks also test both contradictions and both valid alternatives against the advertised JSON Schema; an actual stdio call checks that non-JSON trailing whitespace returns a typed caller-input failure. These are correctness changes. Prior CLI/performance results retain their exact pins and are not a fresh measurement of the expanded classification schema or agent catalog costs. No speed or token reduction is claimed for this follow-up.

Final executed source pin 38b5a3c44824282b55041389b7cbb4d9c261cc8c incorporates main 98ec00f4068bab894639d0d1d83ac0bfc428bcbf. All 216 selected checks pass after the runtime rebuild: 52.922 s elapsed, 51.098 CPU s, 1,347.9 MiB sampled peak family RSS. Type/lint, complete formatting and generated documentation checks pass. Both pinned public LLVM/pycrashreport inputs were repeated through the actual stdio SDK/Ajv: 20.231 s elapsed, 20.602 CPU s, 934.0 MiB sampled family RSS, with complete coverage. Full Evidence and IDs agree with the saved pre-correction public-corpus outputs for both valid inputs. This repeat is a fresh client/server process with primed OS/file caches; it is not a cold-system measurement. Client/schema work is included in runtime costs; model/catalog token usage was not measured in this repeat. The family sampler's shared-page and short-lived-child limitations described above still apply.

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea