Skip to content

Clarify ctypes _b_needsfree_ ownership in tagVARIANT and add tests. - #972

Merged
junkmd merged 5 commits into
enthought:mainfrom
junkmd:variant_dunder_del_comment
Oct 18, 2026
Merged

junkmd merged 5 commits into
enthought:mainfrom
junkmd:variant_dunder_del_comment

Conversation

@junkmd

@junkmd junkmd commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

While investigating intermittent CI test failures in #971 for potential resource leaks, I checked tagVARIANT.__del__ and found that the existing comment ("_b_needsfree_ is never set because the buffer is internal to the object") does not reflect modern ctypes behavior.

In CPython's ctypes:

  • Standalone objects (even those within the 16-byte inline buffer such as VARIANT) have obj->b_needsfree = 1 because they own the memory and are responsible for freeing its resources.
  • Other ctypes types/objects that merely reference another object's buffer (such as struct members, array elements, or pointer targets) have obj->b_needsfree = 0 as they lack ownership.

This PR updates the outdated comment in tagVARIANT.__del__ and adds a test verifying that standalone VARIANT instances have _b_needsfree_ == 1 and properly invoke _VariantClear when deleted.

@junkmd junkmd added tests enhance or fix tests ci shared_info use cases, tips and troubleshoots and removed ci labels Oct 18, 2026
@codecov-commenter

codecov-commenter commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.55%. Comparing base (2c38849) to head (fefa623).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #972      +/-   ##
==========================================
+ Coverage   89.53%   89.55%   +0.01%     
==========================================
  Files         143      143              
  Lines       14122    14147      +25     
==========================================
+ Hits        12644    12669      +25     
  Misses       1478     1478              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Correct the outdated comment in `tagVARIANT.__del__`.

Previously, a comment stated that `_b_needsfree_` is never set because
the buffer is internal to the object, suggesting `_VariantClear` was
not invoked.

However, in `ctypes` (`Modules/_ctypes/_ctypes.c`), even when an object fits
within `sizeof(obj->b_value)` (16 bytes) and uses the internal inline
buffer, `obj->b_needsfree` is explicitly initialized to `1`.

As documented in CPython:
> The b_needsfree flag does not mean that we actually did
> call PyMem_Malloc to allocate the memory block; instead it
> means we are the *owner* of the memory and are responsible
> for freeing resources associated with the memory. This is
> also the reason that b_needsfree is exposed to Python.

In `ctypes`, `b_needsfree` is set to `0` only when the object does not own
its buffer (e.g. referencing a parent object's buffer as a struct member,
an array item `arr[0]`, or pointer contents `p.contents`). Standalone
`VARIANT` instances own their buffer, so `_b_needsfree_` is set to `1`
and `__del__` invokes `_VariantClear(self)` as intended.
Verify that `tagVARIANT.__del__` invokes `_VariantClear` for standalone
`VARIANT` instances.

Add `VariantTestCase.test_del_to_clear` to assert that:
- Standalone `VARIANT` instances have `_b_needsfree_ == 1` because they own
  their buffer.
- `_VariantClear` is called when the instance is deleted, clearing its
  type (`VT_EMPTY`) and value.
@junkmd
junkmd force-pushed the variant_dunder_del_comment branch from e9e9785 to fefa623 Compare October 18, 2026 14:22
@junkmd
junkmd merged commit 009c9d1 into enthought:main Oct 18, 2026
145 of 151 checks passed
@junkmd
junkmd deleted the variant_dunder_del_comment branch October 18, 2026 14:56
@junkmd junkmd added this to the 1.5.0 / Support Python 3.15 milestone Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

shared_info use cases, tips and troubleshoots tests enhance or fix tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants