Uploaded image for project: 'Apache Arrow'
  1. Apache Arrow
  2. ARROW-10562

[Rust] Potential UB on unsafe code

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • None
    • 3.0.0
    • Rust
    • None

    Description

      The function set_bits_raw may be (unsafely) accessing memory out of bounds.

      Specifically, if I re-write it in a safe manner, it panics (instead of UB)

      pub fn set_bits_raw(data: &mut [u8], start: usize, end: usize) {
          let start_byte = start >> 3;
          let end_byte = end >> 3;
      
          let start_offset = (start & 7) as u8;
          let end_offset = (end & 7) as u8;
      
          // All set apart from lowest `start_offset` bits
          let start_mask = !((1 << start_offset) - 1);
          // All clear apart from lowest `end_offset` bits
          let end_mask = (1 << end_offset) - 1;
      
          if start_byte == end_byte {
              data[start_byte] |= start_mask & end_mask;
          } else {
              data[start_byte] |= start_mask;
              for i in (start_byte + 1)..end_byte {
                  data[i] = 0xFF;
              }
              data[end_byte] |= end_mask;
          }
      }
      

      A test that panics (and that represents an operation that we peform in `BufferBuilder` would be)

          #[test]
          fn test_set_bits_raw_from_start() {
              let mut buf = vec![0; 1];
              unsafe {set_bits_raw(buf.as_mut(), 0, 0)};
              // 00000000
              assert_eq!(buf[0], 0);
              unsafe {set_bits_raw(buf.as_mut(), 0, 1)};
              // 00000001
              assert_eq!(buf[0], 1);
              unsafe {set_bits_raw(buf.as_mut(), 0, 2)};
              // 00000001
              assert_eq!(buf[0], 3);
              unsafe {set_bits_raw(buf.as_mut(), 0, 7)};
              // 01111111
              assert_eq!(buf[0], 127);
              unsafe {set_bits_raw(buf.as_mut(), 0, 8)};
              // 11111111
              assert_eq!(buf[0], 255);
          }
      

      I think that it is related to the fact that the documentation states that the bounds are non-inclusive, but the `end` seems to be inclusive.

      Attachments

        Activity

          People

            jorgecarleitao Jorge Leitão
            jorgecarleitao Jorge Leitão
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: