Cintu07 opened a new issue, #10983:
URL: https://github.com/apache/arrow-rs/issues/10983

   ## Describe the bug
   
   `substring` takes `start: i64` and `length: Option<u64>`, and narrows both 
to `i32` with an unchecked cast on the `Utf8` and `Binary` arms 
(`arrow-string/src/substring.rs:87` and `:104`):
   
   ```rust
   DataType::Utf8 => byte_substring(
       array.as_string::<i32>(),
       start as i32,
       length.map(|e| e as i32),
   ),
   ```
   
   a `start` at or above 2^31 wraps to a negative number, and `byte_substring` 
reads a negative start as counting from the end of the value rather than the 
front. so the call does not fail, it silently performs a different operation.
   
   the `LargeUtf8` and `LargeBinary` arms narrow to `i64` instead and are 
unaffected, which makes the same call return different data depending only on 
the offset width of the input.
   
   ## To Reproduce
   
   ```rust
   use arrow_array::{LargeStringArray, StringArray};
   use arrow_string::substring::substring;
   
   let utf8 = StringArray::from(vec![Some("hello"), Some("world")]);
   let large = LargeStringArray::from(vec![Some("hello"), Some("world")]);
   
   // skipping 2^31 characters of a 5 character string should give empty strings
   let start: i64 = 1 << 31;
   
   substring(&utf8, start, None)   // -> ["hello", "world"]
   substring(&large, start, None)  // -> ["", ""]
   ```
   
   ```
   start=2147483648  Utf8       -> [Some("hello"), Some("world")]
   start=2147483648  LargeUtf8  -> [Some(""), Some("")]
   start=3           Utf8       -> [Some("lo"), Some("ld")]        (control)
   ```
   
   the 64 bit path is right. the 32 bit path wraps to `i32::MIN`, takes the 
`Ordering::Less` arm at `substring.rs:361`, clamps to `pair[0]`, and returns 
the whole value.
   
   `length` wraps the same way but surfaces differently. `substring(&utf8, 0, 
Some(1 << 31))` returns
   
   ```
   Compute error: The offset 18446744071562067968 is at an invalid utf-8 
boundary.
   ```
   
   which is an error rather than bad data, but 18446744071562067968 is just 
-2147483648 read back as a `u64`, so the message points at nothing real.
   
   ## Expected behavior
   
   the two offset widths should not disagree. either the out of range value is 
rejected, or the 32 bit arm saturates so it matches what the 64 bit arm already 
does.
   
   i have not sent a patch yet because the choice matters and i would rather 
ask. rejecting with an `InvalidArgumentError` is the smaller change and matches 
how the width overflow in `concat_elements_fixed_size_binary` was handled in 
#10981, but it leaves `Utf8` erroring where `LargeUtf8` returns empty, so the 
two still differ. saturating makes them agree, but `pair[0] + start` inside 
`byte_substring` would then need checked arithmetic since `i32::MAX` plus an 
offset overflows on its own.
   
   happy to send either. i found this looking for the same shape as #10972 
after that one merged.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to