Dear Motoko Developers,
We recently discovered that Motoko’s implementation of stable memory regions (Region.mo
) introduced a serious bug in the implementation of the following four operations:
Region.loadInt32
Region.storeInt32
Region.loadNat32
Region.storeNat32
The problem was that the operations were saving the Motoko representation of the values (also 32-bit), not the actual values. Small values between -2^30 (inclusive) and 2^30 (exclusive) would be saved shifted left 1 bit. Values outside that range are boxed on the heap and the address of the value, minus 1, would be stored instead of the value itself. This “works” until a GC kicks in and collects or moves some of the heap allocated values.
We hope no one is already using this feature in production, but, if so, please message us (publicly or privately) to discuss mitigations.
We suspect our tests were passing because a) GC never kicked in b) we only checked round-tripping of the values, not the physical bytes.
The bug only affects library Region.mo
.
The corresponding ExperimentalStableMemory.mo
operations are not buggy.
The bug is fixed in Motoko 0.10.3 which should be included in a future release of dfx
(hopefully 0.15.3).The current release of dfx
(0.15.2) is still shipping the defective Motoko 0.10.2 (as are the betas of 0.15.3).
Next Steps
If you have used any of the Stable Regions methods listed above (loadInt32
, storeInt32
, loadNat32
, or storeNat32
) in versions of Motoko 0.10.2 or earlier, please reply to this thread, send a DM or email team-motoko@dfinity.org and we will help you determine what mitigation is required. Simply upgrading to code compiled with Motoko 0.10.3 will lead to data corruption if a value was written with version 0.10.2 (say) but is read with version 0.10.3.
We apologize for the error and inconvenience caused.