Skip to content

gh-142884: Fix use-after-free in array.array.tofile() with reentrant writer#144925

Closed
raminfp wants to merge 1 commit intopython:mainfrom
raminfp:fix-array-tofile-uaf
Closed

gh-142884: Fix use-after-free in array.array.tofile() with reentrant writer#144925
raminfp wants to merge 1 commit intopython:mainfrom
raminfp:fix-array-tofile-uaf

Conversation

@raminfp
Copy link
Contributor

@raminfp raminfp commented Feb 17, 2026

array_array_tofile_impl() pre-computes nbytes and nblocks once at the start of the function then iterates in 64 KB blocks, calling f.write() for each block. Since f.write() can execute arbitrary Python code, a reentrant writer callback can mutate the array (clear, shrink, or reallocate), leaving the cached values stale. On the next iteration the loop reads from freed or invalid memory, causing a use-after-free, NULL pointer dereference, or heap-buffer-overflow.

Fix

Temporarily increment self->ob_exports before the write loop to mark the array buffer as exported. This prevents any resize operation during the write() callback — any attempt to mutate the array raises BufferError. This is consistent with how the buffer protocol already protects array buffers (e.g. via memoryview).

Tests

Added three regression tests covering the three mutation variants:

  • test_tofile_reentrant_write_clearwrite() tries to clear the array
  • test_tofile_reentrant_write_shrinkwrite() tries to replace contents with a smaller array
  • test_tofile_reentrant_write_reallocatewrite() tries to clear and append (smaller reallocation)

All three now raise BufferError instead of crashing with a SEGV.

…trant writer

array_array_tofile_impl() pre-computed nbytes and nblocks once at the
start of the function.  If the file-like object's write() callback
mutated the array (e.g. by clearing it or replacing its contents), the
cached values became stale and subsequent iterations read from freed or
invalid memory.

Fix by re-checking Py_SIZE(self) on every loop iteration so the loop
terminates safely when the array is modified during the write callback.
@picnixz
Copy link
Member

picnixz commented Feb 17, 2026

Do not open a PR if there is already one for the issue please. And do not just rely on LLM-generated PRs. In particular, read the devguide: https://devguide.python.org/getting-started/generative-ai/

@raminfp
Copy link
Contributor Author

raminfp commented Feb 17, 2026

@picnixz Thank you. I already had the patch prepared and had seen your suggestion as well. I was rewriting the code when you pointed out that a new PR should not be submitted while the previous one is still open.

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