This is an automated email from the ASF dual-hosted git repository.

Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 4dc1469336 fix(arrow-json): validate ListView child nullability 
(#10486)
4dc1469336 is described below

commit 4dc146933636be970316ebfa536fdd56c2845a9b
Author: Joshua Nwachinemere <[email protected]>
AuthorDate: Thu Jul 30 03:43:09 2026 +0100

    fix(arrow-json): validate ListView child nullability (#10486)
    
    # Which issue does this PR close?
    
    - Closes #10476.
    
    # Rationale for this change
    
    The JSON reader constructs `ListView` arrays without validating child
    nullability. As a result, JSON containing `null` can be accepted for a
    non-nullable child field.
    
    # What changes are included in this PR?
    
    - Replace unchecked `ListView` construction with
    `GenericListViewArray::try_new`, returning an `ArrowError` when child
    nullability is invalid.
    - Add regression coverage for both `ListView` and `LargeListView`.
    
    # Are these changes tested?
    
    Yes:
    
    - `cargo test -p arrow-json
    reader::tests::test_read_list_view_rejects_null_non_nullable_child --
    --exact`
    - `cargo test -p arrow-json --all-features`
    - `cargo clippy --workspace --all-targets --all-features -- -D warnings`
    - `cargo fmt --all -- --check`
    - `git diff --check`
    
    # Are there any user-facing changes?
    
    Yes. Invalid JSON containing a null inside a non-nullable `ListView` or
    `LargeListView` child now returns an error. There is no public API
    change.
---
 arrow-json/src/reader/list_array.rs | 17 +++++++----------
 arrow-json/src/reader/mod.rs        | 28 ++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/arrow-json/src/reader/list_array.rs 
b/arrow-json/src/reader/list_array.rs
index 63644964c3..fc6af59079 100644
--- a/arrow-json/src/reader/list_array.rs
+++ b/arrow-json/src/reader/list_array.rs
@@ -112,16 +112,13 @@ impl<O: OffsetSizeTrait, const IS_VIEW: bool> 
ArrayDecoder for ListLikeArrayDeco
                 sizes.push(offsets[i] - offsets[i - 1]);
             }
             offsets.pop();
-            // SAFETY: offsets and sizes are constructed correctly from the 
tape
-            let array = unsafe {
-                GenericListViewArray::<O>::new_unchecked(
-                    self.field.clone(),
-                    ScalarBuffer::from(offsets),
-                    ScalarBuffer::from(sizes),
-                    values,
-                    nulls,
-                )
-            };
+            let array = GenericListViewArray::<O>::try_new(
+                self.field.clone(),
+                ScalarBuffer::from(offsets),
+                ScalarBuffer::from(sizes),
+                values,
+                nulls,
+            )?;
             Ok(Arc::new(array))
         } else {
             // SAFETY: offsets are built monotonically starting from 0
diff --git a/arrow-json/src/reader/mod.rs b/arrow-json/src/reader/mod.rs
index bc95f9562b..ee8d0a542a 100644
--- a/arrow-json/src/reader/mod.rs
+++ b/arrow-json/src/reader/mod.rs
@@ -2341,6 +2341,34 @@ mod tests {
         assert_read_list_view::<i64>();
     }
 
+    #[test]
+    fn test_read_list_view_rejects_null_non_nullable_child() {
+        let field = Arc::new(Field::new("item", DataType::Int32, false));
+        for (data_type, array_type) in [
+            (DataType::ListView(field.clone()), "ListViewArray"),
+            (DataType::LargeListView(field.clone()), "LargeListViewArray"),
+        ] {
+            let schema = Arc::new(Schema::new(vec![Field::new("lv", data_type, 
true)]));
+            let buf = r#"
+            {"lv": [1, 2, 3]}
+            {"lv": [4, null]}
+            "#;
+
+            let error = ReaderBuilder::new(schema)
+                .build(Cursor::new(buf.as_bytes()))
+                .unwrap()
+                .collect::<Result<Vec<_>, _>>()
+                .unwrap_err();
+
+            assert_eq!(
+                error.to_string(),
+                format!(
+                    "Invalid argument error: Non-nullable field of 
{array_type} \"item\" cannot contain nulls"
+                )
+            );
+        }
+    }
+
     #[test]
     fn test_fixed_size_list() {
         let buf = r#"

Reply via email to