| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ ShareComment @coderabbitai help to get the list of available commands. |
Sorry, something went wrong.
…n the call completes A plain JS object passed where native expects a struct pointer (MyStruct*) is snapshotted into a malloc'd buffer that was never freed - the long- standing 'How to free this?' TODO in Interop::WriteValue, and the last remaining entry from the Instruments leaks run addressed by 8080bc0. The buffer is now owned by the FFICall driving the invocation and freed once the call completes, making the literal form a call-scoped borrow. Only SetFFIParams passes the owner: writes into interop.Reference slots (where the pointer outlives the call) and nested ref/out-param initialization deliberately keep the unowned allocation. BREAKING-ish: native APIs that retained such a pointer past the call only worked because of the leak; they must now be fed a wrapped struct instance (caller-kept) or interop.alloc memory (manual/callee-freed) instead.
| Back | FazBrowse Home | New Git URL |
What changes
Passing a plain JS object literal where a native parameter expects a pointer to a struct (e.g. CGPoint*, NSRange*):
previously snapshotted the literal into a malloc'd buffer that was never freed (the long-standing // TODO: How to free this? in Interop::WriteValue) — one leak per call. With this PR the buffer is owned by the FFICall driving the invocation and freed when the call completes (after ffi_call returns and the result is read).
Writes of literals into MyStruct*-typed slots of an interop.Reference are unchanged: that pointer is stored in memory that outlives any call, so those buffers deliberately remain unowned.
The lifetime contract (new, documented behavior)
⚠️ Behavior change & risk — please test in real apps before merging
This is a deliberate behavior change with a known hazard class: code that passes a literal and relies on native retaining that pointer past the call worked before only because of the leak (the buffer was accidentally immortal). Under this PR such code gets a dangling pointer at call end — a use-after-free instead of a leak. Symmetrically, an API whose contract is "callee frees the pointer" would now double-free; interop.alloc is the correct form there.
Mitigating data — a survey of NativeScript core (packages/core + test apps):
So exposure is limited to third-party plugins / app code using a pattern core never uses. Still: this should soak in real apps (ideally ones heavy on CoreGraphics/CoreText/AV struct-pointer APIs) before it ships, and the release notes should state the new lifetime rule.
Implementation
Tests
New specs in Marshalling/RecordTests.js:
Full suite passes. The leak itself is verified fixed out-of-band with the Instruments Leaks template — this path was the last remaining entry from the leaks run that 8080bc0 addressed.