Skip to content

Fix memory pool lifetime for Arrow stream buffers - #464

Open
mrdrivingduck wants to merge 1 commit into
alibaba:mainfrom
mrdrivingduck:codex/fix-arrow-buffer-pool-lifetime
Open

Fix memory pool lifetime for Arrow stream buffers#464
mrdrivingduck wants to merge 1 commit into
alibaba:mainfrom
mrdrivingduck:codex/fix-arrow-buffer-pool-lifetime

Conversation

@mrdrivingduck

Copy link
Copy Markdown
Contributor

I found this while debugging an S3 crash. I initially suspected the S3 filesystem, but the issue was in the Arrow input-stream adapter: a returned buffer can outlive its memory pool when a reader is closed while a caller still holds a buffer. This is more likely with network filesystems, where asynchronous reads may finish after the reader is closed.

This patch uses shared_ptr's aliasing constructor to keep the pool alive with the returned buffer. It also adds deterministic coverage for Read, ReadAt, and ReadAsync using a small InputStream mock. Without the change, the tests crash; with it, they pass.

@mrdrivingduck
mrdrivingduck marked this pull request as ready for review July 30, 2026 09:25
Copilot AI review requested due to automatic review settings July 30, 2026 09:25

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.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Fixes a use-after-free risk where Arrow stream buffers can outlive the arrow::MemoryPool used to allocate them, especially when readers are closed while callers still hold buffers (or async reads complete after close).

Changes:

  • Keep the arrow::MemoryPool alive for the lifetime of returned arrow::Buffer objects using shared_ptr aliasing.
  • Add deterministic unit tests covering Read, ReadAt, and ReadAsync with a minimal deferred InputStream mock.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/paimon/common/utils/arrow/arrow_stream_adapter_test.cpp Adds a deferred/mock input stream and new tests that ensure buffers remain valid after the adapter/pool are destroyed.
src/paimon/common/utils/arrow/arrow_input_stream_adapter.cpp Wraps returned buffers so they retain ownership of the memory pool until buffer destruction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/paimon/common/utils/arrow/arrow_stream_adapter_test.cpp Outdated
Comment thread src/paimon/common/utils/arrow/arrow_stream_adapter_test.cpp
Comment thread src/paimon/common/utils/arrow/arrow_input_stream_adapter.cpp
ASSERT_NE(adapter, nullptr);

auto result = adapter->Read(kTestSize);
ASSERT_TRUE(result.ok());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

could you use ASSERT_OK_AND_ASSIGN here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, seems to be an arrow::Result instead of paimon::Result here, so ASSERT_OK_AND_ASSIGN is not supported.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Oh, I misspoke earlier. You can just use std::shared_ptr<arrow::Buffer> buffer = adapter->Read(kTestSize).ValueOrDie(); directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

@zjw1111
zjw1111 requested a review from lucasfang July 31, 2026 05:10
@mrdrivingduck
mrdrivingduck force-pushed the codex/fix-arrow-buffer-pool-lifetime branch 2 times, most recently from dd772d5 to 6e4fa8e Compare July 31, 2026 14:58
Keep the Arrow memory pool alive while stream buffers remain referenced.

Add deterministic coverage for synchronous and asynchronous reads after
adapter teardown.

Co-authored-by: GPT-5.6 Terra <codex@users.noreply.github.com>
@mrdrivingduck
mrdrivingduck force-pushed the codex/fix-arrow-buffer-pool-lifetime branch from 6e4fa8e to 5572ac1 Compare July 31, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants