obmarg/serde_eetf

Could not convert integer without overflow

Opened this issue · 4 comments

Hey, thanks for this library! It's been a breeze to use so far.

I encountered this issue when de-serializing a value into a u64 type: Could not convert integer without overflow. When I tried to reproduce the error in a test, I see this error instead: panicked at 'could not reconstruct chord message: IntegerConvertError'.

I'm not sure if my usage is incorrect, or if there is a bug in the library itself. Your insight would be really helpful.

I'm including a minimal example of my reproducible error:

// start serializing
let id: u64 = 14529754943055079556;
let ip_addr: SocketAddr = "127.0.0.2:6789".parse().expect("could not parse ip_addr");
let msg = ChordMessage::RectifyRequest(RectifyRequest::new(PeerMetadata::new(
    id,
    ip_addr,
)));

let payload = serde_eetf::to_bytes(&msg).expect("could not serialize message");

let sender = String::from("ChordMembershipService");
let service_msg = ServiceMessage::new(sender.clone(), sender, payload);
let service_payload =
    serde_eetf::to_bytes(&service_msg).expect("could not serialize service message");

let mut datagram = ConnectDatagram::new(service_payload).expect("could not construct datagram");

// start deserializing back
let service_payload_back = datagram.take_payload().unwrap();
let service_msg_back: ServiceMessage = serde_eetf::from_bytes(service_payload_back.as_slice()).expect("could not reconstruct service message");

// The line below is the source of the error
let msg_back: ChordMessage = serde_eetf::from_bytes(service_msg_back.message().as_slice()).expect("could not reconstruct chord message");

if let ChordMessage::RectifyRequest(req)  = msg_back {
    assert_eq!(*req.predecessor().id(), 14529754943055079556);
    assert_eq!(req.predecessor().ip_addr().clone(), ip_addr);
} else {
    assert!(false)
}

Thanks in advance!

Hi @sachanganesh - no problem, glad someone is finding a use for it 👍

So I think this is a result of the underlying eetf library I'm using representing FixIntegers as i32s. You're probably hitting this code path here which tries to convert from an i32 to whatever type you have and returns an IntegerConvertError if it can't.

There's probably an integer field in one of your structs that's either a u32 or some smaller integer. That field must have some value that can't be represented by the type you've provided. Obvious examples would be if you've got an unsigned integer and the number is actually negative, a u8 and the number is > 255, a u16 > 65536 etc.

Is that enough for you to do a bit more investigating? Happy to try and help a bit more if you want, but would need you to share the definitions ofthe structs that you serializing & deserializing.

Also possible you're hitting this path: https://github.com/obmarg/serde_eetf/blob/master/src/de.rs#L84-L94 if you've got a big int rather than a fix int. Looking at that code with fresh eyes not 100% sure it's doing the right thing - happy to accept a fix if you can figure out how/if it's wrong.

I have a feeling it's the second code path, as the example I provided fails with the u64. At the time of writing, it was a verbose message: ChordMessage::RectifyRequest(RectifyRequest::new(PeerMetadata::new( id, ip_addr, )));. The only struct fields involved are the u64 id and SocketAddr ip_addr.

When I find some time I'll try to take a closer look and verify. Thanks for the running start!

Could well be the u64 - I'm converting the BigInt to an i64 first here: https://github.com/obmarg/serde_eetf/blob/master/src/de.rs#L85 which I guess would fail if given a particularly large u64.

Might need to figure out a more reliable way to convert a BigInt into any given T...