Skip to content

Zigzag signed encode/decode overflow #8

Description

@aditink

The zigzag decode helper sign, on input u64::MAX, panics in debug builds and silently returns 0 instead of i64::MIN in release builds.

In src/lib.rs:

fn sign(value: u64) -> i64 {
    if value & 1 != 0 {
        -(((value + 1) / 2) as i64)
    } else {
        (value / 2) as i64
    }
}

u64::MAX is odd, so we enter the if-branch. u64::MAX + 1 overflows u64:

  • Debug: panic with "attempt to add with overflow"
  • Release: wraps to 0, so sign(u64::MAX) silently returns 0 instead of the correct i64::MIN (-9223372036854775808)

This can lead to data corruption. Unit test to reproduce:

#[test]
fn test_roundtrip_i64_min() {
    let mut buf = [0u8; 10];
    let n = signed_encode(i64::MIN, &mut buf);
    let mut out = 0i64;
    signed_decode(&buf[..n], &mut out);
    assert_eq!(out, i64::MIN); // fails: out == 0
}

The encode side (unsign) has a similar overflow (i64::MIN * -2), but wrapping arithmetic accidentally produces the correct result (u64::MAX), so encode works in release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions