Skip to content

Commit 2e05771

Browse files
Clean up the marshal code.
1 parent 37eb1f8 commit 2e05771

File tree

1 file changed

+123
-81
lines changed

1 file changed

+123
-81
lines changed

Python/marshal.c

Lines changed: 123 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,105 @@ typedef struct {
8686
char *ptr;
8787
const char *end;
8888
char *buf;
89-
_Py_hashtable_t *hashtable;
89+
struct {
90+
_Py_hashtable_t *hashtable;
91+
} refs;
9092
int version;
9193
} WFILE;
9294

93-
#define w_byte(c, p) do { \
94-
if ((p)->ptr != (p)->end || w_reserve((p), 1)) \
95-
*(p)->ptr++ = (c); \
96-
} while(0)
95+
static void
96+
w_decref_entry(void *key)
97+
{
98+
PyObject *entry_key = (PyObject *)key;
99+
Py_XDECREF(entry_key);
100+
}
101+
102+
static int
103+
w_init_refs(WFILE *wf)
104+
{
105+
if (wf->version >= 3) {
106+
wf->refs.hashtable = _Py_hashtable_new_full(_Py_hashtable_hash_ptr,
107+
_Py_hashtable_compare_direct,
108+
w_decref_entry, NULL, NULL);
109+
if (wf->refs.hashtable == NULL) {
110+
PyErr_NoMemory();
111+
return -1;
112+
}
113+
}
114+
return 0;
115+
}
116+
117+
static void
118+
w_clear_refs(WFILE *wf)
119+
{
120+
if (wf->refs.hashtable != NULL) {
121+
_Py_hashtable_destroy(wf->refs.hashtable);
122+
}
123+
}
124+
125+
static int
126+
w_init(WFILE *wf, FILE *fp, char *buf, int version)
127+
{
128+
memset(wf, 0, sizeof(*wf));
129+
wf->fp = fp;
130+
if (fp == NULL) {
131+
assert(buf == NULL);
132+
wf->str = PyBytes_FromStringAndSize((char *)NULL, 50);
133+
if (wf->str == NULL) {
134+
return -1;
135+
}
136+
wf->ptr = wf->buf = PyBytes_AS_STRING(wf->str);
137+
wf->end = wf->ptr + PyBytes_GET_SIZE(wf->str);
138+
}
139+
else {
140+
assert(buf != NULL);
141+
wf->ptr = wf->buf = buf;
142+
wf->end = wf->ptr + sizeof(buf);
143+
}
144+
wf->error = WFERR_OK;
145+
wf->version = version;
146+
return 0;
147+
}
148+
149+
static void
150+
w_clear(WFILE *wf)
151+
{
152+
Py_XDECREF(wf->str);
153+
w_clear_refs(wf);
154+
}
155+
156+
static int
157+
w_handle_err(WFILE *wf)
158+
{
159+
if (wf->error == WFERR_OK) {
160+
return 0;
161+
}
162+
if (wf->error == WFERR_NOMEMORY) {
163+
PyErr_NoMemory();
164+
}
165+
else {
166+
PyErr_SetString(PyExc_ValueError,
167+
(wf->error == WFERR_UNMARSHALLABLE) ? "unmarshallable object"
168+
: "object too deeply nested to marshal");
169+
}
170+
return 1;
171+
}
172+
173+
static PyObject *
174+
w_finish_string(WFILE *wf)
175+
{
176+
if (wf->str == NULL) {
177+
Py_RETURN_NONE;
178+
}
179+
const char *base = PyBytes_AS_STRING(wf->str);
180+
if (_PyBytes_Resize(&wf->str, (Py_ssize_t)(wf->ptr - base)) < 0) {
181+
return NULL;
182+
}
183+
PyObject *finished = wf->str;
184+
wf->str = NULL;
185+
w_clear(wf);
186+
return finished;
187+
}
97188

98189
static void
99190
w_flush(WFILE *p)
@@ -138,6 +229,11 @@ w_reserve(WFILE *p, Py_ssize_t needed)
138229
}
139230
}
140231

232+
#define w_byte(c, p) do { \
233+
if ((p)->ptr != (p)->end || w_reserve((p), 1)) \
234+
*(p)->ptr++ = (c); \
235+
} while(0)
236+
141237
static void
142238
w_string(const void *s, Py_ssize_t n, WFILE *p)
143239
{
@@ -296,14 +392,14 @@ w_ref(PyObject *v, char *flag, WFILE *p)
296392
_Py_hashtable_entry_t *entry;
297393
int w;
298394

299-
if (p->version < 3 || p->hashtable == NULL)
395+
if (p->version < 3 || p->refs.hashtable == NULL)
300396
return 0; /* not writing object references */
301397

302398
/* if it has only one reference, it definitely isn't shared */
303399
if (Py_REFCNT(v) == 1)
304400
return 0;
305401

306-
entry = _Py_hashtable_get_entry(p->hashtable, v);
402+
entry = _Py_hashtable_get_entry(p->refs.hashtable, v);
307403
if (entry != NULL) {
308404
/* write the reference index to the stream */
309405
w = (int)(uintptr_t)entry->value;
@@ -313,15 +409,15 @@ w_ref(PyObject *v, char *flag, WFILE *p)
313409
w_long(w, p);
314410
return 1;
315411
} else {
316-
size_t s = p->hashtable->nentries;
412+
size_t s = p->refs.hashtable->nentries;
317413
/* we don't support long indices */
318414
if (s >= 0x7fffffff) {
319415
PyErr_SetString(PyExc_ValueError, "too many objects");
320416
goto err;
321417
}
322418
w = (int)s;
323419
Py_INCREF(v);
324-
if (_Py_hashtable_set(p->hashtable, v, (void *)(uintptr_t)w) < 0) {
420+
if (_Py_hashtable_set(p->refs.hashtable, v, (void *)(uintptr_t)w) < 0) {
325421
Py_DECREF(v);
326422
goto err;
327423
}
@@ -583,72 +679,35 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
583679
}
584680
}
585681

586-
static void
587-
w_decref_entry(void *key)
588-
{
589-
PyObject *entry_key = (PyObject *)key;
590-
Py_XDECREF(entry_key);
591-
}
592-
593-
static int
594-
w_init_refs(WFILE *wf, int version)
595-
{
596-
if (version >= 3) {
597-
wf->hashtable = _Py_hashtable_new_full(_Py_hashtable_hash_ptr,
598-
_Py_hashtable_compare_direct,
599-
w_decref_entry, NULL, NULL);
600-
if (wf->hashtable == NULL) {
601-
PyErr_NoMemory();
602-
return -1;
603-
}
604-
}
605-
return 0;
606-
}
607-
608-
static void
609-
w_clear_refs(WFILE *wf)
610-
{
611-
if (wf->hashtable != NULL) {
612-
_Py_hashtable_destroy(wf->hashtable);
613-
}
614-
}
615-
616682
/* version currently has no effect for writing ints. */
617683
void
618684
PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
619685
{
620686
char buf[4];
621687
WFILE wf;
622-
memset(&wf, 0, sizeof(wf));
623-
wf.fp = fp;
624-
wf.ptr = wf.buf = buf;
625-
wf.end = wf.ptr + sizeof(buf);
626-
wf.error = WFERR_OK;
627-
wf.version = version;
688+
(void)w_init(&wf, fp, buf, version);
628689
w_long(x, &wf);
629690
w_flush(&wf);
691+
w_clear(&wf);
630692
}
631693

632694
void
633695
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
634696
{
635-
char buf[BUFSIZ];
636-
WFILE wf;
637697
if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) {
638698
return; /* caller must check PyErr_Occurred() */
639699
}
640-
memset(&wf, 0, sizeof(wf));
641-
wf.fp = fp;
642-
wf.ptr = wf.buf = buf;
643-
wf.end = wf.ptr + sizeof(buf);
644-
wf.error = WFERR_OK;
645-
wf.version = version;
646-
if (w_init_refs(&wf, version)) {
700+
701+
char buf[BUFSIZ];
702+
WFILE wf;
703+
(void)w_init(&wf, fp, buf, version);
704+
if (w_init_refs(&wf) != 0) {
705+
w_clear(&wf);
647706
return; /* caller must check PyErr_Occurred() */
648707
}
649708
w_object(x, &wf);
650-
w_clear_refs(&wf);
651709
w_flush(&wf);
710+
w_clear(&wf);
652711
}
653712

654713
typedef struct {
@@ -1648,41 +1707,24 @@ PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len)
16481707
PyObject *
16491708
PyMarshal_WriteObjectToString(PyObject *x, int version)
16501709
{
1651-
WFILE wf;
1652-
16531710
if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) {
16541711
return NULL;
16551712
}
1656-
memset(&wf, 0, sizeof(wf));
1657-
wf.str = PyBytes_FromStringAndSize((char *)NULL, 50);
1658-
if (wf.str == NULL)
1713+
1714+
WFILE wf;
1715+
if (w_init(&wf, NULL, NULL, version) != 0) {
16591716
return NULL;
1660-
wf.ptr = wf.buf = PyBytes_AS_STRING(wf.str);
1661-
wf.end = wf.ptr + PyBytes_GET_SIZE(wf.str);
1662-
wf.error = WFERR_OK;
1663-
wf.version = version;
1664-
if (w_init_refs(&wf, version)) {
1665-
Py_DECREF(wf.str);
1717+
}
1718+
if (w_init_refs(&wf) != 0) {
1719+
w_clear(&wf);
16661720
return NULL;
16671721
}
16681722
w_object(x, &wf);
1669-
w_clear_refs(&wf);
1670-
if (wf.str != NULL) {
1671-
const char *base = PyBytes_AS_STRING(wf.str);
1672-
if (_PyBytes_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base)) < 0)
1673-
return NULL;
1674-
}
1675-
if (wf.error != WFERR_OK) {
1676-
Py_XDECREF(wf.str);
1677-
if (wf.error == WFERR_NOMEMORY)
1678-
PyErr_NoMemory();
1679-
else
1680-
PyErr_SetString(PyExc_ValueError,
1681-
(wf.error==WFERR_UNMARSHALLABLE)?"unmarshallable object"
1682-
:"object too deeply nested to marshal");
1723+
if (w_handle_err(&wf)) {
1724+
w_clear(&wf);
16831725
return NULL;
16841726
}
1685-
return wf.str;
1727+
return w_finish_string(&wf);
16861728
}
16871729

16881730
/* And an interface for Python programs... */

0 commit comments

Comments
 (0)