[PR #846] [MERGED] fix(native): report exact plist integers beyond the JSON number range #2284

Closed
opened 2026-10-16 21:16:43 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/846
Author: @kaoru0822-kitauji
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/7/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/plist-exact-large-integers


📝 Commits (2)

  • 430c297 fix(native): report exact plist integers beyond the JSON number range
  • f85056d fix(native): keep plist XML element types for large numbers

📊 Changes

3 files changed (+227 additions, -10 deletions)

View changed files

➕ src/native/parsers/plist.test.ts (+73 -0)
📝 src/native/parsers/plist.ts (+102 -10)
📝 tests/boundary/cli/nativePlistCli.test.ts (+52 -0)

📄 Description

Summary

Follow-up I noted in #841. Plist <integer> values are 64-bit, but inspect_plist parses plutil's JSON with plain JSON.parse. Integers outside ±(2⁵³ − 1) are silently rounded, while native plutil reports them exactly:

<integer> plutil -convert json REA on main
18446744073709551615 18446744073709551615 18446744073709552000
-9223372036854775808 -9223372036854775808 -9223372036854776000

No limitation accompanies the wrong value. AGENTS.md asks to preserve reported values and keep unknowns explicit.

Fix

  • JSON path (the normal path): the JSON.parse reviver reads context.source, which is available in every Node range in engines. An integer literal whose number isn't a safe integer is reported as { "$plist_type": "integer", "decimal": "<exact digits>" }, matching #841's $plist_type convention, with a limitation giving the count. Safe integers and reals are unchanged, and plists without such integers get the same output and no limitation.
  • XML fallback path (plists with data, dates, or non-finite reals): the plist package decodes <integer> and <real> into numbers before REA sees them, rounding large integers. REA reads the element literals from plutil's XML text instead; plutil escapes < in keys and strings, so these tags are unambiguous.
    • An unsafe integral number that matches exactly one <integer> literal and no <real> gets its exact decimal.
    • An integral <real> such as 9007199254740992 stays a number.
    • A value that both an <integer> and a <real> round to is left as decoded, with an explicit limitation. This follows the review on this PR.
  • Housekeeping: #841's rewrite turned the BOM regex's  escape into a raw, invisible U+FEFF character. It behaved the same, but it was the only raw BOM in src/ and tests/. The escape is restored.

Scope / impact, stated honestly

This is a correctness edge case. I scanned 5,351 plists under /System/Applications, /Applications, and /System/Library/CoreServices on this host, and none contains such an integer. The change only stops REA from reporting wrong values without saying so when one does occur.

Contract / behavior changes

No schema or catalog changes (value is jsonValueSchema). Output changes only for plists containing integers outside the safe range.

Verification

  • New src/native/parsers/plist.test.ts: exact decimals on the JSON path with safe-integer and real controls, and no limitation when all integers are exact. On the XML path: an exact decimal recovered from the element literal, an integral <real> kept as a real, and the ambiguous integer/real case.
  • New darwin-only real-plutil CLI cases in tests/boundary/cli/nativePlistCli.test.ts for the JSON path and for the XML path (forced by <data>).
  • All 3 new regressions fail on main and pass here.
  • npm run test:focused for the plist parser tests, nativePlistCli, nativeTextRobustness, and nativeProvider: all pass. npm run check:changed and npm run check:fast pass.

MCP uses the same provider path. No Hopper/Ghidra/IDA involvement.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/846 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/7/2026 **Status:** ✅ Merged **Merged:** 10/7/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/plist-exact-large-integers` --- ### 📝 Commits (2) - [`430c297`](https://github.com/morluto/rea/commit/430c297ca4ddb3491c2b835b889486e6a2ffdc17) fix(native): report exact plist integers beyond the JSON number range - [`f85056d`](https://github.com/morluto/rea/commit/f85056d83e42a461c8c947792774580294d0ceb9) fix(native): keep plist XML element types for large numbers ### 📊 Changes **3 files changed** (+227 additions, -10 deletions) <details> <summary>View changed files</summary> ➕ `src/native/parsers/plist.test.ts` (+73 -0) 📝 `src/native/parsers/plist.ts` (+102 -10) 📝 `tests/boundary/cli/nativePlistCli.test.ts` (+52 -0) </details> ### 📄 Description ## Summary Follow-up I noted in #841. Plist `<integer>` values are 64-bit, but `inspect_plist` parses plutil's JSON with plain `JSON.parse`. Integers outside ±(2⁵³ − 1) are **silently rounded**, while native `plutil` reports them exactly: | `<integer>` | `plutil -convert json` | REA on `main` | |---|---|---| | `18446744073709551615` | `18446744073709551615` | `18446744073709552000` | | `-9223372036854775808` | `-9223372036854775808` | `-9223372036854776000` | No limitation accompanies the wrong value. AGENTS.md asks to preserve reported values and keep unknowns explicit. ## Fix - **JSON path** (the normal path): the `JSON.parse` reviver reads `context.source`, which is available in every Node range in `engines`. An integer literal whose number isn't a safe integer is reported as `{ "$plist_type": "integer", "decimal": "<exact digits>" }`, matching #841's `$plist_type` convention, with a limitation giving the count. Safe integers and reals are unchanged, and plists without such integers get the same output and no limitation. - **XML fallback path** (plists with data, dates, or non-finite reals): the `plist` package decodes `<integer>` and `<real>` into numbers before REA sees them, rounding large integers. REA reads the element literals from plutil's XML text instead; plutil escapes `<` in keys and strings, so these tags are unambiguous. - An unsafe integral number that matches exactly one `<integer>` literal and no `<real>` gets its **exact** decimal. - An integral `<real>` such as `9007199254740992` stays a number. - A value that both an `<integer>` and a `<real>` round to is left as decoded, with an explicit limitation. This follows the review on this PR. - **Housekeeping:** #841's rewrite turned the BOM regex's `` escape into a raw, invisible U+FEFF character. It behaved the same, but it was the only raw BOM in `src/` and `tests/`. The escape is restored. ## Scope / impact, stated honestly This is a correctness edge case. I scanned **5,351** plists under `/System/Applications`, `/Applications`, and `/System/Library/CoreServices` on this host, and **none** contains such an integer. The change only stops REA from reporting wrong values without saying so when one does occur. ## Contract / behavior changes No schema or catalog changes (`value` is `jsonValueSchema`). Output changes only for plists containing integers outside the safe range. ## Verification - New `src/native/parsers/plist.test.ts`: exact decimals on the JSON path with safe-integer and real controls, and no limitation when all integers are exact. On the XML path: an exact decimal recovered from the element literal, an integral `<real>` kept as a real, and the ambiguous integer/real case. - New darwin-only real-`plutil` CLI cases in `tests/boundary/cli/nativePlistCli.test.ts` for the JSON path and for the XML path (forced by `<data>`). - **All 3 new regressions fail on `main` and pass here.** - `npm run test:focused` for the plist parser tests, `nativePlistCli`, `nativeTextRobustness`, and `nativeProvider`: all pass. `npm run check:changed` and `npm run check:fast` pass. MCP uses the same provider path. No Hopper/Ghidra/IDA involvement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-16 21:16:43 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2284
No description provided.