Skip to content

Commit f6eebc2

Browse files
committed
fix: bignum parsed as Value
Fixes: #31 Signed-off-by: Ahmed Charles <[email protected]>
1 parent ba48adc commit f6eebc2

File tree

3 files changed

+67
-37
lines changed

3 files changed

+67
-37
lines changed

ciborium-ll/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,11 @@ mod tests {
460460
Header::Break,
461461
],
462462
),
463+
("c340", &[Header::Tag(3), Header::Bytes(Some(0))]),
464+
(
465+
"c35fff",
466+
&[Header::Tag(3), Header::Bytes(None), Header::Break],
467+
),
463468
];
464469

465470
for (bytes, headers) in data {

ciborium/src/de/mod.rs

+49-21
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ use alloc::{string::String, vec::Vec};
1010

1111
use ciborium_io::Read;
1212
use ciborium_ll::*;
13-
use serde::{de, de::Deserializer as _, forward_to_deserialize_any};
13+
use serde::{
14+
de::{self, value::BytesDeserializer, Deserializer as _},
15+
forward_to_deserialize_any,
16+
};
1417

1518
trait Expected<E: de::Error> {
1619
fn expected(self, kind: &'static str) -> E;
@@ -72,7 +75,11 @@ where
7275
}
7376

7477
#[inline]
75-
fn integer(&mut self, mut header: Option<Header>) -> Result<(bool, u128), Error<R::Error>> {
78+
fn integer<B: FnMut(u8)>(
79+
&mut self,
80+
mut header: Option<Header>,
81+
mut append: Option<B>,
82+
) -> Result<(bool, u128), Error<R::Error>> {
7683
loop {
7784
let header = match header.take() {
7885
Some(h) => h,
@@ -99,7 +106,21 @@ where
99106
while let Some(chunk) = segment.pull(&mut buffer)? {
100107
for b in chunk {
101108
match index {
102-
16 => return Err(de::Error::custom("bigint too large")),
109+
16 => {
110+
if let Some(app) = append.as_mut() {
111+
for v in value {
112+
app(v);
113+
}
114+
app(*b);
115+
index = 17; // Indicate overflow, see below
116+
continue;
117+
}
118+
return Err(de::Error::custom("bigint too large"));
119+
}
120+
17 => { // append is not None
121+
append.as_mut().unwrap()(*b);
122+
continue;
123+
}
103124
0 if *b == 0 => continue, // Skip leading zeros
104125
_ => value[index] = *b,
105126
}
@@ -109,8 +130,12 @@ where
109130
}
110131
}
111132

112-
value[..index].reverse();
113-
Ok((neg, u128::from_le_bytes(value)))
133+
if index == 17 {
134+
Ok((false, 0))
135+
} else {
136+
value[..index].reverse();
137+
Ok((neg, u128::from_le_bytes(value)))
138+
}
114139
}
115140

116141
h => Err(h.expected("bytes")),
@@ -157,18 +182,21 @@ where
157182
let header = self.decoder.pull()?;
158183
self.decoder.push(header);
159184

160-
// If it is bytes, capture the length.
161-
let len = match header {
162-
Header::Bytes(x) => x,
163-
_ => None,
164-
};
165-
166-
match (tag, len) {
167-
(tag::BIGPOS, Some(len)) | (tag::BIGNEG, Some(len)) if len <= 16 => {
168-
let result = match self.integer(Some(Header::Tag(tag)))? {
169-
(false, raw) => return visitor.visit_u128(raw),
170-
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
171-
};
185+
match tag {
186+
tag::BIGPOS | tag::BIGNEG => {
187+
let mut bytes = Vec::new();
188+
let result =
189+
match self.integer(Some(Header::Tag(tag)), Some(|b| bytes.push(b)))? {
190+
(false, _) if !bytes.is_empty() => {
191+
let access = crate::tag::TagAccess::new(
192+
BytesDeserializer::new(&bytes),
193+
Some(tag),
194+
);
195+
return visitor.visit_enum(access);
196+
}
197+
(false, raw) => return visitor.visit_u128(raw),
198+
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
199+
};
172200

173201
match result {
174202
Ok(x) => visitor.visit_i128(x),
@@ -238,7 +266,7 @@ where
238266
}
239267

240268
fn deserialize_i64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
241-
let result = match self.integer(None)? {
269+
let result = match self.integer(None, None::<fn(_)>)? {
242270
(false, raw) => i64::try_from(raw),
243271
(true, raw) => i64::try_from(raw).map(|x| x ^ !0),
244272
};
@@ -250,7 +278,7 @@ where
250278
}
251279

252280
fn deserialize_i128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
253-
let result = match self.integer(None)? {
281+
let result = match self.integer(None, None::<fn(_)>)? {
254282
(false, raw) => i128::try_from(raw),
255283
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
256284
};
@@ -274,7 +302,7 @@ where
274302
}
275303

276304
fn deserialize_u64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
277-
let result = match self.integer(None)? {
305+
let result = match self.integer(None, None::<fn(_)>)? {
278306
(false, raw) => u64::try_from(raw),
279307
(true, ..) => return Err(de::Error::custom("unexpected negative integer")),
280308
};
@@ -286,7 +314,7 @@ where
286314
}
287315

288316
fn deserialize_u128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
289-
match self.integer(None)? {
317+
match self.integer(None, None::<fn(_)>)? {
290318
(false, raw) => visitor.visit_u128(raw),
291319
(true, ..) => Err(de::Error::custom("unexpected negative integer")),
292320
}

ciborium/tests/codec.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,16 @@ macro_rules! map {
6868
case(1i32, val!(1i32), "1b0000000000000001", true, same),
6969
case(1i64, val!(1i64), "1b0000000000000001", true, same),
7070
case(1i128, val!(1i128), "1b0000000000000001", true, same),
71-
case(1u8, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
72-
case(1u16, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
73-
case(1u32, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
74-
case(1u64, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
75-
case(1u128, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
76-
case(1i8, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
77-
case(1i16, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
78-
case(1i32, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
79-
case(1i64, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
80-
case(1i128, bigint(), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
71+
case(1u8, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
72+
case(1u16, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
73+
case(1u32, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
74+
case(1u64, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
75+
case(1u128, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
76+
case(1i8, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
77+
case(1i16, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
78+
case(1i32, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
79+
case(1i64, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
80+
case(1i128, val!(1), "c2540000000000000000000000000000000000000001", true, same), // Not In RFC
8181
case(10u8, val!(10u8), "0a", false, same),
8282
case(10u16, val!(10u16), "0a", false, same),
8383
case(10u32, val!(10u32), "0a", false, same),
@@ -274,6 +274,9 @@ macro_rules! map {
274274
case(Enum::Newtype(45), cbor!({"Newtype" => 45}).unwrap(), "a1674e657774797065182d", false, same), // Not In RFC
275275
case(Enum::Tuple(56, 67), cbor!({"Tuple" => [56, 67]}).unwrap(), "a1655475706c658218381843", false, same), // Not In RFC
276276
case(Enum::Struct { first: 78, second: 89 }, cbor!({ "Struct" => { "first" => 78, "second" => 89 }}).unwrap(), "a166537472756374a2656669727374184e667365636f6e641859", false, same), // Not In RFC
277+
case(hex!("0100000000000000000000000000000000000001"), Value::Tag(2, Value::Bytes(hex!("0100000000000000000000000000000000000001").to_vec()).into()), "c2540100000000000000000000000000000000000001", true, same), // Not In RFC
278+
case(-1i8, val!(-1), "c340", true, same), // Not In RFC
279+
case(-1i8, val!(-1), "c35fff", true, same), // Not In RFC
277280
)]
278281
fn codec<'de, T: Serialize + Clone, V: Debug + PartialEq + DeserializeOwned, F: Fn(T) -> V>(
279282
input: T,
@@ -380,12 +383,6 @@ fn vmap_big() -> Value {
380383
)
381384
}
382385

383-
#[inline]
384-
fn bigint() -> Value {
385-
let bytes = hex::decode("0000000000000000000000000000000000000001").unwrap();
386-
Value::Tag(2, Value::Bytes(bytes).into())
387-
}
388-
389386
#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, Eq)]
390387
struct UnitStruct;
391388

0 commit comments

Comments
 (0)