X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Lib/test/test_listcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ def test_references___class___defined(self):
code, outputs={"res": [2]}, scopes=["module", "function"])
self._check_in_scopes(code, raises=NameError, scopes=["class"])

def test_references___classdict__(self):
code = """
class i: [__classdict__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___conditional_annotations__(self):
code = """
class i: [__conditional_annotations__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___class___enclosing(self):
code = """
__class__ = 2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :exc:`SystemError` when ``__classdict__`` or
``__conditional_annotations__`` is in a class-scope inlined comprehension.
Found by OSS Fuzz in :oss-fuzz:`491105000`.
26 changes: 23 additions & 3 deletions Python/symtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,8 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
PyObject *k, *v;
Py_ssize_t pos = 0;
int remove_dunder_class = 0;
int remove_dunder_classdict = 0;
int remove_dunder_cond_annotations = 0;

while (PyDict_Next(comp->ste_symbols, &pos, &k, &v)) {
// skip comprehension parameter
Expand All @@ -829,15 +831,27 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
if (existing == NULL && PyErr_Occurred()) {
return 0;
}
// __class__ is never allowed to be free through a class scope (see
// __class__, __classdict__ and __conditional_annotations__ are
// never allowed to be free through a class scope (see
// drop_class_free)
if (scope == FREE && ste->ste_type == ClassBlock &&
_PyUnicode_EqualToASCIIString(k, "__class__")) {
(_PyUnicode_EqualToASCIIString(k, "__class__") ||
_PyUnicode_EqualToASCIIString(k, "__classdict__") ||
_PyUnicode_EqualToASCIIString(k, "__conditional_annotations__"))) {
scope = GLOBAL_IMPLICIT;
if (PySet_Discard(comp_free, k) < 0) {
return 0;
}
remove_dunder_class = 1;

if (_PyUnicode_EqualToASCIIString(k, "__class__")) {
remove_dunder_class = 1;
}
else if (_PyUnicode_EqualToASCIIString(k, "__conditional_annotations__")) {
remove_dunder_cond_annotations = 1;
}
else {
remove_dunder_classdict = 1;
}
}
if (!existing) {
// name does not exist in scope, copy from comprehension
Expand Down Expand Up @@ -877,6 +891,12 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
if (remove_dunder_class && PyDict_DelItemString(comp->ste_symbols, "__class__") < 0) {
return 0;
}
if (remove_dunder_classdict && PyDict_DelItemString(comp->ste_symbols, "__classdict__") < 0) {
return 0;
}
if (remove_dunder_cond_annotations && PyDict_DelItemString(comp->ste_symbols, "__conditional_annotations__") < 0) {
return 0;
}
return 1;
}

Expand Down
Loading
X Tutup