jamesmunns / postcard

A no_std + serde compatible message library for Rust
Apache License 2.0
930 stars 89 forks source link

Postcard error: Found a varint that didn't terminate. Is the usize too big for this platform? #113

Open PSeitz opened 1 year ago

PSeitz commented 1 year ago

As reported by a user here: https://github.com/quickwit-oss/quickwit/issues/3975 Currently we don't have something to reproduce.

The error message seems to be wrong. Looking at the code this seems to occur when there's not enough bytes in the buffer (similar to UnexpectedEOF).

The docs states to support a maximum set of features of serde, but I couldn't find the list of actual supported features.

The code that probably fails is deserializing a Vec<Span>. The datastructures are simple, but there's some custom serde code which I don't know, if it's supported or not.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Span {
    pub trace_id: TraceId,
    #[serde(with = "serde_datetime")]
    pub span_timestamp: DateTime,
}

mod serde_datetime {
    use serde::{Deserialize, Deserializer, Serializer};
    use tantivy::DateTime;

    pub(crate) fn serialize<S>(datetime: &DateTime, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        serializer.serialize_i64(datetime.into_timestamp_nanos())
    }

    pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<DateTime, D::Error>
    where D: Deserializer<'de> {
        let datetime_i64: i64 = Deserialize::deserialize(deserializer)?;
        Ok(DateTime::from_timestamp_nanos(datetime_i64))
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TraceId([u8; 16]);

impl Serialize for TraceId {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let b64trace_id = BASE64_STANDARD.encode(self.0);
        serializer.serialize_str(&b64trace_id)
    }
}

impl<'de> Deserialize<'de> for TraceId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de> {
        let b64trace_id = String::deserialize(deserializer)?;

        if b64trace_id.len() != TraceId::BASE64_LENGTH {
            let message = format!(
                "base64 trace ID must be {} bytes long, got {}",
                TraceId::BASE64_LENGTH,
                b64trace_id.len()
            );
            return Err(de::Error::custom(message));
        }
        let mut trace_id = [0u8; 16];
        BASE64_STANDARD
            // Using the unchecked version here because otherwise the engine gets the wrong size
            // estimate and fails.
            .decode_slice_unchecked(b64trace_id.as_bytes(), &mut trace_id)
            .map_err(|error| {
                let message = format!("failed to decode base64 trace ID: {:?}", error);
                de::Error::custom(message)
            })?;
        Ok(TraceId(trace_id))
    }
}