- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 33.3k
gh-140232: Do not track frozenset objects with immutables #140234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 17 commits
a3292c2
              cd294a6
              7e28cf2
              30057a5
              c4deb03
              607237a
              2735a71
              c05db54
              7f6bc4b
              0b97604
              948daed
              08e22c3
              62afc76
              eab653e
              37fc61d
              4f8bda7
              e9d42b4
              4b39149
              2859802
              08f43c5
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|  | @@ -9,6 +9,7 @@ | |||
| import warnings | ||||
| import weakref | ||||
| from random import randrange, shuffle | ||||
| import _testcapi | ||||
| from test import support | ||||
| from test.support import warnings_helper | ||||
|  | ||||
|  | @@ -2154,6 +2155,30 @@ def test_cuboctahedron(self): | |||
| for cubevert in edge: | ||||
| self.assertIn(cubevert, g) | ||||
|  | ||||
| class TestPySet_Add(unittest.TestCase): | ||||
| def test_set(self): | ||||
| # Test the PySet_Add c-api for set objects | ||||
| s = set() | ||||
| assert _testcapi.pyset_add(s, 1) == {1} | ||||
| self.assertRaises(TypeError, _testcapi.pyset_add, s, []) | ||||
|  | ||||
| def test_frozenset(self): | ||||
| # Test the PySet_Add c-api for frozenset objects | ||||
| assert _testcapi.pyset_add(frozenset(), 1) == frozenset([1]) | ||||
| frozen_set = frozenset() | ||||
| self.assertRaises(SystemError, _testcapi.pyset_add, frozen_set, 1) | ||||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why the second test fails, whereas the first succeed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second test fails because the argument  Line 2777 in ce4b0ed 
 I will add a comment to the test | ||||
|  | ||||
| def test_frozenset_gc_tracking(self): | ||||
| # see gh-140234 | ||||
|         
                  efimov-mikhail marked this conversation as resolved.
              Show resolved
            Hide resolved | ||||
| class TrackedHashableClass(): | ||||
| pass | ||||
|  | ||||
| a = TrackedHashableClass() | ||||
| result_set = _testcapi.pyset_add(frozenset(), 1) | ||||
| assert not gc.is_tracked(result_set) | ||||
| result_set = _testcapi.pyset_add(frozenset(), a) | ||||
| assert gc.is_tracked(result_set) | ||||
|         
                  eendebakpt marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||||
|  | ||||
|  | ||||
| #============================================================================== | ||||
|  | ||||
|  | ||||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Frozenset objects with immutable elements are no longer tracked by the garbage collector. | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -1174,6 +1174,23 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) | |
| return make_new_set(type, iterable); | ||
| } | ||
|  | ||
| void | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a comment to explain the purpose of this function with a link to the GitHub issue. | ||
| _PyFrozenSet_MaybeUntrack(PyObject *op) | ||
| { | ||
| if (op == NULL || !PyFrozenSet_CheckExact(op)) { | ||
|          | ||
| return; | ||
| } | ||
| // if no elements of a frozenset are tracked, we untrack the object | ||
|         
                  eendebakpt marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| Py_ssize_t pos = 0; | ||
| setentry *entry; | ||
| while (set_next((PySetObject *)op, &pos, &entry)) { | ||
| if (_PyObject_GC_MAY_BE_TRACKED(entry->key)) { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should use faster  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure performance matters a lot, but I would prefer to have it consistent with what is used in  | ||
| return; | ||
| } | ||
| } | ||
| _PyObject_GC_UNTRACK(op); | ||
| } | ||
|  | ||
| static PyObject * | ||
| make_new_frozenset(PyTypeObject *type, PyObject *iterable) | ||
| { | ||
|  | @@ -1185,7 +1202,9 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) | |
| /* frozenset(f) is idempotent */ | ||
| return Py_NewRef(iterable); | ||
| } | ||
| return make_new_set(type, iterable); | ||
| PyObject *obj = make_new_set(type, iterable); | ||
| _PyFrozenSet_MaybeUntrack(obj); | ||
| return obj; | ||
|         
                  eendebakpt marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| } | ||
|  | ||
| static PyObject * | ||
|  | @@ -2710,7 +2729,9 @@ PySet_New(PyObject *iterable) | |
| PyObject * | ||
| PyFrozenSet_New(PyObject *iterable) | ||
| { | ||
| return make_new_set(&PyFrozenSet_Type, iterable); | ||
| PyObject *result = make_new_set(&PyFrozenSet_Type, iterable); | ||
| _PyFrozenSet_MaybeUntrack(result); | ||
| return result; | ||
| } | ||
|  | ||
| Py_ssize_t | ||
|  | @@ -2779,6 +2800,9 @@ PySet_Add(PyObject *anyset, PyObject *key) | |
| return -1; | ||
| } | ||
|  | ||
| if (PyFrozenSet_CheckExact(anyset) && PyObject_GC_IsTracked(key) && !PyObject_GC_IsTracked(anyset) ) { | ||
| _PyObject_GC_TRACK(anyset); | ||
| } | ||
| int rv; | ||
| Py_BEGIN_CRITICAL_SECTION(anyset); | ||
| rv = set_add_key((PySetObject *)anyset, key); | ||
|  | ||
Uh oh!
There was an error while loading. Please reload this page.