fix(arrow-array): align FFI buffers before validation under force_validate - #10798
fix(arrow-array): align FFI buffers before validation under force_validate#10798bit2swaz wants to merge 17 commits into
Conversation
Jefffrey
left a comment
There was a problem hiding this comment.
how is this change tested if the test already passes on main?
|
it passes on main because arrow-rs/arrow-array/Cargo.toml Line 72 in d6b0bd7 so in the and being honest with you: i really couldnt find a way to write a test that exercises the fix under arrow-rs/arrow-data/src/data.rs Lines 2267 to 2268 in d6b0bd7 you cant source it from a valid array either: to be under aligned for the import type youd need a source type with the same byte width but smaller alignment and no arrow primitive fits that ( what is covered: normal builds run the realignment test. under so i can realistically think of two options: leave it as is with the gate and the comment explaining why, or i hand build the which would you prefer? |
lets see how this pans out; i think it would just need creating a decimal128 array, then manually offsetting the pointer by 8 to unalign it (ensuring still stays within allocation bound) 🤔 |
|
done. now the fixture is a valid |
could you double check this? i tried running the test on main (without the accompanying fix) and it still succeeds, both with force_validate enabled and with no default features |
…e-validate # Conflicts: # arrow-array/src/ffi.rs
|
checked it out. thats the old |
|
ah i probably wasnt running with the ffi feature, my bad |
|
i tried again; copying only the arrow-rs (main)$ cargo test -p arrow-array --features ffi --lib under_aligned
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.06s
Running unittests src/lib.rs (/Users/jeffrey/.cargo_target_cache/debug/deps/arrow_array-6904f486d1ee4d68)
running 1 test
test ffi::tests_to_then_from_ffi::test_decimal128_under_aligned_round_trip ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 770 filtered out; finished in 0.00s
arrow-rs (main)$ cargo test -p arrow-array --features force_validate,ffi --lib under_aligned
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.07s
Running unittests src/lib.rs (/Users/jeffrey/.cargo_target_cache/debug/deps/arrow_array-a9af9d70cecd6150)
running 1 test
test ffi::tests_to_then_from_ffi::test_decimal128_under_aligned_round_trip ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 756 filtered out; finished in 0.01scould you double check if this test is exercising a failure behaviour we're supposed to see on main? or am i doing something wrong for reference, this is the copy pasted test as of the state of this PR: // arrow-array/src/ffi.rs
#[test]
fn test_decimal128_under_aligned_round_trip() -> Result<()> {
// 8-byte-aligned i128 buffer: legal over the C Data Interface, but
// under-aligned for arrow-rs. Carried as `FixedSizeBinary(16)` (1-byte
// alignment) so the fixture stays valid under `force_validate`, then
// imported as `Decimal128`, which must realign it.
let aligned = Buffer::from_vec(vec![0_i128, 1_i128, 2_i128]);
let under_aligned = aligned.slice(8);
assert_eq!(under_aligned.as_ptr().align_offset(8), 0);
assert_ne!(under_aligned.as_ptr().align_offset(16), 0);
let data = ArrayData::builder(DataType::FixedSizeBinary(16))
.len(2)
.add_buffer(under_aligned)
.build()?;
let array = FFI_ArrowArray::new(&data);
let imported = unsafe { from_ffi_and_data_type(array, DataType::Decimal128(10, 2)) }?;
let array = Decimal128Array::from(imported);
// [0i128, 1, 2] sliced 8 bytes in yields `1 << 64` and `2 << 64`.
assert_eq!(array.len(), 2);
assert_eq!(array.value(0), 1_i128 << 64);
assert_eq!(array.value(1), 2_i128 << 64);
Ok(())
} |
|
the test passes on the failure only shows up under |
this seems like a bug and something we should fix, especially as it seems the original issue was assuming that |
|
checks out. from what i can see, adding i can file a follow up issue for it if that works |
|
i think it would be preferable to fix the feature issue (make arrow-array force_validate enable arrow-data one) as that gap seems unintuitive, and then keep the test in ffi so it stays close to the relevant code it seems force_validate was added to arrow-array to satisfy a clippy lint, so im assuming it was just a miss that it didnt also enable arrow-data's force_validate: |
|
done and pushed. |
Jefffrey
left a comment
There was a problem hiding this comment.
thanks for persisting with this; almost there, after fixing some merge conflicts
|
done, merged main and pushed #10807 removed the ArrayData path in ready for review again :) |
Which issue does this PR close?
from_ffirealignment is bypassed underforce_validate#10034.Rationale for this change
from_ffirealigned under-aligned C Data Interface buffers (e.g. an 8-byte alignedDecimal128from a JVM producer) afterconsume(). underforce_validate,consume()'sbuild()validates first and rejects the buffer before the realign runs, so spec-legal input errors. reachable via thearrowcrate withfeatures = ["force_validate", "ffi"]callingarrow::ffi::from_ffi.What changes are included in this PR?
ImportedArrowArray::consumebuilds throughArrayDataBuilderwithalign_buffers(true)before validation, matchingarrow-ipc'screate_array_from_builderalign_buffers()calls infrom_ffi/from_ffi_and_data_type.Are these changes tested?
covered by
test_decimal128_under_aligned_round_trip. the issue suggested ungating it underforce_validate, but that isn't possible as its fixture is a misalignedArrayDatabuilt withbuild_unchecked, which validates underforce_validateand so rejects the input at construction, beforefrom_ffiruns. the gate stays with a comment explaining whyAre there any user-facing changes?
no public API change. behavior only changes under
force_validate, where spec-legal under-aligned input is realigned instead of erroring.