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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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