`mimalloc` memory allocator is broken

We are attempting to add more precise memory leak detection to Azle’s fuzz tests, and to do this we need better memory allocation introspection than we get through dfx or the default memory allocator for the wasm32-wasip1 target. By default we see only the total bytes of the Wasm memory pages allocated, which unfortunately never reduce in size once allocated.

mimalloc is a memory allocator that not only purportedly provides better introspection into bytes allocated, but also may be more performant and have some nice added security features.

But unfortunately on dfx 0.27.0, ic-cdk 0.18.3, ic-wasi-polyfill 0.8.2, and the wasm32-wasip1 target, mimalloc is quite broken when attempting to call canister methods defined in Rust.

Here’s a very simple Rust canister:

 use mimalloc::MiMalloc;
 
 #[global_allocator]
 static GLOBAL: MiMalloc = MiMalloc;
 
 #[ic_cdk::init]
 fn init() {
     ic_wasi_polyfill::init(&[], &[]);
 }
 
 #[ic_cdk::query]
 fn greet(name: String) -> String {
     format!("Hello, {}!", name)
 }
 
 #[ic_cdk::update]
 fn test() -> String {
     "Should return just fine".to_string()
 }

When trying to call either of those two methods, you will intermittently get an error like this:

 Canister trapped: unknown
 Canister Backtrace:
 __funcs_on_exit
 __wasm_call_dtors
 canister_update test.command_export

This is the first time we have really tried to use a custom allocator that I can remember, but this might highlight a broader problem with ic-cdk. I believe custom allocators are a valid feature that ICP developers may want to take advantage of.

P.S. The problem only presents on canister methods defined in Rust using the ic_cdk macros. Regular Azle methods defined in JavaScript are exported from the Wasm binary directly, not using the macros. So this seems like an issue in the ic-cdk macros themselves.

1 Like

I notice the use of ic-wasi-polyfill here, and I believe mimalloc cannot be compiled for headless WASM. Could this be at fault? The CDK does not interact with the existence of a custom global allocator, and should not be affecting this at all; I suspect a fundamental incompatibility, or perhaps just a polyfill shortcoming (using a global alloc that does not require WASI, like dlmalloc, succeeds).

Can you post a minimal repro that does not use the macros and succeeds?

mimalloc does compile for wasm32-wasip1, but I do not believe it compiles for wasm32-unknown-unknown. But we compile everything to wasm32-wasip1.

Let me verify this even more, any repro would just be a very basic Azle canister, but with the mimalloc allocator used in the Rust code for the Wasm binary template.