### What did you do? Created an image with `Image.fromarrow` and passed it to `pyarrow.array`. ```python from PIL import Image import pyarrow as pa im = Image.fromarrow(pa.array([0] * 100, type=pa.uint8()), "RGBA", (5, 5)) im.getpixel((0, 0)) # fine pa.array(im) # segmentation fault ``` The same happens with a single band image (`"L"` from 25 values), with `im.__arrow_c_array__()` called directly, and on Pillow 11.3.0, 12.3.0 and current `main` (098de8a6e). After any change to the image (`im.putpixel((0, 0), (1, 2, 3, 4))`, which copies the storage) the export works. ### What did you expect to happen? An Arrow array with the same values, as for any other image, or a `ValueError` if a borrowed image cannot be exported. The docstring of `fromarrow` shows both directions (`Image.fromarrow(...)` and `pa.array(im)`), so a round trip is the documented usage. ### What actually happened? The process dies with SIGSEGV (exit code 139), nothing is printed. ### Why `ImagingBorrowArrow` (`src/libImaging/Storage.c`) fills only the row pointers `im->image[y]` of the borrowed image and leaves `im->block` and `im->blocks` NULL. `export_single_channel_array` and `export_fixed_pixel_array` (`src/libImaging/Arrow.c`) take the data pointer from `im->block`, or from `im->blocks[0].ptr` when `block` is NULL: ```c if (im->block) { array->buffers[1] = im->block; } else { array->buffers[1] = im->blocks[0].ptr; } ``` For a borrowed image `blocks` is NULL, so this dereferences NULL. The `im->blocks_count > 1` check above it does not catch this case, `blocks_count` is 0. `Tests/test_pyarrow.py` compares `fromarrow` images with `getpixel`, so the round trip is not covered. ### Possible fix A borrowed array is accepted only when its length matches the image exactly, so its rows are contiguous and the export can use the first row. Adding a branch at both places: ```c if (im->block) { array->buffers[1] = im->block; } else if (im->arrow_array_capsule) { array->buffers[1] = im->image[0]; } else { array->buffers[1] = im->blocks[0].ptr; } ``` With this change (built from `main`) the example returns `fixed_size_list<RGBA: uint8 not null>[4]` with the original values, and the `"L"` case returns the 25 values. ### Context pillow-heif is moving its plugin to `Image.fromarrow`, so every HEIF image opened with `Image.open` would be a borrowed image, and `pa.array(im)` on such an image would crash. We are holding that release until this is fixed in Pillow. ### What are your OS, Python and Pillow versions? * OS: macOS 26.5 arm64 * Python: 3.14.5 * Pillow: 11.3.0, 12.3.0, main (098de8a6e) * pyarrow: 25.0.1