6

I am facing a problem with decode() on SharedArrayBuffer.

Code:

  var sharedArrayBuffer = new SharedArrayBuffer(2);
  var uint8Array = new Uint8Array(sharedArrayBuffer);
  uint8Array[0] = 20;
  var decoder = new TextDecoder();
  decoder.decode(uint8Array);

Error:

Failed to execute 'decode' on 'TextDecoder': The provided ArrayBufferView value must not be shared.

There is a specification here that warns developers about race-condition on this type of memory. Can I somehow force decoding? I am sure data will not be changed during decoding. Or is there a workaround for this?

Reasons: I want to create a single copy of Uint8Array and pass it without copying via postmessage (which copies by default if transferrable is not specified) to several(>3) IFrames(with sandbox tag). Maybe there are other possible solutions?

7
  • Your pages are same-origin anyway, right? So can't you just do top.globallyAccessibleArrayBuffer from your frames? Commented Jul 12, 2022 at 8:12
  • I am missing something, is there a way IFrame with tag sandbox can access its parents' variables? Or can I ask you to elaborate on your comment(provide any code)? Commented Jul 12, 2022 at 8:30
  • You never stated these iframes were sandboxed befire my comment. How do you make your CO isolation work? With the experimental allow=cross-origin-isolated feature policy? Or with sandbox=allow-same-origin? Or with something else I'm not aware of? I was under the impression you need same-origin to have SharedArrayBuffer, and thus you'd have access to the various contexts anyway. Commented Jul 12, 2022 at 9:32
  • Sorry, I changed the description after your comment, totally missed it when describing the problem. I use "Cross-Origin-Opener-Policy" : "same-origin", "Cross-Origin-Embedder-Policy" : "require-corp" in headers of my webpack dev server in order to use SharedArrayBuffer. Commented Jul 12, 2022 at 10:08
  • Interesting... What browser are you using? My main one is Firefox and because of it I thought its behavior was the "normal" one, and there, I am unable to load a sandboxed iframe from a cross-origin isolated document, unless it has the "allow-same-origin" sandbox clause. I now see that both Chrome and Safari do allow it though, but then, only in Safari am I able to postMessage an SAB, Chrome failing silently (no error, no message). So given all this it seems that to have a cross-browser behavior you'd need the iframes to be same-origin anyway. But maybe you're targeting only one vendor? Commented Jul 12, 2022 at 12:38

3 Answers 3

2

Sadly, today you have to incur the extra buffer + copy in order to consistently do this across browsers. It's plausible that any given browser may allow this, but it isn't portable as of writing this.

For context, the ability for TextDecoder.decode(...) to take a SharedArrayBuffer is desired functionality for WebAssembly and other low-level performance scenarios, but it's stuck in standards and implementation-related discussions.

Here's an example of a buffer-intermediate code path that works to bypass this failing today:

function decodeFromSharedBuffer(sharedBuffer, maxLength) {
  const decoder = new TextDecoder()
  const copyLength = Math.min(sharedBuffer.byteLength, maxLength)

  // Create a temporary ArrayBuffer and copy the contents of the shared buffer
  // into it.
  const tempBuffer = new ArrayBuffer(copyLength)
  const tempView = new Uint8Array(tempBuffer)

  let sharedView = new Uint8Array(sharedBuffer)
  if (sharedBuffer.byteLength != copyLength) {
    sharedView = sharedView.subarray(0, copyLength)
  }
  tempView.set(sharedView)

  return decoder.decode(tempBuffer)
}
Sign up to request clarification or add additional context in comments.

Comments

0

Looks like using ArrayBuffer works fine.

  var arrayBuffer = new ArrayBuffer(2);
  var uint8Array = new Uint8Array(arrayBuffer);
  uint8Array[0] = 20;
  var decoder = new TextDecoder();
  decoder.decode(uint8Array);

3 Comments

The problem is - I would like then share this memory to IFrames, I do want to evade of structured cloning during postmessage, thus I am using SharedArrayBuffer.
ah, right. Looks like you have to use Atomics in this case. See developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Am I right that I have to implement decoding by myself using atomics for SharedArrayBuffer?
-1

Js

var sharedArrayBuffer = new SharedArrayBuffer(32);
var ary = new Int32Array(sharedArrayBuffer);
ary[0] = 20;
var encoder = new TextEncoder();
var EncodedArray = encoder.encode(ary);
console.log("Encoded Array : ", EncodedArray)
var decoder = new TextDecoder();
var DecodedArray = decoder.decode(EncodedArray);
console.log("Decoded Array is : ", DecodedArray)

2 Comments

Sir, I do not want to encode my SharedArrayBuffer, the data in it is already encoded. I only need to decode it, thanks. Whilst your approach - while encoding it first returns a complete new Uint8Array which is ArrayBuffer underneath and hence can be passed to decode() function later. So, your answer is not what I am looking for.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.