VotersWatch issueWatchersLinkCloneUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments
    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

        Activity

          This comment will be Viewable by All Users Viewable by All Users
          Cancel

          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

                Slack

                  Issue deployment