You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The text was updated successfully, but these errors were encountered:
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
produces three arrays which all share an ArrayBuffer.
b
andc
see different slices ofa
, and appear to be 3 elements long.Because
stringify(b)
andstringify(c)
don't pay attention to the offset and length of the array within the buffer, stringifying every array produces[["Uint8Array","AQIDBAUG"]]
, whichparse
s 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)
producesnew 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 be42
as well, but this is not the case if the values are passed througheval(uneval({a, b, c}))
, because the arrays no longer share their backing store.The text was updated successfully, but these errors were encountered: