diff --git a/Changelog.md b/Changelog.md index d60d1193ca1..73280cf738c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,21 @@ # Motoko compiler changelog +* motoko (`moc`) + + * Candid decoding: impose an upper limit on the number of values decoded or skipped in a single candid payload, + as a linear function, `max_values`, of binary payload size. + + ``` + max_values(blob) = (blob.size() * numerator)/denominator + bias + ``` + + The current default settings are `{numerator = 1; denominator = 1; bias = 1024 }`, allowing a maximum + of 1024 values plus one additional value per byte in the payload. + + While hopefully not required, the constant factors can be read/modified using system functions: + * Prim.setCandidLimits: `{numerator : Nat32; denominator : Nat32; bias : Nat32 } -> ()` + * Prim.getCandidLimits: `() -> {numerator : Nat32; denominator : Nat32; bias : Nat32 }` + ## 0.12.1 (2024-08-08) * motoko (`moc`) diff --git a/nix/sources.json b/nix/sources.json index b25f0f5d414..1eef3e3c6c2 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -6,10 +6,10 @@ "homepage": "", "owner": "dfinity", "repo": "candid", - "rev": "331217bae379cbebfa531a140f2186c99fae1425", - "sha256": "095w2a4lxy2gd7vfjxn7jszm4x3srw8xlxb1zzd096y6h047rxlj", + "rev": "34b4eb0b581bbf04902e20bf1370e3a293d1956f", + "sha256": "1gr49p938hzm8fq4r3n7j2lzfj0hmah5sb411sma24plnmwy7ljx", "type": "tarball", - "url": "https://github.com/dfinity/candid/archive/331217bae379cbebfa531a140f2186c99fae1425.tar.gz", + "url": "https://github.com/dfinity/candid/archive/34b4eb0b581bbf04902e20bf1370e3a293d1956f.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "esm": { diff --git a/rts/motoko-rts/src/idl.rs b/rts/motoko-rts/src/idl.rs index 21378c4a384..59a9c13bca8 100644 --- a/rts/motoko-rts/src/idl.rs +++ b/rts/motoko-rts/src/idl.rs @@ -11,6 +11,11 @@ use core::cmp::min; use motoko_rts_macros::ic_mem_fn; +extern "C" { + // check instruction decoding limit, exported by moc + pub fn idl_limit_check(decrement: bool, value_count: u64); +} + // // IDL constants // @@ -306,6 +311,7 @@ unsafe fn skip_any_vec(buf: *mut Buf, typtbl: *mut *mut u8, t: i32, count: u32) if count == 0 { return; } + idl_limit_check(false, count as u64); let ptr_before = (*buf).ptr; skip_any(buf, typtbl, t, 0); let ptr_after = (*buf).ptr; @@ -314,6 +320,7 @@ unsafe fn skip_any_vec(buf: *mut Buf, typtbl: *mut *mut u8, t: i32, count: u32) // makes no progress. No point in calling it over and over again. // (This is easier to detect this way than by analyzing the type table, // where we’d have to chase single-field-records.) + idl_limit_check(true, (count - 1) as u64); return; } for _ in 1..count { @@ -332,6 +339,8 @@ unsafe extern "C" fn skip_any(buf: *mut Buf, typtbl: *mut *mut u8, t: i32, depth idl_trap_with("skip_any: too deeply nested record"); } + idl_limit_check(true, 1); // decrement and check quota + if t < 0 { // Primitive type match t { @@ -525,9 +534,9 @@ unsafe extern "C" fn skip_fields(tb: *mut Buf, buf: *mut Buf, typtbl: *mut *mut } } -unsafe fn is_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { +unsafe fn is_null_opt_reserved(typtbl: *mut *mut u8, end: *mut u8, t: i32) -> bool { if is_primitive_type(false, t) { - return t == IDL_PRIM_reserved; + return t == IDL_PRIM_null || t == IDL_PRIM_reserved; } // unfold t @@ -629,7 +638,7 @@ unsafe fn sub( for _ in 0..in1 { let t11 = sleb128_decode(&mut tb1); if in2 == 0 { - if !is_opt_reserved(typtbl1, end1, t11) { + if !is_null_opt_reserved(typtbl1, end1, t11) { break 'return_false; } } else { @@ -651,7 +660,7 @@ unsafe fn sub( for _ in 0..out2 { let t21 = sleb128_decode(&mut tb2); if out1 == 0 { - if !is_opt_reserved(typtbl2, end2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { break 'return_false; } } else { @@ -709,7 +718,7 @@ unsafe fn sub( let t21 = sleb128_decode(&mut tb2); if n1 == 0 { // check all remaining fields optional - if !is_opt_reserved(typtbl2, end2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { break 'return_false; } continue; @@ -725,7 +734,7 @@ unsafe fn sub( } }; if tag1 > tag2 { - if !is_opt_reserved(typtbl2, end2, t21) { + if !is_null_opt_reserved(typtbl2, end2, t21) { // missing, non_opt field break 'return_false; } diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index b9361d10cb7..c88b580cdc1 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -6341,7 +6341,12 @@ module RTS_Exports = struct E.add_export env (nr { name = Lib.Utf8.decode "moc_stable_mem_set_version"; edesc = nr (FuncExport (nr moc_stable_mem_set_version_fi)) - }) + }); + + E.add_export env (nr { + name = Lib.Utf8.decode "idl_limit_check"; + edesc = nr (FuncExport (nr (E.built_in env "idl_limit_check"))) + }) end (* RTS_Exports *) @@ -6531,13 +6536,23 @@ module MakeSerialization (Strm : Stream) = struct G.i (GlobalGet (nr (E.get_global env "__typtbl_idltyps"))) module Registers = struct + + (* interval for checking instruction counter *) + let idl_value_numerator = 1l + let idl_value_denominator = 1l + let idl_value_bias = 1024l + let register_globals env = E.add_global32 env "@@rel_buf_opt" Mutable 0l; E.add_global32 env "@@data_buf" Mutable 0l; E.add_global32 env "@@ref_buf" Mutable 0l; E.add_global32 env "@@typtbl" Mutable 0l; E.add_global32 env "@@typtbl_end" Mutable 0l; - E.add_global32 env "@@typtbl_size" Mutable 0l + E.add_global32 env "@@typtbl_size" Mutable 0l; + E.add_global32 env "@@value_denominator" Mutable idl_value_denominator; + E.add_global32 env "@@value_numerator" Mutable idl_value_numerator; + E.add_global32 env "@@value_bias" Mutable idl_value_bias; + E.add_global64 env "@@value_quota" Mutable 0L let get_rel_buf_opt env = G.i (GlobalGet (nr (E.get_global env "@@rel_buf_opt"))) @@ -6568,6 +6583,88 @@ module MakeSerialization (Strm : Stream) = struct G.i (GlobalGet (nr (E.get_global env "@@typtbl_size"))) let set_typtbl_size env = G.i (GlobalSet (nr (E.get_global env "@@typtbl_size"))) + + let get_value_quota env = + G.i (GlobalGet (nr (E.get_global env "@@value_quota"))) + let set_value_quota env = + G.i (GlobalSet (nr (E.get_global env "@@value_quota"))) + + let get_value_numerator env = + G.i (GlobalGet (nr (E.get_global env "@@value_numerator"))) + let set_value_numerator env = + G.i (GlobalSet (nr (E.get_global env "@@value_numerator"))) + + let get_value_denominator env = + G.i (GlobalGet (nr (E.get_global env "@@value_denominator"))) + let set_value_denominator env = + G.i (GlobalSet (nr (E.get_global env "@@value_denominator"))) + + let get_value_bias env = + G.i (GlobalGet (nr (E.get_global env "@@value_bias"))) + let set_value_bias env = + G.i (GlobalSet (nr (E.get_global env "@@value_bias"))) + + let reset_value_limit env get_blob get_rel_buf_opt = + get_rel_buf_opt ^^ + G.if0 + begin (* Candid deserialization *) + (* Set instruction limit *) + (* Use 32-bit factors and terms to (mostly) avoid 64-bit overflow *) + let (set_product, get_product) = new_local64 env "product" in + get_blob ^^ + Blob.len env ^^ + G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) ^^ + get_value_numerator env ^^ + G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) ^^ + G.i (Binary (Wasm.Values.I64 I64Op.Mul)) ^^ + get_value_denominator env ^^ + G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) ^^ + G.i (Binary (Wasm.Values.I64 I64Op.DivU)) ^^ + set_product ^^ + get_product ^^ + get_value_bias env ^^ + G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) ^^ + G.i (Binary (Wasm.Values.I64 I64Op.Add)) ^^ + set_value_quota env ^^ + (* Saturate value_quota on overflow *) + get_value_quota env ^^ + get_product ^^ + G.i (Compare (Wasm.Values.I64 I64Op.LtU)) ^^ + G.if0 begin + compile_const_64 (-1L) ^^ + set_value_quota env + end + G.nop + end + begin (* Extended candid/ Destabilization *) + G.nop + end + + let define_idl_limit_check env = + Func.define_built_in env "idl_limit_check" + [("decrement", I32Type); ("count", I64Type)] [] (fun env -> + get_rel_buf_opt env ^^ + G.if0 begin (* Candid deserialization *) + get_value_quota env ^^ + G.i (LocalGet (nr 1l)) ^^ (* Count of values *) + G.i (Compare (Wasm.Values.I64 I64Op.LtU)) ^^ + E.then_trap_with env "IDL error: exceeded value limit" ^^ + (* if (decrement) quota -= count *) + G.i (LocalGet (nr 0l)) ^^ + G.if0 begin + get_value_quota env ^^ + G.i (LocalGet (nr 1l)) ^^ + G.i (Binary (Wasm.Values.I64 I64Op.Sub)) ^^ + set_value_quota env + end + G.nop + end begin (* Extended Candid/Destabilization *) + G.nop + end) + + let idl_limit_check env = + G.i (Call (nr (E.built_in env "idl_limit_check"))) + end open Typ_hash @@ -7224,6 +7321,11 @@ module MakeSerialization (Strm : Stream) = struct let get_typtbl_end = Registers.get_typtbl_end env in let get_typtbl_size = Registers.get_typtbl_size env in + (* Decrement and check idl quota *) + compile_unboxed_const 1l ^^ + compile_const_64 1L ^^ + Registers.idl_limit_check env ^^ + (* Check recursion depth (protects against empty record etc.) *) (* Factor 2 because at each step, the expected type could go through one level of opt that is not present in the value type @@ -7642,7 +7744,7 @@ module MakeSerialization (Strm : Stream) = struct end begin match normalize t with - | Opt _ | Any -> Opt.null_lit env + | Prim Null | Opt _ | Any -> Opt.null_lit env | _ -> coercion_failed "IDL error: did not find tuple field in record" end ) ts ^^ @@ -7671,7 +7773,7 @@ module MakeSerialization (Strm : Stream) = struct end begin match normalize f.typ with - | Opt _ | Any -> Opt.null_lit env + | Prim Null | Opt _ | Any -> Opt.null_lit env | _ -> coercion_failed (Printf.sprintf "IDL error: did not find field %s in record" f.lab) end ) (sort_by_hash fs)) ^^ @@ -7733,6 +7835,10 @@ module MakeSerialization (Strm : Stream) = struct ReadBuf.read_sleb128 env get_typ_buf ^^ set_arg_typ ^^ ReadBuf.read_leb128 env get_data_buf ^^ set_len ^^ + (* Don't decrement just check quota *) + compile_unboxed_const 0l ^^ + get_len ^^ G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) ^^ + Registers.idl_limit_check env ^^ get_len ^^ Arr.alloc env ^^ set_x ^^ get_len ^^ from_0_to_n env (fun get_i -> get_x ^^ get_i ^^ Arr.unsafe_idx env ^^ @@ -7978,6 +8084,16 @@ module MakeSerialization (Strm : Stream) = struct (* Allocate memo table, if necessary *) with_rel_buf_opt env extended (get_typtbl_size_ptr ^^ load_unskewed_ptr) (fun get_rel_buf_opt -> + begin + (* set up invariant register arguments *) + get_rel_buf_opt ^^ Registers.set_rel_buf_opt env ^^ + get_data_buf ^^ Registers.set_data_buf env ^^ + get_ref_buf ^^ Registers.set_ref_buf env ^^ + get_typtbl_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl env ^^ + get_maintyps_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl_end env ^^ + get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl_size env ^^ + Registers.reset_value_limit env get_blob get_rel_buf_opt + end ^^ (* set up a dedicated read buffer for the list of main types *) ReadBuf.alloc env (fun get_main_typs_buf -> @@ -7988,7 +8104,7 @@ module MakeSerialization (Strm : Stream) = struct G.concat_map (fun t -> let can_recover, default_or_trap = Type.( match normalize t with - | Opt _ | Any -> + | Prim Null | Opt _ | Any -> (Bool.lit true, fun msg -> Opt.null_lit env) | _ -> (get_can_recover, fun msg -> @@ -8002,15 +8118,6 @@ module MakeSerialization (Strm : Stream) = struct G.if1 I32Type (default_or_trap ("IDL error: too few arguments " ^ ts_name)) (begin - begin - (* set up invariant register arguments *) - get_rel_buf_opt ^^ Registers.set_rel_buf_opt env ^^ - get_data_buf ^^ Registers.set_data_buf env ^^ - get_ref_buf ^^ Registers.set_ref_buf env ^^ - get_typtbl_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl env ^^ - get_maintyps_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl_end env ^^ - get_typtbl_size_ptr ^^ load_unskewed_ptr ^^ Registers.set_typtbl_size env - end ^^ (* set up variable frame arguments *) Stack.with_frame env "frame_ptr" 3l (fun () -> (* idltyp *) @@ -11735,6 +11842,26 @@ and compile_prim_invocation (env : E.t) ae p es at = | OtherPrim "btstInt64", [_;_] -> const_sr (SR.UnboxedWord64 Type.Int64) (Word64.btst_kernel env) + | OtherPrim "setCandidLimits", [e1; e2; e3] -> + SR.unit, + compile_exp_as env ae (SR.UnboxedWord32 Type.Nat32) e1 ^^ + Serialization.Registers.set_value_numerator env ^^ + compile_exp_as env ae (SR.UnboxedWord32 Type.Nat32) e2 ^^ + Serialization.Registers.set_value_denominator env ^^ + Serialization.Registers.get_value_denominator env ^^ + E.else_trap_with env "Candid limit denominator cannot be zero" ^^ + compile_exp_as env ae (SR.UnboxedWord32 Type.Nat32) e3 ^^ + Serialization.Registers.set_value_bias env + + | OtherPrim "getCandidLimits", [] -> + SR.UnboxedTuple 3, + Serialization.Registers.get_value_numerator env ^^ + BoxedSmallWord.box env Type.Nat32 ^^ + Serialization.Registers.get_value_denominator env ^^ + BoxedSmallWord.box env Type.Nat32 ^^ + Serialization.Registers.get_value_bias env ^^ + BoxedSmallWord.box env Type.Nat32 + (* Coercions for abstract types *) | CastPrim (_,_), [e] -> compile_exp env ae e @@ -12823,6 +12950,7 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module = GC.register_globals env; StableMem.register_globals env; Serialization.Registers.register_globals env; + Serialization.Registers.define_idl_limit_check env; (* See Note [Candid subtype checks] *) let set_serialization_globals = Serialization.register_delayed_globals env in diff --git a/src/mo_values/prim.ml b/src/mo_values/prim.ml index 64a1ac0e4e2..5aced3cdd49 100644 --- a/src/mo_values/prim.ml +++ b/src/mo_values/prim.ml @@ -382,4 +382,11 @@ let prim trap = | "canister_version" -> fun _ v k -> as_unit v; k (Nat64 (Numerics.Nat64.of_int 42)) + (* fake *) + | "setCandidLimits" -> + fun _ v k -> k unit + | "getCandidLimits" -> + fun _ v k -> k (Tup [ + Nat32 Numerics.Nat32.zero; Nat32 Numerics.Nat32.zero; Nat32 Numerics.Nat32.zero]) + | s -> trap.trap ("Value.prim: " ^ s) diff --git a/src/prelude/prim.mo b/src/prelude/prim.mo index b750b75dfad..b4032fec57c 100644 --- a/src/prelude/prim.mo +++ b/src/prelude/prim.mo @@ -501,6 +501,26 @@ let call_raw = @call_raw; func performanceCounter(counter : Nat32) : Nat64 = (prim "performanceCounter" : (Nat32) -> Nat64) counter; +// Candid configuration +func setCandidLimits ( + { numerator: Nat32; + denominator: Nat32; + bias: Nat32 } + ) { + (prim "setCandidLimits" : (Nat32, Nat32, Nat32) -> ()) + (numerator, denominator, bias) +}; + +func getCandidLimits() : + { numerator: Nat32; + denominator: Nat32; + bias: Nat32 } { + let (numerator, denominator, bias) = (prim "getCandidLimits" : () -> (Nat32, Nat32, Nat32)) (); + { numerator; + denominator; + bias } +}; + // predicates for motoko-san func forall(f: T -> Bool): Bool { diff --git a/test/bench/ok/bignum.drun-run-opt.ok b/test/bench/ok/bignum.drun-run-opt.ok index 6c2f41a833a..07058c94561 100644 --- a/test/bench/ok/bignum.drun-run-opt.ok +++ b/test/bench/ok/bignum.drun-run-opt.ok @@ -2,5 +2,5 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a000000000000000001 ingress Completed: Reply: 0x4449444c0000 debug.print: {cycles = 2_512_723; size = +59_652} ingress Completed: Reply: 0x4449444c0000 -debug.print: {cycles = 107_695_281; size = +1_817_872} +debug.print: {cycles = 107_695_686; size = +1_817_872} ingress Completed: Reply: 0x4449444c0000 diff --git a/test/bench/ok/bignum.drun-run.ok b/test/bench/ok/bignum.drun-run.ok index b037729f278..23fd2c89444 100644 --- a/test/bench/ok/bignum.drun-run.ok +++ b/test/bench/ok/bignum.drun-run.ok @@ -2,5 +2,5 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a000000000000000001 ingress Completed: Reply: 0x4449444c0000 debug.print: {cycles = 2_619_856; size = +59_652} ingress Completed: Reply: 0x4449444c0000 -debug.print: {cycles = 107_890_020; size = +1_817_872} +debug.print: {cycles = 107_890_430; size = +1_817_872} ingress Completed: Reply: 0x4449444c0000 diff --git a/test/bench/ok/heap-32.drun-run-opt.ok b/test/bench/ok/heap-32.drun-run-opt.ok index c7bc95204b1..252fe116bd8 100644 --- a/test/bench/ok/heap-32.drun-run-opt.ok +++ b/test/bench/ok/heap-32.drun-run-opt.ok @@ -1,5 +1,5 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 ingress Completed: Reply: 0x4449444c0000 debug.print: (50_227, +29_863_068, 708_174_952) -debug.print: (50_070, +32_992_212, 766_613_520) +debug.print: (50_070, +32_992_212, 766_613_800) ingress Completed: Reply: 0x4449444c0000 diff --git a/test/bench/ok/heap-32.drun-run.ok b/test/bench/ok/heap-32.drun-run.ok index 549fd2fc3fb..0d7c2f874b5 100644 --- a/test/bench/ok/heap-32.drun-run.ok +++ b/test/bench/ok/heap-32.drun-run.ok @@ -1,5 +1,5 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 ingress Completed: Reply: 0x4449444c0000 debug.print: (50_227, +29_863_068, 769_000_085) -debug.print: (50_070, +32_992_212, 830_427_128) +debug.print: (50_070, +32_992_212, 830_427_562) ingress Completed: Reply: 0x4449444c0000 diff --git a/test/fail/ok/no-timer-canc.tc.ok b/test/fail/ok/no-timer-canc.tc.ok index 945c0494309..a3d2468f9fd 100644 --- a/test/fail/ok/no-timer-canc.tc.ok +++ b/test/fail/ok/no-timer-canc.tc.ok @@ -114,6 +114,8 @@ no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not floatToText : Float -> Text; floatTrunc : Float -> Float; forall : (T -> Bool) -> Bool; + getCandidLimits : + () -> {bias : Nat32; denominator : Nat32; numerator : Nat32}; getCertificate : () -> ?Blob; hashBlob : Blob -> Nat32; idlHash : Text -> Nat32; @@ -214,6 +216,8 @@ no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not rts_stable_memory_size : () -> Nat; rts_total_allocation : () -> Nat; rts_version : () -> Text; + setCandidLimits : + {bias : Nat32; denominator : Nat32; numerator : Nat32} -> (); setCertifiedData : Blob -> (); shiftLeft : (Nat, Nat32) -> Nat; shiftRight : (Nat, Nat32) -> Nat; diff --git a/test/fail/ok/no-timer-set.tc.ok b/test/fail/ok/no-timer-set.tc.ok index 5b4762cf378..0f9db73e121 100644 --- a/test/fail/ok/no-timer-set.tc.ok +++ b/test/fail/ok/no-timer-set.tc.ok @@ -114,6 +114,8 @@ no-timer-set.mo:3.10-3.18: type error [M0119], object field setTimer is not cont floatToText : Float -> Text; floatTrunc : Float -> Float; forall : (T -> Bool) -> Bool; + getCandidLimits : + () -> {bias : Nat32; denominator : Nat32; numerator : Nat32}; getCertificate : () -> ?Blob; hashBlob : Blob -> Nat32; idlHash : Text -> Nat32; @@ -214,6 +216,8 @@ no-timer-set.mo:3.10-3.18: type error [M0119], object field setTimer is not cont rts_stable_memory_size : () -> Nat; rts_total_allocation : () -> Nat; rts_version : () -> Text; + setCandidLimits : + {bias : Nat32; denominator : Nat32; numerator : Nat32} -> (); setCertifiedData : Blob -> (); shiftLeft : (Nat, Nat32) -> Nat; shiftRight : (Nat, Nat32) -> Nat; diff --git a/test/run-drun/idl-candid-config.mo b/test/run-drun/idl-candid-config.mo new file mode 100644 index 00000000000..b7e329c450e --- /dev/null +++ b/test/run-drun/idl-candid-config.mo @@ -0,0 +1,22 @@ +import { setCandidLimits; getCandidLimits } = "mo:⛔"; + +actor { + + let limits = { numerator = 1 : Nat32; + denominator = 2 : Nat32; + bias = 3 : Nat32 }; + + setCandidLimits(limits); + assert getCandidLimits() == limits; + + + setCandidLimits( + { numerator = 1; + denominator = 0; // should trap + bias = 3 }); +} + +//SKIP run-low +//SKIP run +//SKIP run-ir +//SKIP ic-ref-run diff --git a/test/run-drun/idl-spacebomb.mo b/test/run-drun/idl-spacebomb.mo new file mode 100644 index 00000000000..997f414a743 --- /dev/null +++ b/test/run-drun/idl-spacebomb.mo @@ -0,0 +1,224 @@ +import { debugPrint; errorMessage; call_raw; principalOfActor; charToText; performanceCounter } "mo:⛔"; + +// Space bomb tests + +// Messages in this test all take a lot of time, memory and stack space to decode. +// With infinite resources, these are all valid Candid messages. +// When using Candid in a resource limited environment, for example one consensus round in a blockchain, +// an implementation with self-metering should reject these messages relatively early +// without going through the whole deserialisation process. + +// \80\94\eb\dc\03 is 1000_000_000 +// \80\ad\e2\04 is 10_000_000 +// \ff\ff\3f is 1_048_575 +// \80\b5\18 is 400_000 + +// Tests manually ported from Candid test suite +// https://github.com/dfinity/candid/blob/master/test/spacebomb.test.did + +// Currently we cannot run this particular Candid test suite +// because we rely on IC performance_counter(0) to limit execution. +// and the test suite is run on wasmtime (sans perf counter). + +actor this { + + func toHex(b : Blob) : Text { + let s = debug_show b; + var t = ""; + for (c in s.chars()) { + if (not (c == '\"' or c == '\\')) { + t #= charToText(c) + } + }; + t + }; + + func assert_low_cost() { + let limit : Nat64 = 50_000; + let c = performanceCounter(0); + if (c > limit) debugPrint (debug_show c); + assert performanceCounter(0) < limit; + debugPrint("decoded at low cost"); + }; + + public func vec_null_extra_argument() : async () { + assert_low_cost(); + }; + + public func vec_reserved_extra_argument() : async () { + assert_low_cost(); + }; + + public func zero_sized_record_extra_argument() : async () { + assert_low_cost(); + }; + + public func vec_vec_null_extra_argument() : async () { + assert_low_cost(); + }; + + public func vec_record_emp_extra_argument() : async () { + assert_low_cost(); + }; + + public func vec_opt_record_with_2_20_null_extra_argument() : async () { + assert_low_cost(); + }; + + public func vec_null_not_ignored(_ : [?Nat]) : async () { + assert_low_cost(); + }; + + public func vec_reserved_not_ignored(_ : [Any]) : async () { + assert_low_cost(); + }; + + // this test may be broken + public func zero_sized_record_not_ignored(_ : [{_0_: Null; _1_: {_0_:Any}; _2_: {}}]) : async () { + assert_low_cost(); + }; + + public func vec_vec_null_not_ignored(_ : [[Null]]) : async () { + assert_low_cost(); + }; + + // this test may be broken + public func vec_record_emp_not_ignored(_ : [{}]) : async () { + assert_low_cost(); + }; + + public func vec_null_subtyping(_ : ?Nat) : async () { + assert_low_cost(); + }; + + public func vec_reserved_subtyping(_ : ?Nat) : async () { + assert_low_cost(); + }; + + public func zero_sized_record_subtyping(_ : ?Nat) : async () { + assert_low_cost(); + }; + + public func vec_vec_null_subtyping(_ : [?Nat]) : async () { + assert_low_cost(); + }; + + public func vec_record_emp_subtyping(_ : ?Nat) : async () { + assert_low_cost(); + }; + + public func vec_opt_record_with_2_20_null_subtyping(_ : [?{}]) : async () { + assert_low_cost(); + }; + + func test(m : Text, blobs : [Blob]) : async* () { + let p = principalOfActor(this); + for (blob in blobs.vals()) { + debugPrint (debug_show { function = m; hex = toHex blob}); + try { + ignore await call_raw(p, m, blob); + } + catch e { + debugPrint(errorMessage(e)); + } + } + }; + + public func go() : async () { + + // Plain decoding (unused arguments) + await* test("vec_null_extra_argument", [ + "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" + ]); + + await* test("vec_reserved_extra_argument", [ + "DIDL\01\6d\70\01\00\80\94\eb\dc\03" + ]); + + await* test("zero_sized_record_extra_argument", [ + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" + ]); + + await* test("vec_vec_null_extra_argument", [ + "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" + ]); + + await* test("vec_record_emp_extra_argument", [ + "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" + ]); + + await* test("vec_opt_record_with_2_20_null_extra_argument", [ + "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\05\01\01\01\01\01" + ]); + + // Decoding to actual type + await* test("vec_null_not_ignored", [ + "DIDL\01\6d\7f\01\00\80\94\eb\dc\03", + "DIDL\01\6d\7f\01\00\80\ad\e2\04", + "DIDL\01\6d\7f\01\00\ff\ff\3f", + "DIDL\01\6d\7f\01\00\80\bf\18" + ]); + + await* test("vec_reserved_not_ignored", [ + "DIDL\01\6d\70\01\00\80\94\eb\dc\03" : Blob, + "DIDL\01\6d\70\01\00\80\ad\e2\04" : Blob, + "DIDL\01\6d\70\01\00\ff\ff\3f" : Blob, + "DIDL\01\6d\70\01\00\80\bf\18" : Blob, + ]); + + await* test("zero_sized_record_not_ignored", [ + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\ad\e2\04", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\ff\ff\3f", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\b5\18", + ]); + + await* test("vec_vec_null_not_ignored", [ + "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" + ]); + + await* test("vec_record_emp_not_ignored", [ + "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" + ]); + + // Decoding under opt + await* test("vec_null_subtyping", [ + "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" : Blob, + "DIDL\01\6d\7f\01\00\80\ad\e2\04" : Blob, + "DIDL\01\6d\7f\01\00\ff\ff\3f" : Blob, + "DIDL\01\6d\7f\01\00\80\bf\18" : Blob, + ]); + + await* test("vec_reserved_subtyping", [ + "DIDL\01\6d\70\01\00\80\94\eb\dc\03" : Blob, + "DIDL\01\6d\70\01\00\80\ad\e2\04" : Blob, + "DIDL\01\6d\70\01\00\ff\ff\3f" : Blob, + "DIDL\01\6d\70\01\00\80\bf\18" : Blob, + ]); + + await* test("zero_sized_record_subtyping", [ + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\ad\e2\04", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\ff\ff\3f", + "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\b5\18", + ]); + + await* test("vec_vec_null_subtyping", [ + "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" + ]); + + await* test("vec_record_emp_subtyping", [ + "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" + ]); + + await* test("vec_opt_record_with_2_20_null_subtyping", [ + "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\05\01\01\01\01\01" + ]); + +} + +} +//CALL ingress go "DIDL\x00\x00" +//SKIP run +//SKIP run-ir +//SKIP run-low diff --git a/test/run-drun/idl-sub-opt-any-record.mo b/test/run-drun/idl-sub-opt-any-record.mo index 47b32168d47..b32407ded2c 100644 --- a/test/run-drun/idl-sub-opt-any-record.mo +++ b/test/run-drun/idl-sub-opt-any-record.mo @@ -19,17 +19,17 @@ actor this { public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); - // appending Null not ok + // appending Null ok do { let this = actor (t) : actor { send_f0 : (shared {a : Int; n : Null } -> async {b : Bool; x : Null}) -> async (); }; try { await this.send_f0(f0_1_a); - Prim.debugPrint "wrong_0_1_a"; + Prim.debugPrint "ok_0_1_a"; } catch e { - Prim.debugPrint "ok_0_1_a"; + Prim.debugPrint "wrong_0_1_a"; } }; diff --git a/test/run-drun/idl-sub-opt-any.mo b/test/run-drun/idl-sub-opt-any.mo index b614db34734..881ef8b1da1 100644 --- a/test/run-drun/idl-sub-opt-any.mo +++ b/test/run-drun/idl-sub-opt-any.mo @@ -21,17 +21,17 @@ actor this { public func go() : async () { let t = debug_show (Prim.principalOfActor(this)); - // appending Null not ok + // appending Null ok do { let this = actor (t) : actor { send_f0 : (shared (a : Int, n : Null) -> async (Bool, Null)) -> async (); }; try { await this.send_f0(f0_1_a); - Prim.debugPrint "wrong_0_1_a"; + Prim.debugPrint "ok_0_1_a"; } catch e { - Prim.debugPrint "ok_0_1_a"; + Prim.debugPrint "wrong_0_1_a"; } }; diff --git a/test/run-drun/max-stack-variant.mo b/test/run-drun/max-stack-variant.mo index 692a8e0f431..dbde3b75a6c 100644 --- a/test/run-drun/max-stack-variant.mo +++ b/test/run-drun/max-stack-variant.mo @@ -1,9 +1,11 @@ //MOC-FLAG --compacting-gc --rts-stack-pages 32 -measure-rts-stack -import { errorMessage; debugPrint; } = "mo:⛔"; +import { errorMessage; debugPrint; setCandidLimits} = "mo:⛔"; actor { let expectedMinimumSize = 31_000; - + setCandidLimits{ numerator = 0; + denominator = 1; + bias = 1_000_000 }; public func ser() : async () { await go(false) }; public func deser() : async () { await go(true) }; @@ -37,9 +39,9 @@ actor { done := true } }; - + assert(i > expectedMinimumSize); - + let b = to_candid(l); debugPrint("serialized"); diff --git a/test/run-drun/max-stack.mo b/test/run-drun/max-stack.mo index 74775b0e191..7988aac49b4 100644 --- a/test/run-drun/max-stack.mo +++ b/test/run-drun/max-stack.mo @@ -1,9 +1,11 @@ //MOC-FLAG --compacting-gc --rts-stack-pages 32 -measure-rts-stack -import { errorMessage; debugPrint; } = "mo:⛔"; +import { errorMessage; debugPrint; setCandidLimits } = "mo:⛔"; actor { let expectedMinimumSize = 35_000; - + setCandidLimits{ numerator = 0; + denominator = 1; + bias = 1_000_000 }; public func ser() : async () { await go(false) }; public func deser() : async () { await go(true) }; @@ -27,7 +29,6 @@ actor { if deserialize from_candid(b) else null; - () }; } catch e { @@ -37,7 +38,7 @@ actor { }; assert i > expectedMinimumSize; - + let b = to_candid(l); debugPrint("serialized"); diff --git a/test/run-drun/ok/idl-candid-config.drun-run.ok b/test/run-drun/ok/idl-candid-config.drun-run.ok new file mode 100644 index 00000000000..748fc2deaad --- /dev/null +++ b/test/run-drun/ok/idl-candid-config.drun-run.ok @@ -0,0 +1,2 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Err: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: Candid limit denominator cannot be zero diff --git a/test/run-drun/ok/idl-spacebomb.drun-run.ok b/test/run-drun/ok/idl-spacebomb.drun-run.ok new file mode 100644 index 00000000000..ba492848d38 --- /dev/null +++ b/test/run-drun/ok/idl-spacebomb.drun-run.ok @@ -0,0 +1,73 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: {function = "vec_null_extra_argument"; hex = "4449444C016D7F01008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_extra_argument"; hex = "4449444C016D7001008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_extra_argument"; hex = "4449444C046C03007F010102026C0100706C006D0001038094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_vec_null_extra_argument"; hex = "4449444C026D016D7F010005FFFF3FFFFF3FFFFF3FFFFF3FFFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_record_emp_extra_argument"; hex = "4449444C026D016C00010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_opt_record_with_2_20_null_extra_argument"; hex = "4449444C176C02017F027F6C02010002006C02000101016C02000201026C02000301036C02000401046C02000501056C02000601066C02000701076C02000801086C02000901096C02000A010A6C02000B010B6C02000C010C6C02000D020D6C02000E010E6C02000F010F6C02001001106C02001101116C02001201126C02001301136E146D150116050101010101"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_not_ignored"; hex = "4449444C016D7F01008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_not_ignored"; hex = "4449444C016D7F010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_not_ignored"; hex = "4449444C016D7F0100FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_not_ignored"; hex = "4449444C016D7F010080BF18"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_not_ignored"; hex = "4449444C016D7001008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_not_ignored"; hex = "4449444C016D70010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_not_ignored"; hex = "4449444C016D700100FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_not_ignored"; hex = "4449444C016D70010080BF18"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_not_ignored"; hex = "4449444C046C03007F010102026C0100706C006D0001038094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_not_ignored"; hex = "4449444C046C03007F010102026C0100706C006D00010380ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_not_ignored"; hex = "4449444C046C03007F010102026C0100706C006D000103FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_not_ignored"; hex = "4449444C046C03007F010102026C0100706C006D00010380B518"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_vec_null_not_ignored"; hex = "4449444C026D016D7F010005FFFF3FFFFF3FFFFF3FFFFF3FFFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_record_emp_not_ignored"; hex = "4449444C026D016C00010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_subtyping"; hex = "4449444C016D7F01008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_subtyping"; hex = "4449444C016D7F010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_subtyping"; hex = "4449444C016D7F0100FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_null_subtyping"; hex = "4449444C016D7F010080BF18"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_subtyping"; hex = "4449444C016D7001008094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_subtyping"; hex = "4449444C016D70010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_subtyping"; hex = "4449444C016D700100FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_reserved_subtyping"; hex = "4449444C016D70010080BF18"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_subtyping"; hex = "4449444C046C03007F010102026C0100706C006D0001038094EBDC03"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_subtyping"; hex = "4449444C046C03007F010102026C0100706C006D00010380ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_subtyping"; hex = "4449444C046C03007F010102026C0100706C006D000103FFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "zero_sized_record_subtyping"; hex = "4449444C046C03007F010102026C0100706C006D00010380B518"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_vec_null_subtyping"; hex = "4449444C026D016D7F010005FFFF3FFFFF3FFFFF3FFFFF3FFFFF3F"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_record_emp_subtyping"; hex = "4449444C026D016C00010080ADE204"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +debug.print: {function = "vec_opt_record_with_2_20_null_subtyping"; hex = "4449444C176C02017F027F6C02010002006C02000101016C02000201026C02000301036C02000401046C02000501056C02000601066C02000701076C02000801086C02000901096C02000A010A6C02000B010B6C02000C010C6C02000D020D6C02000E010E6C02000F010F6C02001001106C02001101116C02001201126C02001301136E146D150116050101010101"} +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok b/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok index 4eed30d4928..027584112ce 100644 --- a/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any-record.drun-run.ok @@ -1,5 +1,6 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 ingress Completed: Reply: 0x4449444c0000 +debug.print: ok_0 debug.print: ok_0_1_a debug.print: ok_0 debug.print: ok_0_1_b diff --git a/test/run-drun/ok/idl-sub-opt-any.drun-run.ok b/test/run-drun/ok/idl-sub-opt-any.drun-run.ok index 3eccfc5383f..c3ca7c39455 100644 --- a/test/run-drun/ok/idl-sub-opt-any.drun-run.ok +++ b/test/run-drun/ok/idl-sub-opt-any.drun-run.ok @@ -1,5 +1,6 @@ ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 ingress Completed: Reply: 0x4449444c0000 +debug.print: ok_0 debug.print: ok_0_1_a debug.print: ok_0 debug.print: ok_0_1_b diff --git a/test/run-drun/ok/vec-any-bomb.drun-run.ok b/test/run-drun/ok/vec-any-bomb.drun-run.ok new file mode 100644 index 00000000000..9b1905ecaaa --- /dev/null +++ b/test/run-drun/ok/vec-any-bomb.drun-run.ok @@ -0,0 +1,4 @@ +ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101 +ingress Completed: Reply: 0x4449444c0000 +debug.print: IC0503: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped explicitly: IDL error: exceeded value limit +ingress Completed: Reply: 0x4449444c0000 diff --git a/test/run-drun/vec-any-bomb.mo b/test/run-drun/vec-any-bomb.mo new file mode 100644 index 00000000000..c2cff8aa13c --- /dev/null +++ b/test/run-drun/vec-any-bomb.mo @@ -0,0 +1,22 @@ +//MOC-ENV MOC_UNLOCK_PRIM=yesplease +import Prim "mo:⛔"; + +actor { + + func deserUnit(x : Blob) : () = (prim "deserialize" : Blob -> ()) x; + + public func go () : async () { + try { + await async { deserUnit "DIDL\01\6d\70\01\00\f0\f0\f0\f0\08"; }; + assert false + } + catch e { + Prim.debugPrint(Prim.errorMessage(e)); + } + } +} +//SKIP run +//SKIP run-ir +//SKIP run-low +//SKIP ic-ref +//CALL ingress go "DIDL\x00\x00" diff --git a/test/run/ok/vec-any-bomb.tc.ok b/test/run/ok/vec-any-bomb.tc.ok deleted file mode 100644 index 78529ff2c1f..00000000000 --- a/test/run/ok/vec-any-bomb.tc.ok +++ /dev/null @@ -1 +0,0 @@ -vec-any-bomb.mo:2.8-2.12: warning [M0194], unused identifier Prim (delete or rename to wildcard `_` or `_Prim`) diff --git a/test/run/vec-any-bomb.mo b/test/run/vec-any-bomb.mo deleted file mode 100644 index d790b38caf9..00000000000 --- a/test/run/vec-any-bomb.mo +++ /dev/null @@ -1,9 +0,0 @@ -//MOC-ENV MOC_UNLOCK_PRIM=yesplease -import Prim "mo:⛔"; - -func deserUnit(x : Blob) : () = (prim "deserialize" : Blob -> ()) x; -deserUnit "DIDL\01\6d\70\01\00\f0\f0\f0\f0\08"; - -//SKIP run -//SKIP run-ir -//SKIP run-low