emscripten-core / emscripten-core/emscripten

Missing mmap()/munmap()/mremap() features for in-place adjustment of anonymous mappings

Open
#21,816 10 comments 1 reaction 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

**Version of emscripten/emsdk:**
3.1.57

The [WordPress Playground project](https://github.com/WordPress/wordpress-playground) uses Emscripten to compile the PHP runtime as Wasm, and it uses those builds to run PHP in the browser and on Node.js.

PHP's memory manager relies heavily on mmap() and munmap() for allocating and reallocating memory as anonymous mappings. There are two things PHP cannot do properly using Emscripten's mmap() and mumnmap() implementations:
1. Allocating 2MB chunks of memory with 2MB alignment - It does this by mapping twice the amount of desired memory in order to find an aligned region within and freeing the excess at the head and tail using partial unmapping.
2. In-place reallocation, both truncating and extending

For the PHP runtime, the primary thing that is missing from Emscripten is a munmap() implementation that supports partial unmapping of anonymous mappings. This would cover item 1 and half of item 2 (truncation). An example of aligned allocation with mmap()/munmap() can be found [here](https://github.com/php/php-src/blob/bab75e1f5c65892c2d3ec9579df7f9b9d66d81e1/Zend/zend_alloc.c#L753-L762) with the actual munmap() call [here](https://github.com/php/php-src/blob/bab75e1f5c65892c2d3ec9579df7f9b9d66d81e1/Zend/zend_alloc.c#L448). An example of truncation can be found [here](https://github.com/php/php-src/blob/bab75e1f5c65892c2d3ec9579df7f9b9d66d81e1/Zend/zend_alloc.c#L806) which leads to the same actual munmap() call.

Secondly, PHP attempts to extend anonymous mappings in-place using either mremap() or mmap(). When using mremap(), no flags are provided. When [using mmap()](https://github.com/php/php-src/blob/bab75e1f5c65892c2d3ec9579df7f9b9d66d81e1/Zend/zend_alloc.c#L475-L490), PHP passes one of the following combinations of flags:
- `MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_EXCL`
- `MAP_PRIVATE | MAP_ANON | MAP_TRYFIXED`

When PHP cannot extend memory in-place, it resorts to allocating another aligned chunk of memory and copying the contents of the current chunk into it. This increases memory requirements and leads to more frequent out of memory conditions than when memory can be extended in-place.

## Without in-place adjustment of anonymous mappings

Without the ability to adjust anonymous mappings in-place, PHP mishandles memory and incorrectly assumes partial unmapping works, leading to large memory leaks in certain cases.

As a workaround, Playground currently use a PHP extension to install [alternate memory allocation handlers that can only allocate aligned memory and free it](https://github.com/WordPress/wordpress-playground/blob/8ccacca98b536ddeee4b8c9305bd38ead25056d4/packages/php-wasm/compile/php-wasm-memory-storage/wasm_memory_storage.c#L25-L66). No in-place adjustment is supported. Reallocation of aligned regions requires maintaining old and new memory regions at the same time while the old is copied to the new.

Could Emscripten be updated to support in-place adjustment of anonymous mappings?

cc @ThomasTheDane

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.