Skip to content

gh-141510: Add can_modify_dict() in dictobject.c#144955

Merged
vstinner merged 1 commit intopython:mainfrom
vstinner:frozendict_can_modify
Feb 18, 2026
Merged

gh-141510: Add can_modify_dict() in dictobject.c#144955
vstinner merged 1 commit intopython:mainfrom
vstinner:frozendict_can_modify

Conversation

@vstinner
Copy link
Member

@vstinner vstinner commented Feb 18, 2026

can_modify_dict() is stricter than ASSERT_DICT_LOCKED() for frozendict. It uses PyUnstable_Object_IsUniquelyReferenced() which matters for free-threaded builds.

Replace anydict_setitem_take2() with setitem_take2_lock_held(). It's no longer useful to have two functions.

can_modify_dict() is stricter than ASSERT_DICT_LOCKED() for
frozendict. It uses PyUnstable_Object_IsUniquelyReferenced() which
matters for free-threaded builds.

Replace anydict_setitem_take2() with setitem_take2_lock_held(). It's
no longer useful to have two functions.
Copy link
Member

@corona10 corona10 left a comment

Choose a reason for hiding this comment

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

Just to share my thoughts:

  1. When we implement an xxx_lock_held function, I believe the goal is to ensure that developers declare critical sections properly through assertions. This change could cause confusion if someone starts calling xxx_lock_held, since it may require ASSERT_DICT_LOCKED for mutable collections but not for immutable ones.
  2. My personal view is that assertions should report consistent results whenever possible. As I understand it, PyUnstable_Object_IsUniquelyReferenced does not guarantee this. Its result depends on the runtime situation, which means we could miss buggy scenarios until they are triggered in CI.

It does not mean -1 on this change but prefer to listen other core devs opinion.

Copy link
Member

@corona10 corona10 left a comment

Choose a reason for hiding this comment

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

I changed my mind after DM with Victor.
Since the current assertion is only meaningful when the refcount is not 1.

# define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op) \
if (Py_REFCNT(op) != 1) { \
_PyCriticalSection_AssertHeldObj(_PyObject_CAST(op)); \
}

@vstinner
Copy link
Member Author

This change does multiple things:

  • It prepares dictobject.c to access frozendict without locking. @corona10 already made the first change for that in _PyDict_FromKeys() (commit d1b541b).
  • Check for bugs: we must not modify a frozendict if its ref count is greater than 1 (since frozendicts are immutable!). ASSERT_DICT_LOCKED() check is not the right function to check that.

@vstinner vstinner merged commit 1ddb412 into python:main Feb 18, 2026
53 checks passed
@vstinner vstinner deleted the frozendict_can_modify branch February 18, 2026 14:47
@vstinner
Copy link
Member Author

Merged. Thanks for your review @corona10.

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

Comments