diff --git a/rust/candid/src/de.rs b/rust/candid/src/de.rs index 503b27a8..e26e093c 100644 --- a/rust/candid/src/de.rs +++ b/rust/candid/src/de.rs @@ -725,7 +725,6 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - self.dec_value_cost(1)?; visitor.visit_newtype_struct(self) } fn deserialize_option(self, visitor: V) -> Result @@ -851,6 +850,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { let expect = (ek.clone(), ev.clone()); let wire = (wk.clone(), wv.clone()); let len = Len::read(&mut self.input)?.0; + self.dec_value_cost(len)?; visitor.visit_map(Compound::new( self, Style::Map { len, expect, wire }, @@ -1024,7 +1024,9 @@ impl<'de, 'a> de::SeqAccess<'de> for Compound<'a, 'de> { if expect.is_empty() && wire.is_empty() { return Ok(None); } - self.de.dec_value_cost(1)?; + if !wire.is_empty() { + self.de.dec_value_cost(1)?; + } self.de.expect_type = expect .pop_front() .map(|f| f.ty) @@ -1054,15 +1056,16 @@ impl<'de, 'a> de::MapAccess<'de> for Compound<'a, 'de> { match (expect.front(), wire.front()) { (Some(e), Some(w)) => { use std::cmp::Ordering; - self.de.dec_value_cost(1)?; match e.id.get_id().cmp(&w.id.get_id()) { Ordering::Equal => { + self.de.dec_value_cost(1)?; self.de.set_field_name(e.id.clone()); self.de.expect_type = expect.pop_front().unwrap().ty; self.de.wire_type = wire.pop_front().unwrap().ty; } Ordering::Less => { // by subtyping rules, expect_type can only be opt, reserved or null. + self.de.value_cost += 1; // correct the later decrement from serialize_option of producing None. let field = e.id.clone(); self.de.set_field_name(field.clone()); let expect = expect.pop_front().unwrap().ty; @@ -1077,6 +1080,7 @@ impl<'de, 'a> de::MapAccess<'de> for Compound<'a, 'de> { self.de.wire_type = TypeInner::Reserved.into(); } Ordering::Greater => { + self.de.dec_value_cost(1)?; self.de.set_field_name(Label::Named("_".to_owned()).into()); self.de.wire_type = wire.pop_front().unwrap().ty; self.de.expect_type = TypeInner::Reserved.into(); @@ -1090,6 +1094,7 @@ impl<'de, 'a> de::MapAccess<'de> for Compound<'a, 'de> { self.de.expect_type = TypeInner::Reserved.into(); } (Some(e), None) => { + self.de.value_cost += 1; // correct the later decrement from serialize_option of producing None. self.de.set_field_name(e.id.clone()); self.de.expect_type = expect.pop_front().unwrap().ty; self.de.wire_type = TypeInner::Reserved.into(); diff --git a/rust/candid/tests/serde.rs b/rust/candid/tests/serde.rs index 26642781..06de25fc 100644 --- a/rust/candid/tests/serde.rs +++ b/rust/candid/tests/serde.rs @@ -760,10 +760,16 @@ where { use candid::types::value::IDLValue; let mut deserializer = candid::de::IDLDeserialize::new(bytes).unwrap(); - let decoded = deserializer.get_value::().unwrap(); - let cost = deserializer.value_cost(); + let _ = deserializer.get_value::().unwrap(); + let cost1 = deserializer.value_cost(); let _ = deserializer.done().unwrap(); - assert_eq!(cost, decoded.cost()); + + let mut deserializer = candid::de::IDLDeserialize::new(bytes).unwrap(); + let value = deserializer.get_value::().unwrap(); + let cost2 = deserializer.value_cost(); + let _ = deserializer.done().unwrap(); + assert_eq!(cost1, cost2); + assert_eq!(cost2, value.cost()); } } diff --git a/test/spacebomb.test.did b/test/spacebomb.test.did index 5c2d415c..85db704d 100644 --- a/test/spacebomb.test.did +++ b/test/spacebomb.test.did @@ -18,20 +18,6 @@ assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94 assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: () "vec vec null (extra argument)"; assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: () "vec record {} (extra argument)"; -// Messages with exactly 2_000_000 zero-length elements should succeed -assert blob "DIDL\01\6d\7f\01\00\80\89\7a" : () "vec null (exactly 2000000)"; -assert blob "DIDL\01\6d\70\01\00\80\89\7a" : () "vec reserved (exactly 2000000)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\89\7a" : () "zero-sized record (exactly 2000000)"; -assert blob "DIDL\02\6d\01\6d\7f\01\00\05\80\b5\18\80\b5\18\80\b5\18\80\b5\18\80\b5\18" : () "vec vec null (exactly 2000000)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\89\7a" : () "vec record {} (exactly 2000000)"; - -// Messages with exactly 2_000_001 zero-length elements should fail -assert blob "DIDL\01\6d\7f\01\00\80\89\7b" !: () "vec null (exactly 2000001)"; -assert blob "DIDL\01\6d\70\01\00\80\89\7b" !: () "vec reserved (exactly 2000001)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\89\7b" !: () "zero-sized record (exactly 2000001)"; -assert blob "DIDL\02\6d\01\6d\7f\01\00\05\80\b5\18\80\b5\18\80\b5\18\80\b5\18\80\b5\19" !: () "vec vec null (exactly 2000001)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\89\7b" !: () "vec record {} (exactly 2000001)"; - // Decoding to actual type assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: (vec opt nat) "vec null (not ignored)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: (vec reserved) "vec reserved (not ignored)";