GitHub Viewer
/* Write Python objects to files and read them back.
This is primarily intended for writing and reading compiled Python code,
even though dicts, lists, sets and frozensets, not commonly seen in
code objects, are supported.
Version 3 of this protocol properly supports circular links
and sharing. */
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_code.h" // _PyCode_New()
#include "pycore_hashtable.h" // _Py_hashtable_t
#include "pycore_long.h" // _PyLong_DigitCount
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "marshal.h" // Py_MARSHAL_VERSION
/*[clinic input]
module marshal
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c982b7930dee17db]*/
#include "clinic/marshal.c.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,
* raise an exception instead of continuing.
* On Windows debug builds, reduce this value.
*
* BUG: https://bugs.python.org/issue33720
* On Windows PGO builds, the r_object function overallocates its stack and
* can cause a stack overflow. We reduce the maximum depth for all Windows
* releases to protect against this.
* #if defined(MS_WINDOWS) && defined(_DEBUG)
*/
#if defined(MS_WINDOWS)
#define MAX_MARSHAL_STACK_DEPTH 1000
#elif defined(__wasi__)
#define MAX_MARSHAL_STACK_DEPTH 1500
#else
#define MAX_MARSHAL_STACK_DEPTH 2000
#endif
#define TYPE_NULL '0'
#define TYPE_NONE 'N'
#define TYPE_FALSE 'F'
#define TYPE_TRUE 'T'
#define TYPE_STOPITER 'S'
#define TYPE_ELLIPSIS '.'
#define TYPE_INT 'i'
/* TYPE_INT64 is not generated anymore.
Supported for backward compatibility only. */
#define TYPE_INT64 'I'
#define TYPE_FLOAT 'f'
#define TYPE_BINARY_FLOAT 'g'
#define TYPE_COMPLEX 'x'
#define TYPE_BINARY_COMPLEX 'y'
#define TYPE_LONG 'l'
#define TYPE_STRING 's'
#define TYPE_INTERNED 't'
#define TYPE_REF 'r'
#define TYPE_TUPLE '('
#define TYPE_LIST '['
#define TYPE_DICT '{'
#define TYPE_CODE 'c'
#define TYPE_UNICODE 'u'
#define TYPE_UNKNOWN '?'
#define TYPE_SET ''
#define FLAG_REF '\x80' /* with a type, add obj to index */
#define TYPE_ASCII 'a'
#define TYPE_ASCII_INTERNED 'A'
#define TYPE_SMALL_TUPLE ')'
#define TYPE_SHORT_ASCII 'z'
#define TYPE_SHORT_ASCII_INTERNED 'Z'
#define WFERR_OK 0
#define WFERR_UNMARSHALLABLE 1
#define WFERR_NESTEDTOODEEP 2
#define WFERR_NOMEMORY 3
typedef struct {
FILE *fp;
int error; /* see WFERR_* values */
int depth;
PyObject *str;
char *ptr;
const char *end;
char *buf;
_Py_hashtable_t *hashtable;
int version;
} WFILE;
#define w_byte(c, p) do { \
if ((p)->ptr != (p)->end || w_reserve((p), 1)) \
*(p)->ptr++ = (c); \
} while(0)
static void
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 pos, size, delta;
if (p->ptr == NULL)
return 0; /* An error already occurred */
if (p->fp != NULL) {
w_flush(p);
return needed end - p->ptr;
}
assert(p->str != NULL);
pos = p->ptr - p->buf;
size = PyBytes_GET_SIZE(p->str);
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;
}
size += delta;
if (_PyBytes_Resize(&p->str, size) != 0) {
p->end = p->ptr = p->buf = NULL;
return 0;
}
else {
p->buf = PyBytes_AS_STRING(p->str);
p->ptr = p->buf + pos;
p->end = p->buf + size;
return 1;
}
}
static void
w_string(const void *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) {
if (n ptr, s, n);
p->ptr += n;
}
else {
w_flush(p);
fwrite(s, 1, n, p->fp);
}
}
else {
if (n ptr, s, n);
p->ptr += n;
}
}
}
static void
w_short(int x, WFILE *p)
{
w_byte((char)( x & 0xff), p);
w_byte((char)((x>> 8) & 0xff), p);
}
static void
w_long(long x, WFILE *p)
{
w_byte((char)( x & 0xff), p);
w_byte((char)((x>> 8) & 0xff), p);
w_byte((char)((x>>16) & 0xff), p);
w_byte((char)((x>>24) & 0xff), p);
}
#define SIZE32_MAX 0x7FFFFFFF
#if SIZEOF_SIZE_T > 4
# define W_SIZE(n, p) do { \
if ((n) > SIZE32_MAX) { \
(p)->depth--; \
(p)->error = WFERR_UNMARSHALLABLE; \
return; \
} \
w_long((long)(n), p); \
} while(0)
#else
# define W_SIZE w_long
#endif
static void
w_pstring(const void *s, Py_ssize_t n, WFILE *p)
{
W_SIZE(n, p);
w_string(s, n, p);
}
static void
w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
{
w_byte(Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char), p);
w_string(s, n, p);
}
/* We assume that Python ints are stored internally in base some power of
2**15; for the sake of portability we'll always read and write them in base
exactly 2**15. */
#define PyLong_MARSHAL_SHIFT 15
#define PyLong_MARSHAL_BASE ((short)1 long_value.ob_digit[n-1];
assert(d != 0); /* a PyLong is always normalized */
do {
d >>= PyLong_MARSHAL_SHIFT;
l++;
} while (d != 0);
if (l > SIZE32_MAX) {
p->depth--;
p->error = WFERR_UNMARSHALLABLE;
return;
}
w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p);
for (i=0; i < n-1; i++) {
d = ob->long_value.ob_digit[i];
for (j=0; j < PyLong_MARSHAL_RATIO; j++) {
w_short(d & PyLong_MARSHAL_MASK, p);
d >>= PyLong_MARSHAL_SHIFT;
}
assert (d == 0);
}
d = ob->long_value.ob_digit[n-1];
do {
w_short(d & PyLong_MARSHAL_MASK, p);
d >>= PyLong_MARSHAL_SHIFT;
} while (d != 0);
}
static void
w_float_bin(double v, WFILE *p)
{
char buf[8];
if (PyFloat_Pack8(v, buf, 1) < 0) {
p->error = WFERR_UNMARSHALLABLE;
return;
}
w_string(buf, 8, p);
}
static void
w_float_str(double v, WFILE *p)
{
char *buf = PyOS_double_to_string(v, 'g', 17, 0, NULL);
if (!buf) {
p->error = WFERR_NOMEMORY;
return;
}
w_short_pstring(buf, strlen(buf), p);
PyMem_Free(buf);
}
static int
w_ref(PyObject *v, char *flag, WFILE *p)
{
_Py_hashtable_entry_t *entry;
int w;
if (p->version < 3 || p->hashtable == NULL)
return 0; /* not writing object references */
/* If it has only one reference, it definitely isn't shared.
* But we use TYPE_REF always for interned string, to PYC file stable
* as possible.
*/
if (Py_REFCNT(v) == 1 &&
!(PyUnicode_CheckExact(v) && PyUnicode_CHECK_INTERNED(v))) {
return 0;
}
entry = _Py_hashtable_get_entry(p->hashtable, v);
if (entry != NULL) {
/* write the reference index to the stream */
w = (int)(uintptr_t)entry->value;
/* we don't store "long" indices in the dict */
assert(0 nentries;
/* we don't support long indices */
if (s >= 0x7fffffff) {
PyErr_SetString(PyExc_ValueError, "too many objects");
goto err;
}
w = (int)s;
if (_Py_hashtable_set(p->hashtable, Py_NewRef(v),
(void *)(uintptr_t)w) < 0) {
Py_DECREF(v);
goto err;
}
*flag |= FLAG_REF;
return 0;
}
err:
p->error = WFERR_UNMARSHALLABLE;
return 1;
}
static void
w_complex_object(PyObject *v, char flag, WFILE *p);
static void
w_object(PyObject *v, WFILE *p)
{
char flag = '\0';
p->depth++;
if (p->depth > MAX_MARSHAL_STACK_DEPTH) {
p->error = WFERR_NESTEDTOODEEP;
}
else if (v == NULL) {
w_byte(TYPE_NULL, p);
}
else if (v == Py_None) {
w_byte(TYPE_NONE, p);
}
else if (v == PyExc_StopIteration) {
w_byte(TYPE_STOPITER, p);
}
else if (v == Py_Ellipsis) {
w_byte(TYPE_ELLIPSIS, p);
}
else if (v == Py_False) {
w_byte(TYPE_FALSE, p);
}
else if (v == Py_True) {
w_byte(TYPE_TRUE, p);
}
else if (!w_ref(v, &flag, p))
w_complex_object(v, flag, p);
p->depth--;
}
static void
w_complex_object(PyObject *v, char flag, WFILE *p)
{
Py_ssize_t i, n;
if (PyLong_CheckExact(v)) {
int overflow;
long x = PyLong_AsLongAndOverflow(v, &overflow);
if (overflow) {
w_PyLong((PyLongObject *)v, flag, p);
}
else {
#if SIZEOF_LONG > 4
long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31);
if (y && y != -1) {
/* Too large for TYPE_INT */
w_PyLong((PyLongObject*)v, flag, p);
}
else
#endif
{
W_TYPE(TYPE_INT, p);
w_long(x, p);
}
}
}
else if (PyFloat_CheckExact(v)) {
if (p->version > 1) {
W_TYPE(TYPE_BINARY_FLOAT, p);
w_float_bin(PyFloat_AS_DOUBLE(v), p);
}
else {
W_TYPE(TYPE_FLOAT, p);
w_float_str(PyFloat_AS_DOUBLE(v), p);
}
}
else if (PyComplex_CheckExact(v)) {
if (p->version > 1) {
W_TYPE(TYPE_BINARY_COMPLEX, p);
w_float_bin(PyComplex_RealAsDouble(v), p);
w_float_bin(PyComplex_ImagAsDouble(v), p);
}
else {
W_TYPE(TYPE_COMPLEX, p);
w_float_str(PyComplex_RealAsDouble(v), p);
w_float_str(PyComplex_ImagAsDouble(v), p);
}
}
else if (PyBytes_CheckExact(v)) {
W_TYPE(TYPE_STRING, p);
w_pstring(PyBytes_AS_STRING(v), PyBytes_GET_SIZE(v), p);
}
else if (PyUnicode_CheckExact(v)) {
if (p->version >= 4 && PyUnicode_IS_ASCII(v)) {
int is_short = PyUnicode_GET_LENGTH(v) < 256;
if (is_short) {
if (PyUnicode_CHECK_INTERNED(v))
W_TYPE(TYPE_SHORT_ASCII_INTERNED, p);
else
W_TYPE(TYPE_SHORT_ASCII, p);
w_short_pstring(PyUnicode_1BYTE_DATA(v),
PyUnicode_GET_LENGTH(v), p);
}
else {
if (PyUnicode_CHECK_INTERNED(v))
W_TYPE(TYPE_ASCII_INTERNED, p);
else
W_TYPE(TYPE_ASCII, p);
w_pstring(PyUnicode_1BYTE_DATA(v),
PyUnicode_GET_LENGTH(v), p);
}
}
else {
PyObject *utf8;
utf8 = PyUnicode_AsEncodedString(v, "utf8", "surrogatepass");
if (utf8 == NULL) {
p->depth--;
p->error = WFERR_UNMARSHALLABLE;
return;
}
if (p->version >= 3 && PyUnicode_CHECK_INTERNED(v))
W_TYPE(TYPE_INTERNED, p);
else
W_TYPE(TYPE_UNICODE, p);
w_pstring(PyBytes_AS_STRING(utf8), PyBytes_GET_SIZE(utf8), p);
Py_DECREF(utf8);
}
}
else if (PyTuple_CheckExact(v)) {
n = PyTuple_GET_SIZE(v);
if (p->version >= 4 && n < 256) {
W_TYPE(TYPE_SMALL_TUPLE, p);
w_byte((unsigned char)n, p);
}
else {
W_TYPE(TYPE_TUPLE, p);
W_SIZE(n, p);
}
for (i = 0; i < n; i++) {
w_object(PyTuple_GET_ITEM(v, i), p);
}
}
else if (PyList_CheckExact(v)) {
W_TYPE(TYPE_LIST, p);
n = PyList_GET_SIZE(v);
W_SIZE(n, p);
for (i = 0; i < n; i++) {
w_object(PyList_GET_ITEM(v, i), p);
}
}
else if (PyDict_CheckExact(v)) {
Py_ssize_t pos;
PyObject *key, *value;
W_TYPE(TYPE_DICT, p);
/* This one is NULL object terminated! */
pos = 0;
while (PyDict_Next(v, &pos, &key, &value)) {
w_object(key, p);
w_object(value, p);
}
w_object((PyObject *)NULL, p);
}
else if (PyAnySet_CheckExact(v)) {
PyObject *value;
Py_ssize_t pos = 0;
Py_hash_t hash;
if (PyFrozenSet_CheckExact(v))
W_TYPE(TYPE_FROZENSET, p);
else
W_TYPE(TYPE_SET, p);
n = PySet_GET_SIZE(v);
W_SIZE(n, p);
// bpo-37596: To support reproducible builds, sets and frozensets need
// to have their elements serialized in a consistent order (even when
// they have been scrambled by hash randomization). To ensure this, we
// use an order equivalent to sorted(v, key=marshal.dumps):
PyObject *pairs = PyList_New(n);
if (pairs == NULL) {
p->error = WFERR_NOMEMORY;
return;
}
Py_ssize_t i = 0;
while (_PySet_NextEntry(v, &pos, &value, &hash)) {
PyObject *dump = PyMarshal_WriteObjectToString(value, p->version);
if (dump == NULL) {
p->error = WFERR_UNMARSHALLABLE;
Py_DECREF(pairs);
return;
}
PyObject *pair = PyTuple_Pack(2, dump, value);
Py_DECREF(dump);
if (pair == NULL) {
p->error = WFERR_NOMEMORY;
Py_DECREF(pairs);
return;
}
PyList_SET_ITEM(pairs, i++, pair);
}
assert(i == n);
if (PyList_Sort(pairs)) {
p->error = WFERR_NOMEMORY;
Py_DECREF(pairs);
return;
}
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *pair = PyList_GET_ITEM(pairs, i);
value = PyTuple_GET_ITEM(pair, 1);
w_object(value, p);
}
Py_DECREF(pairs);
}
else if (PyCode_Check(v)) {
PyCodeObject *co = (PyCodeObject *)v;
PyObject *co_code = _PyCode_GetCode(co);
if (co_code == NULL) {
p->error = WFERR_NOMEMORY;
return;
}
W_TYPE(TYPE_CODE, p);
w_long(co->co_argcount, p);
w_long(co->co_posonlyargcount, p);
w_long(co->co_kwonlyargcount, p);
w_long(co->co_stacksize, p);
w_long(co->co_flags, p);
w_object(co_code, p);
w_object(co->co_consts, p);
w_object(co->co_names, p);
w_object(co->co_localsplusnames, p);
w_object(co->co_localspluskinds, p);
w_object(co->co_filename, p);
w_object(co->co_name, p);
w_object(co->co_qualname, p);
w_long(co->co_firstlineno, p);
w_object(co->co_linetable, p);
w_object(co->co_exceptiontable, p);
Py_DECREF(co_code);
}
else if (PyObject_CheckBuffer(v)) {
/* Write unknown bytes-like objects as a bytes object */
Py_buffer view;
if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) {
w_byte(TYPE_UNKNOWN, p);
p->depth--;
p->error = WFERR_UNMARSHALLABLE;
return;
}
W_TYPE(TYPE_STRING, p);
w_pstring(view.buf, view.len, p);
PyBuffer_Release(&view);
}
else {
W_TYPE(TYPE_UNKNOWN, p);
p->error = WFERR_UNMARSHALLABLE;
}
}
static void
w_decref_entry(void *key)
{
PyObject *entry_key = (PyObject *)key;
Py_XDECREF(entry_key);
}
static int
w_init_refs(WFILE *wf, int version)
{
if (version >= 3) {
wf->hashtable = _Py_hashtable_new_full(_Py_hashtable_hash_ptr,
_Py_hashtable_compare_direct,
w_decref_entry, NULL, NULL);
if (wf->hashtable == NULL) {
PyErr_NoMemory();
return -1;
}
}
return 0;
}
static void
w_clear_refs(WFILE *wf)
{
if (wf->hashtable != NULL) {
_Py_hashtable_destroy(wf->hashtable);
}
}
/* version currently has no effect for writing ints. */
/* Note that while the documentation states that this function
* can error, currently it never does. Setting an exception in
* this function should be regarded as an API-breaking change.
*/
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.version = version;
w_long(x, &wf);
w_flush(&wf);
}
void
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
{
char buf[BUFSIZ];
WFILE wf;
if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) {
return; /* caller must check PyErr_Occurred() */
}
memset(&wf, 0, sizeof(wf));
wf.fp = fp;
wf.ptr = wf.buf = buf;
wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK;
wf.version = version;
if (w_init_refs(&wf, version)) {
return; /* caller must check PyErr_Occurred() */
}
w_object(x, &wf);
w_clear_refs(&wf);
w_flush(&wf);
}
typedef struct {
FILE *fp;
int depth;
PyObject *readable; /* Stream-like object being read from */
const char *ptr;
const char *end;
char *buf;
Py_ssize_t buf_size;
PyObject *refs; /* a list */
} RFILE;
static const char *
r_string(Py_ssize_t n, RFILE *p)
{
Py_ssize_t read = -1;
if (p->ptr != NULL) {
/* Fast path for loads() */
const char *res = p->ptr;
Py_ssize_t left = p->end - p->ptr;
if (left < n) {
PyErr_SetString(PyExc_EOFError,
"marshal data too short");
return NULL;
}
p->ptr += n;
return res;
}
if (p->buf == NULL) {
p->buf = PyMem_Malloc(n);
if (p->buf == NULL) {
PyErr_NoMemory();
return NULL;
}
p->buf_size = n;
}
else if (p->buf_size < n) {
char *tmp = PyMem_Realloc(p->buf, n);
if (tmp == NULL) {
PyErr_NoMemory();
return NULL;
}
p->buf = tmp;
p->buf_size = n;
}
if (!p->readable) {
assert(p->fp != NULL);
read = fread(p->buf, 1, n, p->fp);
}
else {
PyObject *res, *mview;
Py_buffer buf;
if (PyBuffer_FillInfo(&buf, NULL, p->buf, n, 0, PyBUF_CONTIG) == -1)
return NULL;
mview = PyMemoryView_FromBuffer(&buf);
if (mview == NULL)
return NULL;
res = _PyObject_CallMethod(p->readable, &_Py_ID(readinto), "N", mview);
if (res != NULL) {
read = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
}
}
if (read != n) {
if (!PyErr_Occurred()) {
if (read > n)
PyErr_Format(PyExc_ValueError,
"read() returned too much data: "
"%zd bytes requested, %zd returned",
n, read);
else
PyErr_SetString(PyExc_EOFError,
"EOF read where not expected");
}
return NULL;
}
return p->buf;
}
static int
r_byte(RFILE *p)
{
if (p->ptr != NULL) {
if (p->ptr < p->end) {
return (unsigned char) *p->ptr++;
}
}
else if (!p->readable) {
assert(p->fp);
int c = getc(p->fp);
if (c != EOF) {
return c;
}
}
else {
const char *ptr = r_string(1, p);
if (ptr != NULL) {
return *(const unsigned char *) ptr;
}
return EOF;
}
PyErr_SetString(PyExc_EOFError,
"EOF read where not expected");
return EOF;
}
static int
r_short(RFILE *p)
{
short x = -1;
const unsigned char *buffer;
buffer = (const unsigned char *) r_string(2, p);
if (buffer != NULL) {
x = buffer[0];
x |= buffer[1] PyLong_MARSHAL_BASE)
goto bad_digit;
/* topmost marshal digit should be nonzero */
if (md == 0 && j == shorts_in_top_digit - 1) {
Py_DECREF(ob);
PyErr_SetString(PyExc_ValueError,
"bad marshal data (unnormalized long data)");
return NULL;
}
d += (digit)md depth--;
return retval;
}
static PyObject *
read_object(RFILE *p)
{
PyObject *v;
if (PyErr_Occurred()) {
fprintf(stderr, "XXX readobject called with exception set\n");
return NULL;
}
if (p->ptr && p->end) {
if (PySys_Audit("marshal.loads", "y#", p->ptr, (Py_ssize_t)(p->end - p->ptr)) < 0) {
return NULL;
}
} else if (p->fp || p->readable) {
if (PySys_Audit("marshal.load", NULL) < 0) {
return NULL;
}
}
v = r_object(p);
if (v == NULL && !PyErr_Occurred())
PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for object");
return v;
}
int
PyMarshal_ReadShortFromFile(FILE *fp)
{
RFILE rf;
int res;
assert(fp);
rf.readable = NULL;
rf.fp = fp;
rf.end = rf.ptr = NULL;
rf.buf = NULL;
res = r_short(&rf);
if (rf.buf != NULL)
PyMem_Free(rf.buf);
return res;
}
long
PyMarshal_ReadLongFromFile(FILE *fp)
{
RFILE rf;
long res;
rf.fp = fp;
rf.readable = NULL;
rf.ptr = rf.end = NULL;
rf.buf = NULL;
res = r_long(&rf);
if (rf.buf != NULL)
PyMem_Free(rf.buf);
return res;
}
/* Return size of file in bytes; < 0 if unknown or INT_MAX if too big */
static off_t
getfilesize(FILE *fp)
{
struct _Py_stat_struct st;
if (_Py_fstat_noraise(fileno(fp), &st) != 0)
return -1;
#if SIZEOF_OFF_T == 4
else if (st.st_size >= INT_MAX)
return (off_t)INT_MAX;
#endif
else
return (off_t)st.st_size;
}
/* If we can get the size of the file up-front, and it's reasonably small,
* read it in one gulp and delegate to ...FromString() instead. Much quicker
* than reading a byte at a time from file; speeds .pyc imports.
* CAUTION: since this may read the entire remainder of the file, don't
* call it unless you know you're done with the file.
*/
PyObject *
PyMarshal_ReadLastObjectFromFile(FILE *fp)
{
/* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */
#define REASONABLE_FILE_LIMIT (1L 0 && filesize tp_name);
result = NULL;
}
else {
rf.depth = 0;
rf.fp = NULL;
rf.readable = file;
rf.ptr = rf.end = NULL;
rf.buf = NULL;
if ((rf.refs = PyList_New(0)) != NULL) {
result = read_object(&rf);
Py_DECREF(rf.refs);
if (rf.buf != NULL)
PyMem_Free(rf.buf);
} else
result = NULL;
}
Py_DECREF(data);
return result;
}
/*[clinic input]
marshal.dumps
value: object
Must be a supported type.
version: int(c_default="Py_MARSHAL_VERSION") = version
Indicates the data format that dumps should use.
/
Return the bytes object that would be written to a file by dump(value, file).
Raise a ValueError exception if value has (or contains an object that has) an
unsupported type.
[clinic start generated code]*/
static PyObject *
marshal_dumps_impl(PyObject *module, PyObject *value, int version)
/*[clinic end generated code: output=9c200f98d7256cad input=a2139ea8608e9b27]*/
{
return PyMarshal_WriteObjectToString(value, version);
}
/*[clinic input]
marshal.loads
bytes: Py_buffer
/
Convert the bytes-like object to a value.
If no valid value is found, raise EOFError, ValueError or TypeError. Extra
bytes in the input are ignored.
[clinic start generated code]*/
static PyObject *
marshal_loads_impl(PyObject *module, Py_buffer *bytes)
/*[clinic end generated code: output=9fc65985c93d1bb1 input=6f426518459c8495]*/
{
RFILE rf;
char *s = bytes->buf;
Py_ssize_t n = bytes->len;
PyObject* result;
rf.fp = NULL;
rf.readable = NULL;
rf.ptr = s;
rf.end = s + n;
rf.depth = 0;
if ((rf.refs = PyList_New(0)) == NULL)
return NULL;
result = read_object(&rf);
Py_DECREF(rf.refs);
return result;
}
static PyMethodDef marshal_methods[] = {
MARSHAL_DUMP_METHODDEF
MARSHAL_LOAD_METHODDEF
MARSHAL_DUMPS_METHODDEF
MARSHAL_LOADS_METHODDEF
{NULL, NULL} /* sentinel */
};
PyDoc_STRVAR(module_doc,
"This module contains functions that can read and write Python values in\n\
a binary format. The format is specific to Python, but independent of\n\
machine architecture issues.\n\
\n\
Not all Python object types are supported; in general, only objects\n\
whose value is independent from a particular invocation of Python can be\n\
written and read by this module. The following types are supported:\n\
None, integers, floating point numbers, strings, bytes, bytearrays,\n\
tuples, lists, sets, dictionaries, and code objects, where it\n\
should be understood that tuples, lists and dictionaries are only\n\
supported as long as the values contained therein are themselves\n\
supported; and recursive lists and dictionaries should not be written\n\
(they will cause infinite loops).\n\
\n\
Variables:\n\
\n\
version -- indicates the format that the module uses. Version 0 is the\n\
historical format, version 1 shares interned strings and version 2\n\
uses a binary format for floating point numbers.\n\
Version 3 shares common object references (New in version 3.4).\n\
\n\
Functions:\n\
\n\
dump() -- write value to a file\n\
load() -- read value from a file\n\
dumps() -- marshal value as a bytes object\n\
loads() -- read value from a bytes-like object");
static int
marshal_module_exec(PyObject *mod)
{
if (PyModule_AddIntConstant(mod, "version", Py_MARSHAL_VERSION) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot marshalmodule_slots[] = {
{Py_mod_exec, marshal_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL}
};
static struct PyModuleDef marshalmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "marshal",
.m_doc = module_doc,
.m_methods = marshal_methods,
.m_slots = marshalmodule_slots,
};
PyMODINIT_FUNC
PyMarshal_Init(void)
{
return PyModuleDef_Init(&marshalmodule);
}