summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/marshal.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/marshal.c')
-rw-r--r--contrib/tools/python3/Python/marshal.c146
1 files changed, 109 insertions, 37 deletions
diff --git a/contrib/tools/python3/Python/marshal.c b/contrib/tools/python3/Python/marshal.c
index 3fc3f890422..65481341bdf 100644
--- a/contrib/tools/python3/Python/marshal.c
+++ b/contrib/tools/python3/Python/marshal.c
@@ -6,16 +6,20 @@
Version 3 of this protocol properly supports circular links
and sharing. */
-#define PY_SSIZE_T_CLEAN
-
#include "Python.h"
-#include "pycore_call.h" // _PyObject_CallNoArgs()
-#include "pycore_code.h" // _PyCode_New()
-#include "pycore_long.h" // _PyLong_DigitCount
-#include "pycore_hashtable.h" // _Py_hashtable_t
-#include "marshal.h" // Py_MARSHAL_VERSION
+#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]*/
@@ -35,11 +39,15 @@ module marshal
* #if defined(MS_WINDOWS) && defined(_DEBUG)
*/
#if defined(MS_WINDOWS)
-#define MAX_MARSHAL_STACK_DEPTH 1000
+# define MAX_MARSHAL_STACK_DEPTH 1000
#elif defined(__wasi__)
-#define MAX_MARSHAL_STACK_DEPTH 1500
+# define MAX_MARSHAL_STACK_DEPTH 1500
+// 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 1500
#else
-#define MAX_MARSHAL_STACK_DEPTH 2000
+# define MAX_MARSHAL_STACK_DEPTH 2000
#endif
#define TYPE_NULL '0'
@@ -80,6 +88,7 @@ module marshal
#define WFERR_UNMARSHALLABLE 1
#define WFERR_NESTEDTOODEEP 2
#define WFERR_NOMEMORY 3
+#define WFERR_CODE_NOT_ALLOWED 4
typedef struct {
FILE *fp;
@@ -91,6 +100,7 @@ typedef struct {
char *buf;
_Py_hashtable_t *hashtable;
int version;
+ int allow_code;
} WFILE;
#define w_byte(c, p) do { \
@@ -227,6 +237,9 @@ w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
w_byte((t) | flag, (p)); \
} while(0)
+static PyObject *
+_PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code);
+
static void
w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
{
@@ -349,6 +362,10 @@ w_object(PyObject *v, WFILE *p)
{
char flag = '\0';
+ if (p->error != WFERR_OK) {
+ return;
+ }
+
p->depth++;
if (p->depth > MAX_MARSHAL_STACK_DEPTH) {
@@ -521,22 +538,29 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
return;
}
Py_ssize_t i = 0;
- while (_PySet_NextEntry(v, &pos, &value, &hash)) {
- PyObject *dump = PyMarshal_WriteObjectToString(value, p->version);
+ Py_BEGIN_CRITICAL_SECTION(v);
+ while (_PySet_NextEntryRef(v, &pos, &value, &hash)) {
+ PyObject *dump = _PyMarshal_WriteObjectToString(value,
+ p->version, p->allow_code);
if (dump == NULL) {
p->error = WFERR_UNMARSHALLABLE;
- Py_DECREF(pairs);
- return;
+ Py_DECREF(value);
+ break;
}
PyObject *pair = PyTuple_Pack(2, dump, value);
Py_DECREF(dump);
+ Py_DECREF(value);
if (pair == NULL) {
p->error = WFERR_NOMEMORY;
- Py_DECREF(pairs);
- return;
+ break;
}
PyList_SET_ITEM(pairs, i++, pair);
}
+ Py_END_CRITICAL_SECTION();
+ if (p->error == WFERR_UNMARSHALLABLE || p->error == WFERR_NOMEMORY) {
+ Py_DECREF(pairs);
+ return;
+ }
assert(i == n);
if (PyList_Sort(pairs)) {
p->error = WFERR_NOMEMORY;
@@ -551,6 +575,10 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
Py_DECREF(pairs);
}
else if (PyCode_Check(v)) {
+ if (!p->allow_code) {
+ p->error = WFERR_CODE_NOT_ALLOWED;
+ return;
+ }
PyCodeObject *co = (PyCodeObject *)v;
PyObject *co_code = _PyCode_GetCode(co);
if (co_code == NULL) {
@@ -659,6 +687,7 @@ PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK;
wf.version = version;
+ wf.allow_code = 1;
if (w_init_refs(&wf, version)) {
return; /* caller must check PyErr_Occurred() */
}
@@ -676,6 +705,7 @@ typedef struct {
char *buf;
Py_ssize_t buf_size;
PyObject *refs; /* a list */
+ int allow_code;
} RFILE;
static const char *
@@ -1017,7 +1047,7 @@ r_object(RFILE *p)
break;
case TYPE_NONE:
- retval = Py_NewRef(Py_None);
+ retval = Py_None;
break;
case TYPE_STOPITER:
@@ -1025,15 +1055,15 @@ r_object(RFILE *p)
break;
case TYPE_ELLIPSIS:
- retval = Py_NewRef(Py_Ellipsis);
+ retval = Py_Ellipsis;
break;
case TYPE_FALSE:
- retval = Py_NewRef(Py_False);
+ retval = Py_False;
break;
case TYPE_TRUE:
- retval = Py_NewRef(Py_True);
+ retval = Py_True;
break;
case TYPE_INT:
@@ -1374,6 +1404,11 @@ r_object(RFILE *p)
PyObject* linetable = NULL;
PyObject *exceptiontable = NULL;
+ if (!p->allow_code) {
+ PyErr_SetString(PyExc_ValueError,
+ "unmarshalling code objects is disallowed");
+ break;
+ }
idx = r_ref_reserve(flag, p);
if (idx < 0)
break;
@@ -1619,6 +1654,7 @@ PyMarshal_ReadObjectFromFile(FILE *fp)
{
RFILE rf;
PyObject *result;
+ rf.allow_code = 1;
rf.fp = fp;
rf.readable = NULL;
rf.depth = 0;
@@ -1639,6 +1675,7 @@ PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len)
{
RFILE rf;
PyObject *result;
+ rf.allow_code = 1;
rf.fp = NULL;
rf.readable = NULL;
rf.ptr = str;
@@ -1655,8 +1692,8 @@ PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len)
return result;
}
-PyObject *
-PyMarshal_WriteObjectToString(PyObject *x, int version)
+static PyObject *
+_PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code)
{
WFILE wf;
@@ -1671,6 +1708,7 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
wf.end = wf.ptr + PyBytes_GET_SIZE(wf.str);
wf.error = WFERR_OK;
wf.version = version;
+ wf.allow_code = allow_code;
if (w_init_refs(&wf, version)) {
Py_DECREF(wf.str);
return NULL;
@@ -1684,17 +1722,35 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
}
if (wf.error != WFERR_OK) {
Py_XDECREF(wf.str);
- if (wf.error == WFERR_NOMEMORY)
+ switch (wf.error) {
+ case WFERR_NOMEMORY:
PyErr_NoMemory();
- else
+ break;
+ case WFERR_NESTEDTOODEEP:
+ PyErr_SetString(PyExc_ValueError,
+ "object too deeply nested to marshal");
+ break;
+ case WFERR_CODE_NOT_ALLOWED:
PyErr_SetString(PyExc_ValueError,
- (wf.error==WFERR_UNMARSHALLABLE)?"unmarshallable object"
- :"object too deeply nested to marshal");
+ "marshalling code objects is disallowed");
+ break;
+ default:
+ case WFERR_UNMARSHALLABLE:
+ PyErr_SetString(PyExc_ValueError,
+ "unmarshallable object");
+ break;
+ }
return NULL;
}
return wf.str;
}
+PyObject *
+PyMarshal_WriteObjectToString(PyObject *x, int version)
+{
+ return _PyMarshal_WriteObjectToString(x, version, 1);
+}
+
/* And an interface for Python programs... */
/*[clinic input]
marshal.dump
@@ -1706,6 +1762,9 @@ marshal.dump
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.
@@ -1716,17 +1775,17 @@ to the file. The object will not be properly read back by load().
static PyObject *
marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file,
- int version)
-/*[clinic end generated code: output=aaee62c7028a7cb2 input=6c7a3c23c6fef556]*/
+ int version, int allow_code)
+/*[clinic end generated code: output=429e5fd61c2196b9 input=041f7f6669b0aafb]*/
{
/* XXX Quick hack -- need to do this differently */
PyObject *s;
PyObject *res;
- s = PyMarshal_WriteObjectToString(value, version);
+ s = _PyMarshal_WriteObjectToString(value, version, allow_code);
if (s == NULL)
return NULL;
- res = _PyObject_CallMethodOneArg(file, &_Py_ID(write), s);
+ res = PyObject_CallMethodOneArg(file, &_Py_ID(write), s);
Py_DECREF(s);
return res;
}
@@ -1737,6 +1796,9 @@ 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.
@@ -1749,8 +1811,8 @@ dump(), load() will substitute None for the unmarshallable type.
[clinic start generated code]*/
static PyObject *
-marshal_load(PyObject *module, PyObject *file)
-/*[clinic end generated code: output=f8e5c33233566344 input=c85c2b594cd8124a]*/
+marshal_load_impl(PyObject *module, PyObject *file, int allow_code)
+/*[clinic end generated code: output=0c1aaf3546ae3ed3 input=2dca7b570653b82f]*/
{
PyObject *data, *result;
RFILE rf;
@@ -1772,6 +1834,7 @@ marshal_load(PyObject *module, PyObject *file)
result = NULL;
}
else {
+ rf.allow_code = allow_code;
rf.depth = 0;
rf.fp = NULL;
rf.readable = file;
@@ -1797,6 +1860,9 @@ marshal.dumps
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).
@@ -1805,10 +1871,11 @@ 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]*/
+marshal_dumps_impl(PyObject *module, PyObject *value, int version,
+ int allow_code)
+/*[clinic end generated code: output=115f90da518d1d49 input=167eaecceb63f0a8]*/
{
- return PyMarshal_WriteObjectToString(value, version);
+ return _PyMarshal_WriteObjectToString(value, version, allow_code);
}
/*[clinic input]
@@ -1816,6 +1883,9 @@ marshal.loads
bytes: Py_buffer
/
+ *
+ allow_code: bool = True
+ Allow to load code objects.
Convert the bytes-like object to a value.
@@ -1824,13 +1894,14 @@ 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]*/
+marshal_loads_impl(PyObject *module, Py_buffer *bytes, int allow_code)
+/*[clinic end generated code: output=62c0c538d3edc31f input=14de68965b45aaa7]*/
{
RFILE rf;
char *s = bytes->buf;
Py_ssize_t n = bytes->len;
PyObject* result;
+ rf.allow_code = allow_code;
rf.fp = NULL;
rf.readable = NULL;
rf.ptr = s;
@@ -1894,6 +1965,7 @@ marshal_module_exec(PyObject *mod)
static PyModuleDef_Slot marshalmodule_slots[] = {
{Py_mod_exec, marshal_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL}
};