Skip to content

_testcapi mishandles Py_fopen() failures #155905

Description

@serhiy-storchaka

Bug report

Py_fopen() sets an exception and returns NULL on error, but several _testcapi helpers ignore both halves of that contract.

Modules/_testcapi/object.c does not check the result at all. All four helpers pass it straight to PyObject_Print():

    fp = Py_fopen(filename, "w+");

    if (PyObject_Print(object, fp, flags) < 0) {

so a NULL file pointer reaches fprintf() and the interpreter crashes:

>>> import _testcapi
>>> _testcapi.call_pyobject_print('x', '/nonexistent-dir/out.txt', False)
Segmentation fault

The same happens with pyobject_print_null(), pyobject_print_noref_object() and pyobject_print_os_error().

Modules/_testcapimodule.c sets a second exception. The six pymarshal_* helpers do:

    fp = Py_fopen(filename, "rb");
    if (fp == NULL) {
        PyErr_SetFromErrno(PyExc_OSError);
        return NULL;
    }

so OSError is instantiated while Py_fopen()'s exception is still pending:

>>> _testcapi.pymarshal_read_object_from_file('nonexistent')
SystemError: <class 'OSError'> returned a result with an exception set

On a debug build it aborts instead: Objects/call.c:342: _PyObject_Call: Assertion `!_PyErr_Occurred(tstate)' failed.

Both date from f89e5e2 (gh-127350), which converted these helpers from fopen() to Py_fopen(). They affect 3.14 and later.

Related cleanup: these helpers also close the file with fclose() rather than Py_fclose(), which the documentation requires -- 8 sites in object.c, 6 in _testcapimodule.c and 14 in run.c. It is harmless today, since Py_fclose() is just a wrapper.

All other Py_fopen() call sites in the tree check the result correctly.

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixestestsTests in the Lib/test dirtype-bugAn unexpected behavior, bug, or errortype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions