Skip to content

Commit c392157

Browse files
miss-islingtonserhiy-storchakaclaude
authored
[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 a175da7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 563449b commit c392157

2 files changed

Lines changed: 23 additions & 23 deletions

File tree

Modules/_testcapi/object.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ call_pyobject_print(PyObject *self, PyObject * args)
1616
}
1717

1818
fp = Py_fopen(filename, "w+");
19+
if (fp == NULL) {
20+
return NULL;
21+
}
1922

2023
if (Py_IsTrue(print_raw)) {
2124
flags = Py_PRINT_RAW;
@@ -32,17 +35,15 @@ call_pyobject_print(PyObject *self, PyObject * args)
3235
}
3336

3437
static PyObject *
35-
pyobject_print_null(PyObject *self, PyObject *args)
38+
pyobject_print_null(PyObject *self, PyObject *filename)
3639
{
37-
PyObject *filename;
3840
FILE *fp;
3941

40-
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
42+
fp = Py_fopen(filename, "w+");
43+
if (fp == NULL) {
4144
return NULL;
4245
}
4346

44-
fp = Py_fopen(filename, "w+");
45-
4647
if (PyObject_Print(NULL, fp, 0) < 0) {
4748
fclose(fp);
4849
return NULL;
@@ -54,26 +55,29 @@ pyobject_print_null(PyObject *self, PyObject *args)
5455
}
5556

5657
static PyObject *
57-
pyobject_print_noref_object(PyObject *self, PyObject *args)
58+
pyobject_print_noref_object(PyObject *self, PyObject *filename)
5859
{
5960
PyObject *test_string;
60-
PyObject *filename;
6161
FILE *fp;
6262
char correct_string[100];
6363

6464
test_string = PyUnicode_FromString("Spam spam spam");
65+
if (test_string == NULL) {
66+
return NULL;
67+
}
6568

6669
Py_SET_REFCNT(test_string, 0);
6770

6871
PyOS_snprintf(correct_string, 100, "<refcnt %zd at %p>",
6972
Py_REFCNT(test_string), (void *)test_string);
7073

71-
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
74+
fp = Py_fopen(filename, "w+");
75+
if (fp == NULL) {
76+
Py_SET_REFCNT(test_string, 1);
77+
Py_DECREF(test_string);
7278
return NULL;
7379
}
7480

75-
fp = Py_fopen(filename, "w+");
76-
7781
if (PyObject_Print(test_string, fp, 0) < 0){
7882
fclose(fp);
7983
Py_SET_REFCNT(test_string, 1);
@@ -90,20 +94,22 @@ pyobject_print_noref_object(PyObject *self, PyObject *args)
9094
}
9195

9296
static PyObject *
93-
pyobject_print_os_error(PyObject *self, PyObject *args)
97+
pyobject_print_os_error(PyObject *self, PyObject *filename)
9498
{
9599
PyObject *test_string;
96-
PyObject *filename;
97100
FILE *fp;
98101

99102
test_string = PyUnicode_FromString("Spam spam spam");
100-
101-
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
103+
if (test_string == NULL) {
102104
return NULL;
103105
}
104106

105107
// open file in read mode to induce OSError
106108
fp = Py_fopen(filename, "r");
109+
if (fp == NULL) {
110+
Py_DECREF(test_string);
111+
return NULL;
112+
}
107113

108114
if (PyObject_Print(test_string, fp, 0) < 0) {
109115
fclose(fp);
@@ -496,9 +502,9 @@ is_uniquely_referenced(PyObject *self, PyObject *op)
496502

497503
static PyMethodDef test_methods[] = {
498504
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
499-
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
500-
{"pyobject_print_noref_object", pyobject_print_noref_object, METH_VARARGS},
501-
{"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS},
505+
{"pyobject_print_null", pyobject_print_null, METH_O},
506+
{"pyobject_print_noref_object", pyobject_print_noref_object, METH_O},
507+
{"pyobject_print_os_error", pyobject_print_os_error, METH_O},
502508
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
503509
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
504510
{"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O},

Modules/_testcapimodule.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,6 @@ pymarshal_write_long_to_file(PyObject* self, PyObject *args)
14321432

14331433
fp = Py_fopen(filename, "wb");
14341434
if (fp == NULL) {
1435-
PyErr_SetFromErrno(PyExc_OSError);
14361435
return NULL;
14371436
}
14381437

@@ -1457,7 +1456,6 @@ pymarshal_write_object_to_file(PyObject* self, PyObject *args)
14571456

14581457
fp = Py_fopen(filename, "wb");
14591458
if (fp == NULL) {
1460-
PyErr_SetFromErrno(PyExc_OSError);
14611459
return NULL;
14621460
}
14631461

@@ -1481,7 +1479,6 @@ pymarshal_read_short_from_file(PyObject* self, PyObject *args)
14811479

14821480
fp = Py_fopen(filename, "rb");
14831481
if (fp == NULL) {
1484-
PyErr_SetFromErrno(PyExc_OSError);
14851482
return NULL;
14861483
}
14871484

@@ -1506,7 +1503,6 @@ pymarshal_read_long_from_file(PyObject* self, PyObject *args)
15061503

15071504
fp = Py_fopen(filename, "rb");
15081505
if (fp == NULL) {
1509-
PyErr_SetFromErrno(PyExc_OSError);
15101506
return NULL;
15111507
}
15121508

@@ -1528,7 +1524,6 @@ pymarshal_read_last_object_from_file(PyObject* self, PyObject *args)
15281524

15291525
FILE *fp = Py_fopen(filename, "rb");
15301526
if (fp == NULL) {
1531-
PyErr_SetFromErrno(PyExc_OSError);
15321527
return NULL;
15331528
}
15341529

@@ -1551,7 +1546,6 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args)
15511546

15521547
FILE *fp = Py_fopen(filename, "rb");
15531548
if (fp == NULL) {
1554-
PyErr_SetFromErrno(PyExc_OSError);
15551549
return NULL;
15561550
}
15571551

0 commit comments

Comments
 (0)