Details
-
Sub-task
-
Status: Closed
-
Major
-
Resolution: Fixed
-
0.13.0
-
Patch Available
Description
The Rust library for Thrift uses the integer-encoding crate. In version 1.1.0 (through at least 1.1.3, the most recent version) of this crate Thrift's usage appears to be responsible for a panic in the library when trying to decode i64 numbers in the range 0x4000_0000_0000_0000 to 0x7FFF_FFFF_FFFF_FFFF.
The integer-encoding crate does not panic when using it directly to encode / decode numbers in this range.
To see this, create a scratch crate with "cargo new int_encoding".
Replace the contents of Cargo.toml with the following:
[package] name = "int_encoding" version = "0.1.0" authors = ["Nik Clayton <nik.clayton@dfinity.org>"] edition = "2018" [dependencies] thrift = "0.13.0" integer-encoding = "=1.0.8"
This pins the integer-encoding library to version 1.0.8.
Put the following in src/main.rs:
use thrift::protocol::{ TCompactInputProtocol, TCompactOutputProtocol, TFieldIdentifier, TInputProtocol, TOutputProtocol, TType, }; use integer_encoding::*; fn main() { let mut field_value = i64::max_value(); // Fails // Uncomment the next line to see success //field_value = (1i64 << 62) - 1; let mut buf; println!("Value is: {}, {:X}", field_value, field_value); // First check that encoding and decoding works using the integer_encoding // library directly. buf = field_value.encode_var_vec(); let (val, _) = VarInt::decode_var(&buf[..]); assert_eq!(field_value, val); // Clear the buffer, and try encoding the same value using Thrift. This code // is almost identical to https://docs.rs/thrift/0.13.0/thrift/protocol/index.html // except that (a) it's an I64, and (b) the channel is a Vec. buf.clear(); let mut out_protocol = TCompactOutputProtocol::new(&mut buf); out_protocol .write_field_begin(&TFieldIdentifier::new( "max_int", TType::I64, 1, )) .unwrap(); out_protocol.write_i64(field_value).unwrap(); out_protocol.write_field_end().unwrap(); out_protocol.flush().unwrap(); let mut in_protocol = TCompactInputProtocol::new(&buf[..]); in_protocol.read_field_begin().unwrap(); assert_eq!(field_value, in_protocol.read_i64().unwrap()); in_protocol.read_field_end().unwrap(); }
Run this with "cargo run", it should succeed, and print:
Value is: 9223372036854775807, 7FFFFFFFFFFFFFFF
Edit Cargo.toml and change the "integer-encoding" line to
integer-encoding = "=1.1.3"
Run with "RUST_BACKTRACE=1 cargo run" and you will see the following panic (I've elided the full panic here):
thread 'main' panicked at 'index 11 out of range for slice of length 10', src/libcore/slice/mod.rs:2664:5 stack backtrace: [...] 13: integer_encoding::reader::VarIntProcessor::decode at /Users/nik/d/rs/.cargo-home/registry/src/github.com-1ecc6299db9ec823/integer-encoding-1.1.3/src/reader.rs:56 14: <R as integer_encoding::reader::VarIntReader>::read_varint at /Users/nik/d/rs/.cargo-home/registry/src/github.com-1ecc6299db9ec823/integer-encoding-1.1.3/src/reader.rs:104 15: <thrift::protocol::compact::TCompactInputProtocol<T> as thrift::protocol::TInputProtocol>::read_i64 at /Users/nik/d/rs/.cargo-home/registry/src/github.com-1ecc6299db9ec823/thrift-0.13.0/src/protocol/compact.rs:246 16: int_encoding::main at src/main.rs:41 [...]
As you can see, the panic is coming from the call to Thrift's read_i64(). The earlier code that used integer-encoding directly did not panic. That's why I think the problem is somewhere in Thrift.
If you edit main.rs and uncomment the line
//field_value = (1i64 << 62) - 1;
the panic disappears. I believe this is the largest number that can be used without triggering the panic.
Attachments
Issue Links
- links to