Skip to content

Build mimalloc as C++ - #28000

Open
slowriot wants to merge 1 commit into
emscripten-core:mainfrom
slowriot:mimalloc-builds-as-cpp
Open

slowriot wants to merge 1 commit into
emscripten-core:mainfrom
slowriot:mimalloc-builds-as-cpp

Conversation

@slowriot

Copy link
Copy Markdown
Contributor

Motivation

Emscripten currently compiles all its allocators as C. This makes no difference for dlmalloc and emmalloc, as they have no C++ feature detection and don't supply their own new/delete, but mimalloc does. As a result, building it as C causes abort on bad allocation instead of throwing std::bad_alloc, even when exceptions are enabled and -sABORTING_MALLOC=0.

This change makes sure that mimalloc is built as C++, only for C++ programs with exceptions enabled.

Changes

  • tools/system_libs.py: Make libmimalloc inherit from ExceptionLibrary, giving it separately cached variants for disabled exceptions, Emscripten/JavaScript exceptions, legacy Wasm exceptions and standardized Wasm exceptions. Compile mimalloc's sources with -x c++ -std=c++17 for exception-enabled C++ links. All mimalloc translation units use the same language to keep internal linkage consistent; the underlying emmalloc.c and sbrk.c remain C. C-only programs explicitly select the C-built, no-exception variant, even when Wasm exception support is enabled. C++ programs without exceptions also retain the C build.
  • embuilder.py: Add the single-threaded and multithreaded no-exception variants, plus the legacy and standardized Wasm exception variants, to the minimal prebuild task list.
  • alloc-override.c: Allow Clang through the existing C++ aligned-allocation guard. Clang defines __GNUC__ as 4 for compatibility, so the previous GCC-version check excluded it despite support for aligned allocation. The guard still requires C++17 and __cpp_aligned_new. This preserves mimalloc's aligned new/delete implementations when switching to C++ compilation.
  • prim/emscripten/prim.c: Use mi_decl_externc for the declarations of emmalloc_free and emmalloc_memalign. This gives them extern "C" linkage in the C++ build, matching the underlying C implementation. Their behaviour is unchanged.
  • test/core/test_new_oom.cpp and .out: Add regression coverage for scalar, array and aligned allocation: zero-sized allocation, std::bad_alloc on failure, null returns from nothrow allocation, retrying a returning new_handler, propagating or catching handler exceptions as appropriate, and successful allocation after handling a failure. The test deliberately exceeds MAXIMUM_MEMORY without exhausting the memory needed to construct the exception.
  • test/test_core.py: Run the new test with dlmalloc, emmalloc and mimalloc across all three exception-handling modes. Add mimalloc cases to the existing aborting-new and nothrow-new tests, with and without memory growth.
  • test/test_other.py: Add single-threaded and pthread C allocation tests with Wasm exception support enabled, checking that C-only links do not acquire a C++ runtime dependency.

Comment thread tools/system_libs.py
variation = super().get_default_variation(**kwargs)
# C-only programs must not acquire a dependency on the C++ runtime.
if not settings.LINK_AS_CXX:
variation.eh_mode = Exceptions.NONE

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should make this the default in ExceptionLibrary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds sensible. Would you like me to include that into this change or raise a separate PR?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets try to land that change first / separately.

@sbc100
sbc100 requested review from kleisauke and kripken October 17, 2026 00:25
#endif

#if (__cplusplus > 201402L && defined(__cpp_aligned_new)) && (!defined(__GNUC__) || (__GNUC__ > 5))
#if (__cplusplus > 201402L && defined(__cpp_aligned_new)) && (!defined(__GNUC__) || (__GNUC__ > 5) || defined(__clang__))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a change to upstream mimalloc (not the emscripten-specific parts). Has it been discussed upstream?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C path also uses || defined(__clang__), so this looks like a good candidate for upstreaming. /cc @daanx

#elif (defined(__GNUC__) || defined(__clang__))

Note that you could also fix this by compiling with -fgnuc-version=5.0.0, though this is probably safer.

$ emcc -dM -E - < /dev/null | grep -e GNUC
#define __GNUC_MINOR__ 2
#define __GNUC_PATCHLEVEL__ 1
#define __GNUC_STDC_INLINE__ 1
#define __GNUC__ 4
$ emcc -fgnuc-version=5.0.0 -dM -E - < /dev/null | grep -e GNUC
#define __GNUC_MINOR__ 0
#define __GNUC_PATCHLEVEL__ 0
#define __GNUC_STDC_INLINE__ 1
#define __GNUC__ 5

(Clang claims compatibility with GCC 4.2.1 by default)

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

4 participants