Skip to content

Commit 9b05276

Browse files
Address review comments
Preserve errno across PyErr_CheckSignals() when reporting a read error, rename w_set_error() to w_set_exception(), handle a PyNumber_AsSsize_t() failure explicitly, and check the error message in the test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent ed7d607 commit 9b05276

2 files changed

Lines changed: 15 additions & 6 deletions

File tree

Lib/test/test_marshal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ def test_write_to_file_error(self):
818818

819819
def test_write_unmarshallable_to_file(self):
820820
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
821-
with self.assertRaises(ValueError):
821+
with self.assertRaisesRegex(ValueError, 'unmarshallable object'):
822822
_testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN,
823823
marshal.version)
824824

Python/marshal.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -806,9 +806,9 @@ w_clear_refs(WFILE *wf)
806806
}
807807
}
808808

809-
/* Set the error indicator according to the recorded error. */
809+
/* Set the exception indicator according to the recorded error. */
810810
static void
811-
w_set_error(WFILE *p)
811+
w_set_exception(WFILE *p)
812812
{
813813
assert(p->error != WFERR_OK);
814814
switch (p->error) {
@@ -850,7 +850,7 @@ PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
850850
w_long(x, &wf);
851851
w_flush(&wf);
852852
if (wf.error != WFERR_OK) {
853-
w_set_error(&wf);
853+
w_set_exception(&wf);
854854
}
855855
}
856856

@@ -876,7 +876,7 @@ PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
876876
w_clear_refs(&wf);
877877
w_flush(&wf);
878878
if (wf.error != WFERR_OK) {
879-
w_set_error(&wf);
879+
w_set_exception(&wf);
880880
}
881881
}
882882

@@ -932,7 +932,9 @@ r_string(Py_ssize_t n, RFILE *p)
932932
read = fread(p->buf, 1, n, p->fp);
933933
if (read != n) {
934934
assert(read < n);
935+
int saved_errno = errno;
935936
if (!PyErr_CheckSignals() && ferror(p->fp)) {
937+
errno = saved_errno;
936938
PyErr_SetFromErrno(PyExc_OSError);
937939
}
938940
}
@@ -953,6 +955,9 @@ r_string(Py_ssize_t n, RFILE *p)
953955
}
954956
read = PyNumber_AsSsize_t(res, PyExc_ValueError);
955957
Py_DECREF(res);
958+
if (read == -1 && PyErr_Occurred()) {
959+
return NULL;
960+
}
956961
if (read > n) {
957962
PyErr_Format(PyExc_ValueError,
958963
"read() returned too much data: "
@@ -985,10 +990,12 @@ r_byte(RFILE *p)
985990
if (c != EOF) {
986991
return c;
987992
}
993+
int saved_errno = errno;
988994
if (PyErr_CheckSignals()) {
989995
return EOF;
990996
}
991997
if (ferror(p->fp)) {
998+
errno = saved_errno;
992999
PyErr_SetFromErrno(PyExc_OSError);
9931000
return EOF;
9941001
}
@@ -1922,8 +1929,10 @@ PyMarshal_ReadLastObjectFromFile(FILE *fp)
19221929
if (pBuf != NULL) {
19231930
PyObject *v = NULL;
19241931
size_t n = fread(pBuf, 1, (size_t)filesize, fp);
1932+
int saved_errno = errno;
19251933
if (!PyErr_CheckSignals()) {
19261934
if (ferror(fp)) {
1935+
errno = saved_errno;
19271936
PyErr_SetFromErrno(PyExc_OSError);
19281937
}
19291938
else {
@@ -2016,7 +2025,7 @@ _PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code)
20162025
}
20172026
if (wf.error != WFERR_OK) {
20182027
Py_XDECREF(wf.str);
2019-
w_set_error(&wf);
2028+
w_set_exception(&wf);
20202029
return NULL;
20212030
}
20222031
return wf.str;

0 commit comments

Comments
 (0)