diff --git a/Changelog.md b/Changelog.md index 764fe099b3a..48962e971f0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,13 @@ # Motoko compiler changelog +* motoko (`moc`) + + * bugfix: fix broken implementations of `Region.loadNat32`, `Region.storeNat32`, `Region.loadInt32`, `Region.storeInt32` (#4335). + Values previously stored with the broken 32-bit operations must be loaded with care. + If bit 0 is clear, the original value can be obtained by an arithmetic shift right by 1 bit. + If bit 0 is set, the value cannot be trusted and should be ignored + (it encodes some transient address of a boxed value). + ## 0.10.2 (2023-11-12) * motoko (`moc`) diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 6a50a2eba71..ac91eb668cc 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -10871,7 +10871,7 @@ and compile_prim_invocation (env : E.t) ae p es at = Region.store_word16 env | OtherPrim ("regionLoadNat32" | "regionLoadInt32"), [e0; e1] -> - SR.Vanilla, + SR.UnboxedWord32, compile_exp_as env ae SR.Vanilla e0 ^^ compile_exp_as env ae SR.UnboxedWord64 e1 ^^ Region.load_word32 env @@ -10880,7 +10880,7 @@ and compile_prim_invocation (env : E.t) ae p es at = SR.unit, compile_exp_as env ae SR.Vanilla e0 ^^ compile_exp_as env ae SR.UnboxedWord64 e1 ^^ - compile_exp_as env ae SR.Vanilla e2 ^^ + compile_exp_as env ae SR.UnboxedWord32 e2 ^^ Region.store_word32 env | OtherPrim ("regionLoadNat64" | "regionLoadInt64"), [e0; e1] -> diff --git a/test/run-drun/ok/region-nat32-bug.drun-run.ok b/test/run-drun/ok/region-nat32-bug.drun-run.ok new file mode 100644 index 00000000000..a6f776f43c6 --- /dev/null +++ b/test/run-drun/ok/region-nat32-bug.drun-run.ok @@ -0,0 +1,2 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/region-nat32-bug.tc.ok b/test/run-drun/ok/region-nat32-bug.tc.ok new file mode 100644 index 00000000000..ed556656930 --- /dev/null +++ b/test/run-drun/ok/region-nat32-bug.tc.ok @@ -0,0 +1,4 @@ +region-nat32-bug.mo:5.5-5.6: warning [M0145], this pattern of type + Nat64 +does not cover value + 1 or 2 or _ diff --git a/test/run-drun/region-nat32-bug.mo b/test/run-drun/region-nat32-bug.mo new file mode 100644 index 00000000000..8d1ad6f5049 --- /dev/null +++ b/test/run-drun/region-nat32-bug.mo @@ -0,0 +1,37 @@ +import Prim "mo:⛔"; +import Region "stable-region/Region"; + +let r = Region.new(); +let 0 = Region.grow(r, 1); + +do { + var i : Nat32 = 0; + while(i < 0xFFFF) { + Region.storeNat32(r, 0, i); + let i32 = Region.loadNat32(r, 0); + let i64 = Region.loadNat64(r, 0); + if (i32 != i or Prim.nat64ToNat32(i64) != i) { + Prim.debugPrint(debug_show({i;i64;i32;bytes=Region.loadBlob(r,0,4)})); + assert(false); + }; + i += 1; + }; +}; + +do { + var i : Nat32 = 0xFFFF_FFFF; + while(i > 0xFFFF_0000) { + Region.storeNat32(r, 0, i); + let i32 = Region.loadNat32(r, 0); + let i64 = Region.loadNat64(r, 0); + if (i32 != i or Prim.nat64ToNat32(i64) != i) { + Prim.debugPrint(debug_show({i;i64;i32;bytes=Region.loadBlob(r,0,4)})); + assert(false); + }; + i -= 1; + }; +} + +//SKIP run-low +//SKIP run +//SKIP run-ir