簡體   English   中英

如果我將數據反序列化為錯誤的類型,為什么 bincode 檢測不到錯誤?

[英]Why doesn't bincode detect an error if I deserialize data into the wrong type?

當我嘗試將二進制數據反序列化為錯誤類型時,為什么我不會從 bincode 中收到錯誤消息?

use bincode; // 1.3.1
use serde::{Deserialize, Serialize}; // { version = "1.0", features = ["derive"] }

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct Ping {
    pub pinger_id: usize,
    pub useless_field: usize,
    pub i_need_one_more: usize,
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct Heartbeat {
    pub term: usize,
    pub node_id: usize,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Message {
    Heartbeat(Heartbeat),
    Ping(Ping),
}

fn main() {
    let rpc_message_bin = bincode::serialize(&Ping {
        pinger_id: 0,
        useless_field: 1,
        i_need_one_more: 2,
    })
    .unwrap();
    let m: Message = bincode::deserialize(&rpc_message_bin).unwrap();

    println!("{:#?}", m);
}

我期待收到Message::Ping但我得到:

Heartbeat (
    Heartbeat {
        term: 4294967296,
        node_id: 8589934592,
    },
)

bincode 信任用戶反序列化為預期的類型,你正在做的事情有“隨機”的結果,它是安全的,但它是實現行為。

下面只是一個例子,這可能是錯誤的,但邏輯是正確的。 enum in rust are implementation behavior, bincode is "abusing" rust by assuming an enum is always represented with a unsigned integer value, bincode also choice to encode it as u32 value "enums variants are encoded as a usize u32 u32 is足以滿足所有實際用途。” . 從用戶的角度來看,這並不重要(除了最大2**32變體的enum的“限制”......)。

所以,這就是 bincode 的做法。 在您的代碼中,您要求 bincode 重新加入Ping結構,而不是變體Message::Ping

這意味着編碼緩沖區將包含3個類似Ping結構的usize 然后您要求 bincode 將此數據解釋為Message enum ,基本上這將要求u32從緩沖區中讀取 u32 ,在此示例中,這將通過讀取0得到,而這恰好是數字 rust 和 bincode 用於表示Message enum的第一個變體。 所以 bincode 會認為“好的,我正在閱讀Message::Heartbeat然后 bincode 將再讀取 2 個 usize 以填充Heartbeat結構。就像在 64 位系統中讀取 u32 會引入4個八位字節的偏移量,bincode 不會讀取121 << 322 << 32

這意味着在編碼緩沖區中你有類似的東西

[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]
 ^ first usize        $  ^ second usize       $  ^ last usize         $
 ^ u32    $  ^ first usize       $  ^ second usize       $

從 bincode 的角度來看,這是完全有效的。 bincode 意味着要與閱讀器一起使用,因此閱讀器 cursor 仍有4個八位字節要讀取。

我們可以玩一下,如果你稍微改變一下編碼值pinger_id: usize::MAX ,你會得到一個錯誤信息:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom("invalid value: integer `4294967295`, expected variant index 0 <= i < 2")', src\main.rs:31:61

我們還可以通過將第一個使用大小從Ping更改為usize u32

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct Ping {
    pub pinger_id: u32,
    pub useless_field: usize,
    pub i_need_one_more: usize,
}

現在使用這些值進行編碼:

    let rpc_message_bin = bincode::serialize(&Ping {
        pinger_id: 0,
        useless_field: 1,
        i_need_one_more: 2,
    })

將導致擁有12

Heartbeat(
    Heartbeat {
        term: 1,
        node_id: 2,
    },
)

如果Ping結構太小:

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct Ping {
    pub pinger_id: usize,
}

bincode 會出錯,說缺少數據:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))', src\main.rs:27:61

因此,總而言之,如果將變體反序列化為枚舉類型,則不得發送變體的“直接”值。 使用 bincode 或任何序列化工具時,您必須始終將您編碼的類型與您解碼的類型匹配,因此您必須直接序列化Message::Ping(Ping{.. })而不是Ping {.. }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM