Hey,
I’ve just watched the talk about Best Practices for Canisters in Rust (Community Conversations | Best Practices for Canisters in Rust - YouTube and I have a question about the don’t panic after await best practice.
Here is the example from the slide:
#[update]
fn update_avatar(user_id: UserId, pic: ByteBuf) {
let key = store_async(user_id, &pic)
.await
.unwrap();
// BAD: if call fails, pic is likely to leak
USERS.with(|users| set_avatar_key(user_id, key))
}
I understand it like this. If await is called then the method execution is suspended and all the previous local variables are stored on heap/stack and all this data is part of the commit point. When a reply is there then there are three cases:
- Success reply: method continues to execute and at the end of the method all the local variables are deallocated from stack/heap.
- Error reply (the called canister trapped): current canister panics and traps.
- Success reply but the next synchronous call panics: the current canister traps like in the previous case.
In the last two cases memory leak can occure because after a trap the state is reverted to previous commit point - this is the state where the local variables (created before first await, see text above) are stored and this trap doesn’t deallocate them. Am I right, correct me if I’m wrong.
The questions are:
- How to rewrite the code from above, so this leak dosn’t happen, even if panic occures after an await?
- Can this type of leak also occure in Motoko after an await?
Thanks