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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions