Skip to content

Commit 57f890c

Browse files
committed
pythongh-105184: add return value indicating success/failure for PyMarshal_WriteLongToFile and PyMarshal_ReadLastObjectFromFile
1 parent 4bfa01b commit 57f890c

File tree

4 files changed

+32
-20
lines changed

4 files changed

+32
-20
lines changed

Doc/c-api/marshal.rst

+10-6
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,26 @@ unmarshalling. Version 2 uses a binary format for floating point numbers.
1919
``Py_MARSHAL_VERSION`` indicates the current file format (currently 2).
2020

2121

22-
.. c:function:: void PyMarshal_WriteLongToFile(long value, FILE *file, int version)
22+
.. c:function:: int PyMarshal_WriteLongToFile(long value, FILE *file, int version)
2323
2424
Marshal a :c:expr:`long` integer, *value*, to *file*. This will only write
2525
the least-significant 32 bits of *value*; regardless of the size of the
2626
native :c:expr:`long` type. *version* indicates the file format.
2727
28-
This function can fail, in which case it sets the error indicator.
29-
Use :c:func:`PyErr_Occurred` to check for that.
28+
Return 0 on success. Return -1 and set an exception on error.
3029
31-
.. c:function:: void PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version)
30+
.. versionchanged:: 3.13
31+
Added return value.
32+
33+
.. c:function:: int PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version)
3234
3335
Marshal a Python object, *value*, to *file*.
3436
*version* indicates the file format.
3537
36-
This function can fail, in which case it sets the error indicator.
37-
Use :c:func:`PyErr_Occurred` to check for that.
38+
Return 0 on success. Return -1 and set an exception on error.
39+
40+
.. versionchanged:: 3.13
41+
Added return value.
3842
3943
.. c:function:: PyObject* PyMarshal_WriteObjectToString(PyObject *value, int version)
4044

Include/marshal.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *);
2020
PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *);
2121
PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *);
2222

23-
PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int);
24-
PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);
23+
PyAPI_FUNC(int) PyMarshal_WriteLongToFile(long, FILE *, int);
24+
PyAPI_FUNC(int) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);
2525

2626
#ifdef __cplusplus
2727
}

Modules/_testcapimodule.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,8 @@ pymarshal_write_long_to_file(PyObject* self, PyObject *args)
18071807
return NULL;
18081808
}
18091809

1810-
PyMarshal_WriteLongToFile(value, fp, version);
1810+
int ret = PyMarshal_WriteLongToFile(value, fp, version);
1811+
assert(ret == 0);
18111812
assert(!PyErr_Occurred());
18121813

18131814
fclose(fp);
@@ -1832,7 +1833,8 @@ pymarshal_write_object_to_file(PyObject* self, PyObject *args)
18321833
return NULL;
18331834
}
18341835

1835-
PyMarshal_WriteObjectToFile(obj, fp, version);
1836+
int ret = PyMarshal_WriteObjectToFile(obj, fp, version);
1837+
assert(ret == 0);
18361838
assert(!PyErr_Occurred());
18371839

18381840
fclose(fp);

Python/marshal.c

+16-10
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,7 @@ w_clear_refs(WFILE *wf)
625625
}
626626

627627
/* version currently has no effect for writing ints. */
628-
/* Note that while the documentation states that this function
629-
* can error, currently it never does. Setting an exception in
630-
* this function should be regarded as an API-breaking change.
631-
*/
632-
void
628+
int
633629
PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
634630
{
635631
char buf[4];
@@ -642,28 +638,37 @@ PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
642638
wf.version = version;
643639
w_long(x, &wf);
644640
w_flush(&wf);
641+
642+
/* While the documentation states that this function can error,
643+
* currently it never does. Setting an exception in this function
644+
* should be regarded as an API-breaking change.
645+
*/
646+
assert(!PyErr_Occurred());
647+
648+
return 0;
645649
}
646650

647-
void
651+
int
648652
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
649653
{
650654
char buf[BUFSIZ];
651655
WFILE wf;
652656
if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) {
653-
return; /* caller must check PyErr_Occurred() */
657+
return -1;
654658
}
655659
memset(&wf, 0, sizeof(wf));
656660
wf.fp = fp;
657661
wf.ptr = wf.buf = buf;
658662
wf.end = wf.ptr + sizeof(buf);
659663
wf.error = WFERR_OK;
660664
wf.version = version;
661-
if (w_init_refs(&wf, version)) {
662-
return; /* caller must check PyErr_Occurred() */
665+
if (w_init_refs(&wf, version) < 0) {
666+
return -1;
663667
}
664668
w_object(x, &wf);
665669
w_clear_refs(&wf);
666670
w_flush(&wf);
671+
return 0;
667672
}
668673

669674
typedef struct {
@@ -1612,6 +1617,7 @@ PyMarshal_ReadObjectFromFile(FILE *fp)
16121617
Py_DECREF(rf.refs);
16131618
if (rf.buf != NULL)
16141619
PyMem_Free(rf.buf);
1620+
assert((result != NULL) == !PyErr_Occurred());
16151621
return result;
16161622
}
16171623

@@ -1652,7 +1658,7 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
16521658
wf.end = wf.ptr + PyBytes_GET_SIZE(wf.str);
16531659
wf.error = WFERR_OK;
16541660
wf.version = version;
1655-
if (w_init_refs(&wf, version)) {
1661+
if (w_init_refs(&wf, version) < 0) {
16561662
Py_DECREF(wf.str);
16571663
return NULL;
16581664
}

0 commit comments

Comments
 (0)