Skip to content

GH-51041: [Python] Reject non-Buffer FunctionOptions.deserialize input - #51129

Open
1fanwang wants to merge 1 commit into
apache:mainfrom
1fanwang:1fannnw/reject-non-buffer-deserialize
Open

GH-51041: [Python] Reject non-Buffer FunctionOptions.deserialize input#51129
1fanwang wants to merge 1 commit into
apache:mainfrom
1fanwang:1fannnw/reject-non-buffer-deserialize

Conversation

@1fanwang

@1fanwang 1fanwang commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Rationale for this change

Calling pyarrow.compute.FunctionOptions.deserialize() with anything that is not a Buffer crashes the interpreter. None, an int, a list and a bytes object all segfault, so a caller who passes the wrong object, or who forwards an unvalidated value, loses the process rather than seeing an exception.

deserialize() hands its argument to pyarrow_unwrap_buffer(), which returns a null pointer for a non-Buffer. The deref() on the next line then dereferences null.

Before this change the call terminates the process. After it, the call raises TypeError naming the type it received.

What changes are included in this PR?

The static method now declares its parameter as Buffer buf not None, which is what its docstring already says it takes. Cython rejects a wrong type before the unwrap runs, so the null pointer is never produced.

Are these changes tested?

Yes, by a parametrized case over the four inputs above.

Red, with this commit's source file reverted to its parent
$ git checkout HEAD~1 python/pyarrow/_compute.pyx
$ pip install -e python --no-build-isolation
$ python -X faulthandler -c "import pyarrow.compute as pc; pc.FunctionOptions.deserialize(None)"
Fatal Python error: Segmentation fault

Current thread 0x00000001f6fbe180 (most recent call first):
  File "<string>", line 1 in <module>

Extension modules: numpy._core._multiarray_umath, numpy.linalg._umath_linalg, pyarrow.lib, pyarrow._compute (total: 4)

The same crash occurs for 1, [] and b''.

Green, with the fix applied
$ git checkout HEAD -- python/pyarrow/_compute.pyx
$ pip install -e python --no-build-isolation
$ python -m pytest pyarrow/tests/test_compute.py -k deserialize_rejects_non_buffers -v
collected 607 items / 603 deselected / 4 selected

pyarrow/tests/test_compute.py::test_function_options_deserialize_rejects_non_buffers[None] PASSED [ 25%]
pyarrow/tests/test_compute.py::test_function_options_deserialize_rejects_non_buffers[1] PASSED [ 50%]
pyarrow/tests/test_compute.py::test_function_options_deserialize_rejects_non_buffers[value2] PASSED [ 75%]
pyarrow/tests/test_compute.py::test_function_options_deserialize_rejects_non_buffers[] PASSED [100%]

====================== 4 passed, 603 deselected in 0.06s =======================
$ for v in None 1 "[]" "b''"; do python -c "
import pyarrow.compute as pc
try:
    pc.FunctionOptions.deserialize($v)
except TypeError as e:
    print('$v', '->', e)
"; done
None -> Argument 'buf' has incorrect type (expected pyarrow.lib.Buffer, got NoneType)
1 -> Argument 'buf' has incorrect type (expected pyarrow.lib.Buffer, got int)
[] -> Argument 'buf' has incorrect type (expected pyarrow.lib.Buffer, got list)
b -> Argument 'buf' has incorrect type (expected pyarrow.lib.Buffer, got bytes)

A valid buffer still round-trips, and the rest of test_compute.py is unaffected.

Round-trip and full suite
$ python -c "import pyarrow.compute as pc; o = pc.ArraySortOptions(order='descending'); print(pc.FunctionOptions.deserialize(o.serialize()) == o)"
True

$ python -m pytest pyarrow/tests/test_compute.py -q
584 passed, 23 skipped, 11 warnings in 3.09s

Are there any user-facing changes?

Passing a non-Buffer to FunctionOptions.deserialize() now raises TypeError instead of terminating the process. Callers already passing a Buffer, which is what the docstring documents, are unaffected.

Copilot AI lite review requested due to automatic review settings September 1, 2026 22:54
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

⚠️ GitHub issue #51041 has been automatically assigned in GitHub to PR creator.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change directly prevents a verified crash path by enforcing the documented input type and includes focused regression test coverage for the reported segfault cases.

Pull request overview

This PR hardens the PyArrow compute Python bindings by preventing pyarrow.compute.FunctionOptions.deserialize() from dereferencing a null C++ buffer when callers pass non-Buffer objects, converting a potential interpreter crash into a Python TypeError.

Changes:

  • Tighten the FunctionOptions.deserialize Cython signature to require Buffer buf not None, so invalid types are rejected before unwrapping.
  • Add a pytest parametrized regression test covering several non-Buffer inputs that previously segfaulted.
File summaries
File Description
python/pyarrow/_compute.pyx Adds a typed/non-null Buffer parameter to FunctionOptions.deserialize to prevent null dereference on invalid inputs.
python/pyarrow/tests/test_compute.py Adds a regression test asserting TypeError for non-Buffer inputs to FunctionOptions.deserialize.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…e input

deserialize() passed its argument straight to pyarrow_unwrap_buffer(),
which returns a null pointer for anything that is not a Buffer. The
following deref() then dereferenced null, so None, an int, a list or a
bytes object crashed the interpreter instead of raising.

Generated-by: GitHub Copilot CLI (Claude Opus 5)
Signed-off-by: 1fanwang <1fannnw@gmail.com>
@1fanwang
1fanwang force-pushed the 1fannnw/reject-non-buffer-deserialize branch from 4ee51c3 to b725d23 Compare September 1, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants