https://github.com/python/cpython/commit/c392157f5836bccfe1c67d80ae39c42a1ca8e23f
commit: c392157f5836bccfe1c67d80ae39c42a1ca8e23f
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-29T16:32:57Z
summary:

[3.14] gh-155905: Fix error handling in _testcapi helpers (GH-155906) 
(GH-156581)

Py_fopen() sets an exception and returns NULL on error.  The
pyobject_print*() helpers did not check the result and crashed, and the
pymarshal_*() helpers set a second exception on top of it.

The pyobject_print*() helpers which take a single argument now use
METH_O, and the result of PyUnicode_FromString() is now checked.
(cherry picked from commit a175da7a3ae3ba8d8aab9225c755bb41782edb4c)

Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

files:
M Modules/_testcapi/object.c
M Modules/_testcapimodule.c

diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c
index 4d53b3c678a470..88b8962ab153a3 100644
--- a/Modules/_testcapi/object.c
+++ b/Modules/_testcapi/object.c
@@ -16,6 +16,9 @@ call_pyobject_print(PyObject *self, PyObject * args)
     }
 
     fp = Py_fopen(filename, "w+");
+    if (fp == NULL) {
+        return NULL;
+    }
 
     if (Py_IsTrue(print_raw)) {
         flags = Py_PRINT_RAW;
@@ -32,17 +35,15 @@ call_pyobject_print(PyObject *self, PyObject * args)
 }
 
 static PyObject *
-pyobject_print_null(PyObject *self, PyObject *args)
+pyobject_print_null(PyObject *self, PyObject *filename)
 {
-    PyObject *filename;
     FILE *fp;
 
-    if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
+    fp = Py_fopen(filename, "w+");
+    if (fp == NULL) {
         return NULL;
     }
 
-    fp = Py_fopen(filename, "w+");
-
     if (PyObject_Print(NULL, fp, 0) < 0) {
         fclose(fp);
         return NULL;
@@ -54,26 +55,29 @@ pyobject_print_null(PyObject *self, PyObject *args)
 }
 
 static PyObject *
-pyobject_print_noref_object(PyObject *self, PyObject *args)
+pyobject_print_noref_object(PyObject *self, PyObject *filename)
 {
     PyObject *test_string;
-    PyObject *filename;
     FILE *fp;
     char correct_string[100];
 
     test_string = PyUnicode_FromString("Spam spam spam");
+    if (test_string == NULL) {
+        return NULL;
+    }
 
     Py_SET_REFCNT(test_string, 0);
 
     PyOS_snprintf(correct_string, 100, "<refcnt %zd at %p>",
                   Py_REFCNT(test_string), (void *)test_string);
 
-    if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
+    fp = Py_fopen(filename, "w+");
+    if (fp == NULL) {
+        Py_SET_REFCNT(test_string, 1);
+        Py_DECREF(test_string);
         return NULL;
     }
 
-    fp = Py_fopen(filename, "w+");
-
     if (PyObject_Print(test_string, fp, 0) < 0){
         fclose(fp);
         Py_SET_REFCNT(test_string, 1);
@@ -90,20 +94,22 @@ pyobject_print_noref_object(PyObject *self, PyObject *args)
 }
 
 static PyObject *
-pyobject_print_os_error(PyObject *self, PyObject *args)
+pyobject_print_os_error(PyObject *self, PyObject *filename)
 {
     PyObject *test_string;
-    PyObject *filename;
     FILE *fp;
 
     test_string = PyUnicode_FromString("Spam spam spam");
-
-    if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
+    if (test_string == NULL) {
         return NULL;
     }
 
     // open file in read mode to induce OSError
     fp = Py_fopen(filename, "r");
+    if (fp == NULL) {
+        Py_DECREF(test_string);
+        return NULL;
+    }
 
     if (PyObject_Print(test_string, fp, 0) < 0) {
         fclose(fp);
@@ -496,9 +502,9 @@ is_uniquely_referenced(PyObject *self, PyObject *op)
 
 static PyMethodDef test_methods[] = {
     {"call_pyobject_print", call_pyobject_print, METH_VARARGS},
-    {"pyobject_print_null", pyobject_print_null, METH_VARARGS},
-    {"pyobject_print_noref_object", pyobject_print_noref_object, METH_VARARGS},
-    {"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS},
+    {"pyobject_print_null", pyobject_print_null, METH_O},
+    {"pyobject_print_noref_object", pyobject_print_noref_object, METH_O},
+    {"pyobject_print_os_error", pyobject_print_os_error, METH_O},
     {"pyobject_clear_weakrefs_no_callbacks", 
pyobject_clear_weakrefs_no_callbacks, METH_O},
     {"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, 
METH_O},
     {"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O},
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 5784482d38904d..d50838e876f24a 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1432,7 +1432,6 @@ pymarshal_write_long_to_file(PyObject* self, PyObject 
*args)
 
     fp = Py_fopen(filename, "wb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 
@@ -1457,7 +1456,6 @@ pymarshal_write_object_to_file(PyObject* self, PyObject 
*args)
 
     fp = Py_fopen(filename, "wb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 
@@ -1481,7 +1479,6 @@ pymarshal_read_short_from_file(PyObject* self, PyObject 
*args)
 
     fp = Py_fopen(filename, "rb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 
@@ -1506,7 +1503,6 @@ pymarshal_read_long_from_file(PyObject* self, PyObject 
*args)
 
     fp = Py_fopen(filename, "rb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 
@@ -1528,7 +1524,6 @@ pymarshal_read_last_object_from_file(PyObject* self, 
PyObject *args)
 
     FILE *fp = Py_fopen(filename, "rb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 
@@ -1551,7 +1546,6 @@ pymarshal_read_object_from_file(PyObject* self, PyObject 
*args)
 
     FILE *fp = Py_fopen(filename, "rb");
     if (fp == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to