Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stringify assumes typed arrays own their own buffer #83

Open
nbaum opened this issue Sep 28, 2024 · 0 comments
Open

stringify assumes typed arrays own their own buffer #83

nbaum opened this issue Sep 28, 2024 · 0 comments

Comments

@nbaum
Copy link

nbaum commented Sep 28, 2024

tl;dr: Typed arrays can share a backing store, meaning that their buffer does not have a one-to-one correspondence with their "actual" contents, contrary to stringify's assumption.

The code

const a = Uint8Array.from([1, 2, 3, 4, 5, 6])
const b = a.subarray(0, 3)
const c = a.subarray(3, 6)

produces three arrays which all share an ArrayBuffer. b and c see different slices of a, and appear to be 3 elements long.

Because stringify(b) and stringify(c) don't pay attention to the offset and length of the array within the buffer, stringifying every array produces [["Uint8Array","AQIDBAUG"]], which parses back into the original 6-element array.

This poses a big problem for my use case, where I'm using a library which loads data into an arraybuffer and then parses it into subarrays to avoid making lots of copies, but I'm also using devalue, via Nuxt, to pass the data back to the browser. The end result is that when they arrive in the browser all the arrays have turned back into the top-level buffer.

uneval(a) produces new Uint8Array([1,2,3]) which isn't quite right, but is much less surprising, and also works for me.

My current workaround is doing eval(uneval(a)) before handing the data over to Nuxt.

Additionally, it isn't an issue for my use case, but Rich has said that a goal of devalue is that after passing data through it, you get exactly the same structure back. Neither uneval nor stringify quite do that here because they don't handle the buffer being shared between arrays. e.g. after a[0] = 42, b[0] should be 42 as well, but this is not the case if the values are passed through eval(uneval({a, b, c})), because the arrays no longer share their backing store.

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

No branches or pull requests

1 participant