gtk-rs / gtk-rs-core

Rust bindings for GNOME libraries
https://gtk-rs.org/gtk-rs-core
MIT License
293 stars 115 forks source link

[BUG] impl From<InetAddress> for IpAddr mangles IPv6 address #1535

Closed swsnr closed 1 month ago

swsnr commented 1 month ago

Bug description

impl From<InetAddress> for IpAddr mangles IPv6 addresses on conversion. Specifically, this roundtrip test fails on the last assertion:

use gtk::{gio, prelude::InetAddressExtManual};
use std::net::IpAddr;

#[test]
fn test_ipv6_rust_gio_roundtrip() {
    let address = "2606:50c0:8000::153";
    let rust_addr = address.parse::<IpAddr>().unwrap();
    assert!(rust_addr.is_ipv6());

    let gio_addr = gio::InetAddress::from(rust_addr);
    // This assertion passes: gio_addr is still correct; it's string
    // representation matches the original address.
    assert_eq!(gio_addr.to_string(), address);

    // Explicitly converting back to a rust address creates a correct address.
    let rust_addr_2 = match gio_addr.to_bytes() {
        Some(gio::InetAddressBytes::V4(bytes)) => IpAddr::from(*bytes),
        Some(gio::InetAddressBytes::V6(bytes)) => IpAddr::from(*bytes),
        None => panic!("Unsupported IP address"),
    };
    assert_eq!(rust_addr, rust_addr_2);

    // This test fails; The conversion from a GIO address to a Rust address is
    // broken.
    assert_eq!(
        rust_addr,
        IpAddr::from(gio_addr.clone()),
        "{} != {}",
        rust_addr,
        IpAddr::from(gio_addr)
    );
}

The test failure:

     Running tests/convert_socket.rs (target/debug/deps/convert_socket-431bb22aba253d28)

running 1 test
test test_ipv6_rust_gio_roundtrip ... FAILED

failures:

---- test_ipv6_rust_gio_roundtrip stdout ----
thread 'test_ipv6_rust_gio_roundtrip' panicked at tests/convert_socket.rs:25:5:
assertion `left == right` failed: 2606:50c0:8000::153 != 626:c050:80::5301
  left: 2606:50c0:8000::153
 right: 626:c050:80::5301
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    test_ipv6_rust_gio_roundtrip

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test convert_socket`

Note how the original address 2606:50c0:8000::153 ends up being 626:c050:80::5301 after roundtrip.

I'm not sure where this behaviour comes from; I looked at the trait implementation but couldn't make much sense of it. It uses unsafe code and pointer magic, and that's where I'm lost.