Search code examples
firefoxwebassemblyhttpserversharedarraybuffer

Not possible to test WebAssembly page locally with Firefox - SharedArrayBuffer not defined


I am using a WebAssembly based software that uses multi-threading that requires SharedArrayBuffer. It runs fine both in Chromium local/deployed, and Firefox 89 deployed, but since the best performance is under Firefox, I want to test and tune it on my machine, so I run python -m SimpleHTTPServer. In this situation, when I open 127.0.0.1:8000 or 0.0.0.0:8000 in Firefox, SharedArrayBuffer is undefined. Perhaps this is a security setting, but when using localhost, I'm really not interested in Firefox's interpretation of the situation -- this should just run. How can I make it work? Do I need a different web server, different settings?


Solution

  • As you guessed correctly, it has to do with security restrictions. There have been changes in regards to the use of SharedArrayBuffer that have already been implemented in Firefox 79 and will land in Chrome shortly as well (starting with Chrome 92). (Time of writing this: July 13, 2021.)

    The main purpose is to restrict the use of SharedArrayBuffers in postMessage. Any such attempt will throw an error unless certain restrictive COOP/COEP headers are set to prevent cross-origin attacks:

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp
    

    Unfortunately, without these headers, there is also no global SharedArrayBuffer constructor. Apparently, this restriction may be lifted in the future. The objects themselves still work though (only passing them through postMessage would throw), but you need a different way to instantiate them. You can use WebAssembly.Memory instead:

    const memory = new WebAssembly.Memory({ initial: 10, maximum: 100, shared: true })
    // memory.buffer is instanceof SharedMemoryBuffer
    

    You could now go one step further and recover the constructor from that. Therefore, with the following code as "shim", your existing code should work as long as it doesn't try to pass the buffer through postMessage:

    if (typeof SharedArrayBuffer === 'undefined') {
      const dummyMemory = new WebAssembly.Memory({ initial: 0, maximum: 0, shared: true })
      globalThis.SharedArrayBuffer = dummyMemory.buffer.constructor
    }
    
    // Now, `new SharedArrayBuffer(1024)` works again
    

    Further reading: