Skip to content

Missing PyErr_Occurred() after PyIter_Next in 3 functions + CAtom_getstate error handling gaps #258

@devdanzin

Description

@devdanzin

Three PyIter_Next loops are missing PyErr_Occurred() checks after the loop terminates. PyIter_Next returns NULL for both StopIteration (normal) and errors. Without the check, iteration errors are silently swallowed.

The observe/unobserve functions in the same file (catom.cpp:227,264,294) correctly have if(PyErr_Occurred()) return 0; after their loops — the pattern was not propagated.

1. CAtom_setstate (catom.cpp:472-484)

Reproducer:

import gc; gc.disable()
import os
from atom.api import Atom, Int, Str

class EvilDict(dict):
    def __iter__(self):
        yield "x"
        raise RuntimeError("iteration bomb")

b = Atom.__new__(type("MyAtom", (Atom,), {"x": Int(0)}))
try:
    b.__setstate__(EvilDict({"x": 10}))
    print("__setstate__ succeeded (BUG - error swallowed)")
except RuntimeError:
    print("RuntimeError propagated (correct)")
os._exit(0)

On debug builds: Fatal Python error: _Py_CheckFunctionResult: a function returned a result with an exception set. On release builds: error silently swallowed.

2. validate_set (atomset.cpp:76-88)

Same pattern — iteration error during set validation silently ignored, returns partially validated set.

3. SortedMap_new (sortedmap.cpp:320-328)

Same pattern — iteration error during SortedMap construction silently ignored.

Also: CAtom_getstate missing PyErr_Clear (catom.cpp:403-407)

After PyObject_GetAttr fails with AttributeError (attribute not found), the continue proceeds without PyErr_Clear(), leaving the exception set. The comment says "it is not an error if the attribute is not present" but the exception is not actually cleared.

Also: CAtom_getstate returns NULL without exception (catom.cpp)

On certain error paths returns 0 (NULL) without ensuring an exception is set → SystemError: returned NULL without exception.

Fix for all PyIter_Next sites — add after each loop:

if( PyErr_Occurred() )
    return 0;

Fix for getstate PyErr_Clear — add PyErr_Clear(); before continue at line 407.

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