cpython/Python/marshal.c


/* 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_critical_section.h" // Py_BEGIN_CRITICAL_SECTION()
#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
#include "pycore_pystate.h"          // _PyInterpreterState_GET()

#ifdef __APPLE__
#  include "TargetConditionals.h"
#endif /* __APPLE__ */

/*[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
#elif defined(__wasi__)
#define MAX_MARSHAL_STACK_DEPTH
// TARGET_OS_IPHONE covers any non-macOS Apple platform.
// It won't be defined on older macOS SDKs
#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#define MAX_MARSHAL_STACK_DEPTH
#else
#define MAX_MARSHAL_STACK_DEPTH
#endif

/* Supported types */
#define TYPE_NULL
#define TYPE_NONE
#define TYPE_FALSE
#define TYPE_TRUE
#define TYPE_STOPITER
#define TYPE_ELLIPSIS
#define TYPE_BINARY_FLOAT
#define TYPE_BINARY_COMPLEX
#define TYPE_LONG
#define TYPE_STRING
#define TYPE_TUPLE
#define TYPE_LIST
#define TYPE_DICT
#define TYPE_CODE
#define TYPE_UNICODE
#define TYPE_UNKNOWN
// added in version 2:
#define TYPE_SET
#define TYPE_FROZENSET
// added in version 5:
#define TYPE_SLICE
// Remember to update the version and documentation when adding new types.

/* Special cases for unicode strings (added in version 4) */
#define TYPE_INTERNED
#define TYPE_ASCII
#define TYPE_ASCII_INTERNED
#define TYPE_SHORT_ASCII
#define TYPE_SHORT_ASCII_INTERNED

/* Special cases for small objects */
#define TYPE_INT
#define TYPE_SMALL_TUPLE

/* Supported for backwards compatibility */
#define TYPE_COMPLEX
#define TYPE_FLOAT
#define TYPE_INT64

/* References (added in version 3) */
#define TYPE_REF
#define FLAG_REF


// Error codes:
#define WFERR_OK
#define WFERR_UNMARSHALLABLE
#define WFERR_NESTEDTOODEEP
#define WFERR_NOMEMORY
#define WFERR_CODE_NOT_ALLOWED

WFILE;

#define w_byte(c, p)

static void
w_flush(WFILE *p)
{}

static int
w_reserve(WFILE *p, Py_ssize_t needed)
{}

static void
w_string(const void *s, Py_ssize_t n, WFILE *p)
{}

static void
w_short(int x, WFILE *p)
{}

static void
w_long(long x, WFILE *p)
{}

#define SIZE32_MAX

#if SIZEOF_SIZE_T > 4
#define W_SIZE(n, p)
#else
#define W_SIZE
#endif

static void
w_pstring(const void *s, Py_ssize_t n, WFILE *p)
{}

static void
w_short_pstring(const void *s, Py_ssize_t n, WFILE *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
#define PyLong_MARSHAL_BASE
#define PyLong_MARSHAL_MASK
#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0
#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT"
#endif
#define PyLong_MARSHAL_RATIO

#define W_TYPE(t, p)

static PyObject *
_PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code);

static void
w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
{}

static void
w_float_bin(double v, WFILE *p)
{}

static void
w_float_str(double v, WFILE *p)
{}

static int
w_ref(PyObject *v, char *flag, WFILE *p)
{}

static void
w_complex_object(PyObject *v, char flag, WFILE *p);

static void
w_object(PyObject *v, WFILE *p)
{}

static void
w_complex_object(PyObject *v, char flag, WFILE *p)
{}

static void
w_decref_entry(void *key)
{}

static int
w_init_refs(WFILE *wf, int version)
{}

static void
w_clear_refs(WFILE *wf)
{}

/* 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)
{}

void
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
{}

RFILE;

static const char *
r_string(Py_ssize_t n, RFILE *p)
{}

static int
r_byte(RFILE *p)
{}

static int
r_short(RFILE *p)
{}

static long
r_long(RFILE *p)
{}

/* r_long64 deals with the TYPE_INT64 code. */
static PyObject *
r_long64(RFILE *p)
{}

static PyObject *
r_PyLong(RFILE *p)
{}

static double
r_float_bin(RFILE *p)
{}

/* Issue #33720: Disable inlining for reducing the C stack consumption
   on PGO builds. */
Py_NO_INLINE static double
r_float_str(RFILE *p)
{}

/* allocate the reflist index for a new object. Return -1 on failure */
static Py_ssize_t
r_ref_reserve(int flag, RFILE *p)
{}

/* insert the new object 'o' to the reflist at previously
 * allocated index 'idx'.
 * 'o' can be NULL, in which case nothing is done.
 * if 'o' was non-NULL, and the function succeeds, 'o' is returned.
 * if 'o' was non-NULL, and the function fails, 'o' is released and
 * NULL returned. This simplifies error checking at the call site since
 * a single test for NULL for the function result is enough.
 */
static PyObject *
r_ref_insert(PyObject *o, Py_ssize_t idx, int flag, RFILE *p)
{}

/* combination of both above, used when an object can be
 * created whenever it is seen in the file, as opposed to
 * after having loaded its sub-objects.
 */
static PyObject *
r_ref(PyObject *o, int flag, RFILE *p)
{}

static PyObject *
r_object(RFILE *p)
{}

static PyObject *
read_object(RFILE *p)
{}

int
PyMarshal_ReadShortFromFile(FILE *fp)
{}

long
PyMarshal_ReadLongFromFile(FILE *fp)
{}

/* Return size of file in bytes; < 0 if unknown or INT_MAX if too big */
static off_t
getfilesize(FILE *fp)
{}

/* 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)
{}

PyObject *
PyMarshal_ReadObjectFromFile(FILE *fp)
{}

PyObject *
PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len)
{}

static PyObject *
_PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code)
{}

PyObject *
PyMarshal_WriteObjectToString(PyObject *x, int version)
{}

/* And an interface for Python programs... */
/*[clinic input]
marshal.dump

    value: object
        Must be a supported type.
    file: object
        Must be a writeable binary file.
    version: int(c_default="Py_MARSHAL_VERSION") = version
        Indicates the data format that dump should use.
    /
    *
    allow_code: bool = True
        Allow to write code objects.

Write the value on the open file.

If the value has (or contains an object that has) an unsupported type, a
ValueError exception is raised - but garbage data will also be written
to the file. The object will not be properly read back by load().
[clinic start generated code]*/

static PyObject *
marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file,
                  int version, int allow_code)
/*[clinic end generated code: output=429e5fd61c2196b9 input=041f7f6669b0aafb]*/
{}

/*[clinic input]
marshal.load

    file: object
        Must be readable binary file.
    /
    *
    allow_code: bool = True
        Allow to load code objects.

Read one value from the open file and return it.

If no valid value is read (e.g. because the data has a different Python
version's incompatible marshal format), raise EOFError, ValueError or
TypeError.

Note: If an object containing an unsupported type was marshalled with
dump(), load() will substitute None for the unmarshallable type.
[clinic start generated code]*/

static PyObject *
marshal_load_impl(PyObject *module, PyObject *file, int allow_code)
/*[clinic end generated code: output=0c1aaf3546ae3ed3 input=2dca7b570653b82f]*/
{}

/*[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.
    /
    *
    allow_code: bool = True
        Allow to write code objects.

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,
                   int allow_code)
/*[clinic end generated code: output=115f90da518d1d49 input=167eaecceb63f0a8]*/
{}

/*[clinic input]
marshal.loads

    bytes: Py_buffer
    /
    *
    allow_code: bool = True
        Allow to load code objects.

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, int allow_code)
/*[clinic end generated code: output=62c0c538d3edc31f input=14de68965b45aaa7]*/
{}

static PyMethodDef marshal_methods[] =;


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)
{}

static PyModuleDef_Slot marshalmodule_slots[] =;

static struct PyModuleDef marshalmodule =;

PyMODINIT_FUNC
PyMarshal_Init(void)
{}