Skip to content

MathisRaibaud/wasm-memory-error-safari-repro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WASM out-of-memory error with Emscripten on Safari

This repository contains a toy project which reproduces an out-of-memory error that seems to happen only but systematically in Safari (macOS and iOS) when compiling C++ code to WASM with Emscripten using the -pthread flag.

[TL;DR] Preliminary conclusions:

  • The problem seems to occur only on Safari (iOS and macOS).
  • The problem seems to occur only if the memory is shared (pthread enabled)
  • The error seems to be related to the MAXIMUM_MEMORY value (or to the INITIAL_MEMORY value if ALLOW_MEMORY_GROWTH is disabled).
  • The memory seems to be never deallocated when the page is reloaded and therefore creates an out-of-memory after several reloads.
  • The problem seems to be related to the auto-generated Emscripten script (and not Safari), as it does not occur when shared memory is allocated manually (see Preliminary investigations).

How to reproduce

1. Install Emscripten and CMake

You must have emscripten installed and active in your current terminal (see emscripten documentation) and cmake installed (on macOS, brew install cmake).

2. Compile the project

At the root of this project, compile the C++ code to WASM:

emcmake cmake -S . -B build
cmake --build build

The output files will be placed in the dist/ folder, next to the index.html file.

3. Host and run the HTML page

Host the contents of the dist/ folder on a server and run dist/index.html in Safari.
For instance, to run dist/index.html on a local web server in Safari with emscripten, run:

emrun dist/index.html --browser safari

⚠️ If you don't use a local web server, the website where you host the dist/ folder must be "cross-origin isolated" using COOP and COEP (see this for more informations) since the code uses SharedArrayBuffer (because of the -pthread flag). You can check if your website is cross-origin isolated with the crossOriginIsolated variable.

4. Reproduce the error

Open the Safari debug console and reload the page several times. After a certain number of reloads (~2 reloads on iOS, ~30 reloads on macOS, it may differ on your machine), the web page crashes with an error RangeError: Out of memory in the debug console.

Setup & Configurations

This has been tested with the following configurations:

  • Desktop:
    • Macbook Pro Intel
    • macOS Ventura 13.3.1
    • Safari 16.4
  • Mobile:
    • iPhone 12 mini
    • iOS 16.4.1
    • Safari 16.4

The code has been compiled with Emscripten 1.38 and CMake 3.26.3 for both configurations. To help debugging, emcc -v returns:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.38 (9eff02bc816c50ab0e3b70a3bd5b72a8dc2893a2)
clang version 17.0.0 (https://github.com/llvm/llvm-project 004bf170c6cbaa049601bcf92f86a9459aec2dc2)
Target: wasm32-unknown-emscripten
Thread model: posix

Preliminary investigations

I first encountered this problem only on iOS at first. At that time, I only had the ALLOW_MEMORY_GROWTH and pthread options enabled (the INITIAL_MEMORY and MAXIMUM_MEMORY values were set by default by Emscripten). The page crashed on its first access (no need to reload the page to get the error).

After some research, I came across this ffmpeg.wasm issue and this emscripten issue which described the same memory problem on iOS. The two issues suggested reducing the MAXIMUM_MEMORY to get rid of the out-of-memory error on iOS.

And indeed, the first access to the page works. But I found that if I reloaded the page, I still got the same error. I have the impression that the number of reloads to get the error depends on the value of MAXIMUM_MEMORY. The lower it is, the more reloads you have to do before getting the error.

I then tested on Safari macOS to identify if the problem came only from iOS. On macOS, the error also occurs, but after a larger number of reloads, probably because the memory allowed by the browser is larger on Desktop than on Mobile.

At this point, I suspected a bug coming from Safari and not from Emscripten. So I tested to run the line that crashes in the code generated by Emscripten directly in an HTML page:

  var INITIAL_MEMORY = 16777216;
  wasmMemory = new WebAssembly.Memory({
   "initial": INITIAL_MEMORY / 65536,
   "maximum": 536870912 / 65536,
   "shared": true
  });

But this time, I don't get the error after reloading the page. So I suspect that the problem comes from the code generated by Emscripten.

An interesting point is that once the error has occurred, reloading the page produces the error every time. However, if you open the page in another tab, the cycle starts again from the beginning.

To summarize:

  • The problem seems to occur only on Safari (iOS and macOS).
  • The problem seems to occur only if the memory is shared (pthread enabled)
  • The error seems to be related to the MAXIMUM_MEMORY value (or to the INITIAL_MEMORY value if ALLOW_MEMORY_GROWTH is disabled).
  • The memory seems to be never deallocated when the page is reloaded and therefore creates an out-of-memory after several reloads.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published