Skip to content

Strategy for Testing SharedArrayBuffer in Wasm for Memory Leak Detection #24245

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

Open
spriya2025 opened this issue May 2, 2025 · 3 comments
Open

Comments

@spriya2025
Copy link

I'm working on a WebAssembly application compiled with Emscripten that makes use of SharedArrayBuffer for inter-thread communication via Web Workers. I’d like to understand the usual or recommended strategy followed in the Emscripten/WebAssembly ecosystem for testing and validating correct usage of SharedArrayBuffer, particularly with respect to identifying potential memory leaks.

Specifically:

  1. Are there any tools or test setups (within the Emscripten testing infrastructure or otherwise) that help track memory leaks in such scenarios?
  2. Does Emscripten provide any runtime support or diagnostics that can help monitor shared memory usage or verify clean-up?
  3. Are there known best practices when using SharedArrayBuffer in combination with WebAssembly to ensure proper memory management?
@kripken
Copy link
Member

kripken commented May 5, 2025

You can use sanitizers to find memory leaks:

https://emscripten.org/docs/debugging/Sanitizers.html#memory-leaks

@spriya2025
Copy link
Author

Thank you for your response. We tried the same approach on our side and were able to detect memory leaks using the em++ -fsanitize=address -sEXIT_RUNTIME leak.cpp command. However, when adding the -gsource-map option as shown in your example, we encountered the following error:

leak.cpp

#include <stdio.h>

int main(int argc, char** argv) {
  new int[10];
  return 0;
}

em++ -gsource-map -fsanitize=address -sEXIT_RUNTIME leak.cpp

/Users/a.out.js:1569
 for (var i = 0; i < str.length; ++i) {
             ^

TypeError: Cannot read properties of undefined (reading 'length')
  at lengthBytesUTF8 (/Users/a.out.js:1569:27)
  at stringToNewUTF8 (/Users/a.out.js:4181:14)
  at /Users/a.out.js:4330:33
  at withBuiltinMalloc (/Users/a.out.js:4171:12)
  at _emscripten_pc_get_file (/Users/a.out.js:4326:37)
  at a.out.wasm.__sanitizer::EmscriptenSymbolizerTool::SymbolizePC(unsigned long, __sanitizer::SymbolizedStack*) (wasm://wasm/a.out.wasm-001245ba:wasm-function[793]:0x2856b)
  at a.out.wasm.__sanitizer::Symbolizer::SymbolizePC(unsigned long) (wasm://wasm/a.out.wasm-001245ba:wasm-function[802]:0x2881d)
  at a.out.wasm.__lsan::LeakSuppressionContext::GetSuppressionForAddr(unsigned long) (wasm://wasm/a.out.wasm-001245ba:wasm-function[456]:0x1873d)
  at a.out.wasm.__lsan::LeakSuppressionContext::Suppress(unsigned int, unsigned long, unsigned long) (wasm://wasm/a.out.wasm-001245ba:wasm-function[457]:0x18882)
  at a.out.wasm.__lsan::CheckForLeaks() (wasm://wasm/a.out.wasm-001245ba:wasm-function[466]:0x19635)Without the -gsource-map flag, the leak detection still works, but the trace doesn’t show source-level details—making it harder to pinpoint the exact cause.

Without the -gsource-map flag, the leak detection still works, but the trace doesn’t show source-level details—making it harder to pinpoint the exact cause.

em++ -fsanitize=address -sEXIT_RUNTIME leak.cpp

=================================================================
==42==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40 byte(s) in 1 object(s) allocated from:
  #0 0x1099d in wasm-function[300]+0x1099d (/Users/a.out.js+0x1099d)
  #1 0x3504 in wasm-function[49]+0x3504 (/Users/a.out.js+0x3504)
  #2 0x34e2 in wasm-function[48]+0x34e2 (/Users/a.out.js+0x34e2)
  #3 0x3529 in wasm-function[51]+0x3529 (/Users/a.out.js+0x3529)
  #4 0xd1b in wasm-function[30]+0xd1b (/Users/a.out.js+0xd1b)
  #5 0x80000298 (JavaScript+0x298)
  #6 0x80001242 in callMain /Users/a.out.js:4674:15

SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).

We also wanted to share some context on why we’re asking this:

We are currently evaluating a migration of one of our desktop UI applications to WebAssembly to make it available in web browsers. As part of our QA validation, we found out that memory split-up provided by Chrome profiler tools is totally different from what we actually see the memory taken by the Chrome browser in Activity Monitor. We were able to find few discrepancies like WebGL taken care entirely by Browsers whose memory is out of application scope. Similarly, VMs can also have its own memory. We would like to understand what other factors we need to consider when we want to monitor memory as a whole. Should we consider both the data from Profiler tools inside the browser and the actual memory taken from the OS level? Any guidance would be helpful.

Image

@sbc100
Copy link
Collaborator

sbc100 commented May 6, 2025

Strange that example seem to work fine for me:

$ ./em++ -gsource-map -fsanitize=address -sEXIT_RUNTIME leak.cpp
$ node ./a.out.js

=================================================================
==42==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x000178bf in malloc /emsdk/emscripten/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp:68:3
    #1 0x0000951d in operator_new_impl(unsigned long) /emsdk/emscripten/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h:53:45
    #2 0x000094f3 in operator new(unsigned long) /emsdk/emscripten/system/lib/libcxx/src/new.cpp:47:13
    #3 0x00009554 in operator new[](unsigned long) /emsdk/emscripten/system/lib/compiler-rt/lib/asan/asan_new_delete.cpp:86:3
    #4 0x00000d81 in main leak.cpp:4:3
    #5 0x800003ad  (JavaScript+0x3ad)
    #6 0x8000123d in callMain /usr/local/google/home/sbc/dev/wasm/emscripten/a.out.js:4669:15

SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).

I guess something must be up with the loading of the source map in our browser environment? Do you see any log messages about that on startup?

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

3 participants