Skip to content

segmented_gather produces non-canonical output offsets for sliced gather maps #23826

Description

@VaggelisGian

When the gather map passed to cudf::lists::segmented_gather is a sliced view, the result column has non-canonical offsets: its offsets child starts at a nonzero value even though the materialized column's own offset is 0.

cpp/src/lists/copying/segmented_gather.cu builds the output offsets by copying gather_map.offsets() entries [gather_map.offset(), +size+1) verbatim. For a map sliced at row k, those entries are the parent buffer's cumulative counts starting at o_k, so the result has offsets[0] == K != 0 and offsets.back() != child.size(). The gathered child itself has exactly the sliced element count, so every consumer that interprets offset values as child positions reads out of bounds or misaddressed rows.

Reproduced with libcudf 26.10 nightly: values [10,11],[22],[33,44,55], full map rows {0},{1},{2},{0,1},{2} sliced to rows 2..4 returned a column whose raw offsets child was [2,4,5,7] while an unsliced control returned [0,2,3,5]. Consuming row by row through the stored spans read past the end of the child buffer. The gathered content bytes were correct; only the offsets are shifted.

Note that existing test coverage misses this because CUDF_TEST_EXPECT_COLUMNS_EQUIVALENT normalizes each side by its own first offset before comparing, so a shifted result always compares equal.

Suggested fix: subtract the first copied entry (the value at gather_map.offsets()[gather_map.offset()]) from all copied output offsets, which is a no-op when the map is unsliced since offsets[0] is then 0.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions