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

@clin1234clin1234 commented May 17, 2026

Copy link
Copy Markdown
Contributor

@clin1234clin1234 changed the title gh-149965: Improve thread-safety in ElementObjectsgh-149965: Improve thread-safety in ElementObjects within element_ass_subscrMay 17, 2026
Comment threadModules/_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
ContributorAuthor

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 threadMisc/NEWS.d/next/Library/2026-05-17-22-42-54.gh-issue-149965.OFW3ZD.rst Outdated
Comment threadModules/_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)

@dimaqqdimaqqJun 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>
clin1234and 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

Copy link
Copy Markdown
ContributorAuthor

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

@picnixz

Copy link
Copy Markdown
Member

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

@picnixzpicnixz closed this Jun 9, 2026
clin1234 pushed a commit to clin1234/cpython that referenced this pull request Jun 10, 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>
Sign up for freeto 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

@clin1234@picnixz@sergey-miryanov@dimaqq@savannahostrowski@serhiy-storchaka@sobolevn@zware@ByteFlowing1337@ttw225