summaryrefslogtreecommitdiff
path: root/Python/marshal.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/marshal.c')
-rw-r--r--Python/marshal.c205
1 files changed, 132 insertions, 73 deletions
diff --git a/Python/marshal.c b/Python/marshal.c
index 6f0ee5e83e..d26a997534 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -12,8 +12,7 @@
#include "longintrepr.h"
#include "code.h"
#include "marshal.h"
-
-#define ABS(x) ((x) < 0 ? -(x) : (x))
+#include "../Modules/hashtable.h"
/* High water mark to determine when the marshalled object is dangerously deep
* and risks coring the interpreter. When the object stack gets this deep,
@@ -21,7 +20,7 @@
* On Windows debug builds, reduce this value.
*/
#if defined(MS_WINDOWS) && defined(_DEBUG)
-#define MAX_MARSHAL_STACK_DEPTH 1500
+#define MAX_MARSHAL_STACK_DEPTH 1000
#else
#define MAX_MARSHAL_STACK_DEPTH 2000
#endif
@@ -66,54 +65,83 @@ typedef struct {
FILE *fp;
int error; /* see WFERR_* values */
int depth;
- /* If fp == NULL, the following are valid: */
- PyObject *readable; /* Stream-like object being read from */
PyObject *str;
- PyObject *current_filename;
char *ptr;
char *end;
char *buf;
- Py_ssize_t buf_size;
- PyObject *refs; /* dict on marshal, list on unmarshal */
+ _Py_hashtable_t *hashtable;
int version;
} WFILE;
-#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \
- else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \
- else w_more((c), p)
+#define w_byte(c, p) do { \
+ if ((p)->ptr != (p)->end || w_reserve((p), 1)) \
+ *(p)->ptr++ = (c); \
+ } while(0)
static void
-w_more(char c, WFILE *p)
+w_flush(WFILE *p)
+{
+ assert(p->fp != NULL);
+ fwrite(p->buf, 1, p->ptr - p->buf, p->fp);
+ p->ptr = p->buf;
+}
+
+static int
+w_reserve(WFILE *p, Py_ssize_t needed)
{
- Py_ssize_t size, newsize;
- if (p->str == NULL)
- return; /* An error already occurred */
+ Py_ssize_t pos, size, delta;
+ if (p->ptr == NULL)
+ return 0; /* An error already occurred */
+ if (p->fp != NULL) {
+ w_flush(p);
+ return needed <= p->end - p->ptr;
+ }
+ assert(p->str != NULL);
+ pos = p->ptr - p->buf;
size = PyBytes_Size(p->str);
- newsize = size + size + 1024;
- if (newsize > 32*1024*1024) {
- newsize = size + (size >> 3); /* 12.5% overallocation */
+ if (size > 16*1024*1024)
+ delta = (size >> 3); /* 12.5% overallocation */
+ else
+ delta = size + 1024;
+ delta = Py_MAX(delta, needed);
+ if (delta > PY_SSIZE_T_MAX - size) {
+ p->error = WFERR_NOMEMORY;
+ return 0;
}
- if (_PyBytes_Resize(&p->str, newsize) != 0) {
- p->ptr = p->end = NULL;
+ size += delta;
+ if (_PyBytes_Resize(&p->str, size) != 0) {
+ p->ptr = p->buf = p->end = NULL;
+ return 0;
}
else {
- p->ptr = PyBytes_AS_STRING((PyBytesObject *)p->str) + size;
- p->end =
- PyBytes_AS_STRING((PyBytesObject *)p->str) + newsize;
- *p->ptr++ = c;
+ p->buf = PyBytes_AS_STRING(p->str);
+ p->ptr = p->buf + pos;
+ p->end = p->buf + size;
+ return 1;
}
}
static void
w_string(const char *s, Py_ssize_t n, WFILE *p)
{
+ Py_ssize_t m;
+ if (!n || p->ptr == NULL)
+ return;
+ m = p->end - p->ptr;
if (p->fp != NULL) {
- fwrite(s, 1, n, p->fp);
+ if (n <= m) {
+ Py_MEMCPY(p->ptr, s, n);
+ p->ptr += n;
+ }
+ else {
+ w_flush(p);
+ fwrite(s, 1, n, p->fp);
+ }
}
else {
- while (--n >= 0) {
- w_byte(*s, p);
- s++;
+ if (n <= m || w_reserve(p, n - m)) {
+ Py_MEMCPY(p->ptr, s, n);
+ p->ptr += n;
}
}
}
@@ -192,7 +220,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
}
/* set l to number of base PyLong_MARSHAL_BASE digits */
- n = ABS(Py_SIZE(ob));
+ n = Py_ABS(Py_SIZE(ob));
l = (n-1) * PyLong_MARSHAL_RATIO;
d = ob->ob_digit[n-1];
assert(d != 0); /* a PyLong is always normalized */
@@ -225,46 +253,38 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
static int
w_ref(PyObject *v, char *flag, WFILE *p)
{
- PyObject *id;
- PyObject *idx;
+ _Py_hashtable_entry_t *entry;
+ int w;
- if (p->version < 3 || p->refs == NULL)
+ if (p->version < 3 || p->hashtable == NULL)
return 0; /* not writing object references */
/* if it has only one reference, it definitely isn't shared */
if (Py_REFCNT(v) == 1)
return 0;
- id = PyLong_FromVoidPtr((void*)v);
- if (id == NULL)
- goto err;
- idx = PyDict_GetItem(p->refs, id);
- if (idx != NULL) {
+ entry = _Py_hashtable_get_entry(p->hashtable, v);
+ if (entry != NULL) {
/* write the reference index to the stream */
- long w = PyLong_AsLong(idx);
- Py_DECREF(id);
- if (w == -1 && PyErr_Occurred()) {
- goto err;
- }
+ _Py_HASHTABLE_ENTRY_READ_DATA(p->hashtable, &w, sizeof(w), entry);
/* we don't store "long" indices in the dict */
assert(0 <= w && w <= 0x7fffffff);
w_byte(TYPE_REF, p);
w_long(w, p);
return 1;
} else {
- int ok;
- Py_ssize_t s = PyDict_Size(p->refs);
+ size_t s = p->hashtable->entries;
/* we don't support long indices */
if (s >= 0x7fffffff) {
PyErr_SetString(PyExc_ValueError, "too many objects");
goto err;
}
- idx = PyLong_FromSsize_t(s);
- ok = idx && PyDict_SetItem(p->refs, id, idx) == 0;
- Py_DECREF(id);
- Py_XDECREF(idx);
- if (!ok)
+ w = (int)s;
+ Py_INCREF(v);
+ if (_Py_HASHTABLE_SET(p->hashtable, v, w) < 0) {
+ Py_DECREF(v);
goto err;
+ }
*flag |= FLAG_REF;
return 0;
}
@@ -547,37 +567,81 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
}
}
+static int
+w_init_refs(WFILE *wf, int version)
+{
+ if (version >= 3) {
+ wf->hashtable = _Py_hashtable_new(sizeof(int), _Py_hashtable_hash_ptr,
+ _Py_hashtable_compare_direct);
+ if (wf->hashtable == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+w_decref_entry(_Py_hashtable_entry_t *entry, void *Py_UNUSED(data))
+{
+ Py_XDECREF(entry->key);
+ return 0;
+}
+
+static void
+w_clear_refs(WFILE *wf)
+{
+ if (wf->hashtable != NULL) {
+ _Py_hashtable_foreach(wf->hashtable, w_decref_entry, NULL);
+ _Py_hashtable_destroy(wf->hashtable);
+ }
+}
+
/* version currently has no effect for writing ints. */
void
PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
{
+ char buf[4];
WFILE wf;
+ memset(&wf, 0, sizeof(wf));
wf.fp = fp;
+ wf.ptr = wf.buf = buf;
+ wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK;
- wf.depth = 0;
- wf.refs = NULL;
wf.version = version;
w_long(x, &wf);
+ w_flush(&wf);
}
void
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
{
+ char buf[BUFSIZ];
WFILE wf;
+ memset(&wf, 0, sizeof(wf));
wf.fp = fp;
+ wf.ptr = wf.buf = buf;
+ wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK;
- wf.depth = 0;
- if (version >= 3) {
- if ((wf.refs = PyDict_New()) == NULL)
- return; /* caller mush check PyErr_Occurred() */
- } else
- wf.refs = NULL;
wf.version = version;
+ if (w_init_refs(&wf, version))
+ return; /* caller mush check PyErr_Occurred() */
w_object(x, &wf);
- Py_XDECREF(wf.refs);
+ w_clear_refs(&wf);
+ w_flush(&wf);
}
-typedef WFILE RFILE; /* Same struct with different invariants */
+typedef struct {
+ FILE *fp;
+ int depth;
+ PyObject *readable; /* Stream-like object being read from */
+ PyObject *current_filename;
+ char *ptr;
+ char *end;
+ char *buf;
+ Py_ssize_t buf_size;
+ PyObject *refs; /* a list */
+} RFILE;
static char *
r_string(Py_ssize_t n, RFILE *p)
@@ -727,8 +791,8 @@ r_PyLong(RFILE *p)
return NULL;
}
- size = 1 + (ABS(n) - 1) / PyLong_MARSHAL_RATIO;
- shorts_in_top_digit = 1 + (ABS(n) - 1) % PyLong_MARSHAL_RATIO;
+ size = 1 + (Py_ABS(n) - 1) / PyLong_MARSHAL_RATIO;
+ shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % PyLong_MARSHAL_RATIO;
ob = _PyLong_New(size);
if (ob == NULL)
return NULL;
@@ -1511,25 +1575,20 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
{
WFILE wf;
- wf.fp = NULL;
- wf.readable = NULL;
+ memset(&wf, 0, sizeof(wf));
wf.str = PyBytes_FromStringAndSize((char *)NULL, 50);
if (wf.str == NULL)
return NULL;
- wf.ptr = PyBytes_AS_STRING((PyBytesObject *)wf.str);
+ wf.ptr = wf.buf = PyBytes_AS_STRING((PyBytesObject *)wf.str);
wf.end = wf.ptr + PyBytes_Size(wf.str);
wf.error = WFERR_OK;
- wf.depth = 0;
wf.version = version;
- if (version >= 3) {
- if ((wf.refs = PyDict_New()) == NULL) {
- Py_DECREF(wf.str);
- return NULL;
- }
- } else
- wf.refs = NULL;
+ if (w_init_refs(&wf, version)) {
+ Py_DECREF(wf.str);
+ return NULL;
+ }
w_object(x, &wf);
- Py_XDECREF(wf.refs);
+ w_clear_refs(&wf);
if (wf.str != NULL) {
char *base = PyBytes_AS_STRING((PyBytesObject *)wf.str);
if (wf.ptr - base > PY_SSIZE_T_MAX) {