Skip to content

fix(core): getRandomValues fills the caller's typed array on iOS - #11405

Merged
NathanWalker merged 1 commit into
NativeScript:mainfrom
edusperoni:fix/crypto-get-random-values-fill
Sep 3, 2026
Merged

NathanWalker merged 1 commit into
NativeScript:mainfrom
edusperoni:fix/crypto-get-random-values-fill

Conversation

@edusperoni

Copy link
Copy Markdown
Contributor

PR Checklist

What is the current behavior?

On iOS, crypto.getRandomValues(typedArray) returns the array unchanged: every byte stays zero. Any key, token, IV or nonce minted through it on the main thread or in a worker is all zeros.

The shim wraps V8's backing store in NSMutableData.dataWithBytesNoCopy:length:freeWhenDone: and lets NSCCrypto.getRandomValues: fill mutableBytes. NSMutableData does not adopt foreign bytes, regardless of the ownership flag (measured on macOS 15 and the iOS simulator; only the immutable NSData adopts them):

Call Adopts the caller's buffer?
NSData dataWithBytesNoCopy:… freeWhenDone:NO yes
NSMutableData dataWithBytesNoCopy:… freeWhenDone:NO no, copies on creation
NSMutableData dataWithBytesNoCopy:… freeWhenDone:YES no, copies on creation and frees the original

So freeWhenDone:YES (the previous code) filled a private copy and freed V8's allocation, which is the double-free that was fixed by switching to NO, and NO fills the same private copy and leaves the caller's array untouched. No NSData-based construction can make the native fill reach the typed array.

What is the new behavior?

The iOS branch hands the typed array to SecRandomCopyBytes directly and checks the status. The runtime already passes an ArrayBufferView as its backing store pointer plus the view's byte offset (tns::TryGetBufferFromArrayBuffer), so the bytes land in the caller's own window with no intermediate object: zero copies and nothing for Foundation to own or free. A wider element type is still reinterpreted as a byte view over the same window.

packages/core/references.d.ts now references the Security framework typings. The Android branch is unchanged: the runtime maps the view to a direct ByteBuffer over the same window and the Java side fills it in place.

Specs assert that the very view reaches SecRandomCopyBytes with its byte length, that an offset view and a reinterpreted Uint32Array are filled within their window only and the bytes are visible through the caller's array, that a failure status throws, and that neither NSMutableData nor NSCCrypto is involved.

NSCCrypto.getRandomValues:(NSMutableData *) in NSCWinterTC is left as is; it is no longer used by core and its NSMutableData contract cannot alias caller memory, so it is a candidate for deprecation when the framework is next rebuilt.

NSMutableData never aliases bytes it is handed: with freeWhenDone:NO it copies them on creation, with freeWhenDone:YES it copies them and frees the original. Wrapping V8's backing store in one therefore filled a private copy and left the caller's array zeroed, or double-freed the allocation. Hand the typed array to SecRandomCopyBytes directly; the runtime resolves a view to its backing store at the view's byte offset, so the fill lands in the caller's own window with nothing in between.
@nx-cloud

nx-cloud Bot commented Sep 2, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 00d0102

Command Status Duration Result
nx test apps-automated -c=ios ✅ Succeeded 2m 23s View ↗
nx run-many --target=test --configuration=ci --... ✅ Succeeded 2s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-09-02 03:36:46 UTC

@pkg-pr-new

pkg-pr-new Bot commented Sep 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@nativescript/core@11405
npm i https://pkg.pr.new/@nativescript/vite@11405
npm i https://pkg.pr.new/@nativescript/webpack@11405

commit: 00d0102

@NathanWalker
NathanWalker merged commit 9154f61 into NativeScript:main Sep 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants