Skip to content

gh-149965: Improve thread-safety in ElementObjects within element_ass_subscr#149966

Closed
clin1234 wants to merge 23 commits into
python:mainfrom
clin1234:patch-4
Closed

gh-149965: Improve thread-safety in ElementObjects within element_ass_subscr#149966
clin1234 wants to merge 23 commits into
python:mainfrom
clin1234:patch-4

Conversation

@clin1234

@clin1234 clin1234 commented May 17, 2026

Copy link
Copy Markdown
Contributor

@clin1234 clin1234 changed the title gh-149965: Improve thread-safety in ElementObjects gh-149965: Improve thread-safety in ElementObjects within element_ass_subscr May 17, 2026
Comment thread Modules/_elementtree.c Outdated

// Pointer-by-pointer memmove for PyObject** arrays that is safe
// for shared ElementObjects in Py_GIL_DISABLED builds.
static void

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.

I'm not sure we should duplicate ptr_wise_atomic_memmove here.

Could you please link to the related C-API Working group issue in this PR, and cross-reference it in the original issue?

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.

Since the function is not exposed as part of the public API, I don't think linking a C-API Working Group issue is needed here.

Anyway, it's inspired by #149936

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.

I'll add a link to capi-workgroup/decisions#106 for traceability.

Comment thread Misc/NEWS.d/next/Library/2026-05-17-22-42-54.gh-issue-149965.OFW3ZD.rst Outdated
Comment thread Modules/_elementtree.c Outdated
// Pointer-by-pointer memmove for PyObject** arrays that is safe
// for shared ElementObjects in Py_GIL_DISABLED builds.
static void
ptr_wise_atomic_memmove(ElementObject *a, PyObject **dest, PyObject **src, Py_ssize_t n)

@dimaqq dimaqq Jun 9, 2026

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.

This function needs own set of unit tests, for:

  • gil disabled
  • single owner
  • dest < src
  • dest > str
  • dest == src
    • crazy, but someone will call it this way
    • or an hard assertion forbidding such call
    • or a short-circuit path if it's a no-on
  • dest != src, but ranges overlap

clin1234 pushed a commit to clin1234/cpython that referenced this pull request Jun 9, 2026
…ternal helper and add unit tests

Extract the duplicated static `ptr_wise_atomic_memmove` from
`Modules/_elementtree.c` and `Objects/listobject.c` into a shared
`static inline _Py_ptr_wise_atomic_memmove(PyObject *a, ...)` in
`Include/internal/pycore_object.h`.  The first parameter is generalised
from a type-specific pointer to `PyObject *` since only `PyObject *`-
level operations (`_Py_IsOwnedByCurrentThread`, `_PyObject_GC_IS_SHARED`)
were ever performed on it.

`listobject.c` previously embedded `_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED`
inside the local helper.  That assertion is preserved by moving it
explicitly to each of the four call sites in `listobject.c` (which are
all called under a critical section).  `_elementtree.c`'s open question
about whether a critical section is needed remains unanswered, so no
assertion is added there.

Unit tests are added in `Modules/_testinternalcapi/test_ptr_wise_memmove.c`
covering: dest < src (forward copy), dest > src (backward copy),
dest == src (no-op), overlapping ranges, and the single-owner fast path.
The single-owner test explicitly clears the GC SHARED bit to guard against
freelist reuse leaving the bit set from a sibling test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
clin1234 and others added 17 commits June 9, 2026 14:45
Commented out critical section assertion for ElementObject.
…FW3ZD.rst

Co-authored-by: Sergey Miryanov <sergey.miryanov@gmail.com>
…ternal helper and add unit tests

Extract the duplicated static `ptr_wise_atomic_memmove` from
`Modules/_elementtree.c` and `Objects/listobject.c` into a shared
`static inline _Py_ptr_wise_atomic_memmove(PyObject *a, ...)` in
`Include/internal/pycore_object.h`.  The first parameter is generalised
from a type-specific pointer to `PyObject *` since only `PyObject *`-
level operations (`_Py_IsOwnedByCurrentThread`, `_PyObject_GC_IS_SHARED`)
were ever performed on it.

`listobject.c` previously embedded `_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED`
inside the local helper.  That assertion is preserved by moving it
explicitly to each of the four call sites in `listobject.c` (which are
all called under a critical section).  `_elementtree.c`'s open question
about whether a critical section is needed remains unanswered, so no
assertion is added there.

Unit tests are added in `Modules/_testinternalcapi/test_ptr_wise_memmove.c`
covering: dest < src (forward copy), dest > src (backward copy),
dest == src (no-op), overlapping ranges, and the single-owner fast path.
The single-owner test explicitly clears the GC SHARED bit to guard against
freelist reuse leaving the bit set from a sibling test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ible on instances (pythonGH-139820)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
@clin1234 clin1234 requested review from hugovk and webknjaz as code owners June 9, 2026 18:51
@clin1234

clin1234 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@ericsnowcurrently, mind taking a look on helping me on resolving the mutable global variable issue in Modules/_testinternalcapi/test_ptr_wise_memmove.c?

@picnixz

picnixz commented Jun 9, 2026

Copy link
Copy Markdown
Member

I tzhink the merge was messed up. There are unrelated changes. Please re-open a cleaner PR.

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.

10 participants