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.