Skip to content

Modernization notes: dead version guards, deprecated/private APIs, PyDict_GetItem exception swallowing, free-threading gaps #605

Description

@devdanzin

Collected lower-priority findings for consideration:

Exception swallowing

  • PyDict_GetItem x24 across dynamicscope.cpp (8), signaling.cpp (9), weakmethod.cpp (1), compiler_helpers.cpp (5, dead file) silently swallows exceptions. Hot scope resolution and signal dispatch paths are affected. Migrate to PyDict_GetItemWithError (available since 3.3).
  • Unchecked PyDict_SetItem x2 in compiler_helpers.cpp:239-240 — on OOM, execution continues with active exception.
  • Unguarded PyErr_Clear in compiler_helpers.cpp:460 after PyObject_Hash — clears all exceptions including MemoryError. Also, PyErr_Format at line 461 is called without an exception type as first argument (gets a format string instead) — likely crash or garbage exception.

Version compatibility cleanup

  • 9 dead #if PY_VERSION_HEX >= 0x03090000 guards — min is 3.10, these are always true
  • 17 deprecated PyModule_AddObject calls — should migrate to PyModule_AddObjectRef (available since 3.10)
  • PyWeakref_GET_OBJECT deprecated since 3.13, 5 sites across callableref.cpp, weakmethod.cpp, signaling.cpp. Replace with PyWeakref_GetRef (3.13+).
  • PyErr_Fetch/PyErr_Restore in dynamicscope.cpp:135-136 — deprecated in 3.12
  • compiler_helpers.cpp is dead code (not in setup.py) — should be deleted

Private API uses

  • _Py_NewReference x2 (freelist reuse in signaling.cpp:951, declarative_function.cpp:487) — private, may change
  • _PyObject_GetDictPtr x4 (dynamicscope.cpp:100,196,267, signaling.cpp:93) — private, no public equivalent with same semantics
  • _PyType_Lookup x3 (dynamicscope.cpp:91,178,257) — private, used for MRO lookup without descriptor invocation

GC and type notes

  • Alias, Color, Font have PyObject* members but no Py_TPFLAGS_HAVE_GC / tp_traverse — cycles through these types can't be collected
  • Signal has Py_TPFLAGS_HAVE_GC but no PyObject* members (minor overhead, forward-looking)
  • weak_methods dict in weakmethod.cpp — growing mutable global, never cleaned up

Free-threading readiness

  • 2 freelists (BoundSignal, BoundDMethod) without synchronization
  • ~18 global PyObject* across modules — all m_size=0
  • No Py_MOD_GIL_NOT_USED on any module
  • pythoncapi-compat adoption would help with PyModule_AddObjectRef, PyErr_GetRaisedException migrations

Other

  • Copy-paste naming: Nonlocals_Type_slots in fontext.cpp:239 should be Font_Type_slots
  • add_alias incomplete in compiler_helpers.cpp:691-693 — empty branch, never creates the alias
  • BoundSignal_disconnect leaks CallableRef on method-path disconnect (signaling.cpp:854,867)

Found by cext-review-toolkit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions