XMLWordPrintableJSON

Details

    • Sub-task
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 0.13.0
    • 0.14.0
    • Rust - Library
    • 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

          Activity

            People

              nikclayton Nik Clayton
              nikclayton Nik Clayton
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 20m
                  20m