bpo-41288: Refactor of unpickling NEWOBJ and NEWOBJ_EX opcodes. (GH-21472)

* Share code for NEWOBJ and NEWOBJ_EX.
* More detailed error messages.
This commit is contained in:
Serhiy Storchaka 2020-07-18 11:11:21 +03:00 committed by GitHub
parent d583738a87
commit b4c98ed41e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 33 additions and 76 deletions

View File

@ -5912,118 +5912,75 @@ load_inst(UnpicklerObject *self)
return 0; return 0;
} }
static int static void
load_newobj(UnpicklerObject *self) newobj_unpickling_error(const char * msg, int use_kwargs, PyObject *arg)
{ {
PyObject *args = NULL;
PyObject *clsraw = NULL;
PyTypeObject *cls; /* clsraw cast to its true type */
PyObject *obj;
PickleState *st = _Pickle_GetGlobalState(); PickleState *st = _Pickle_GetGlobalState();
PyErr_Format(st->UnpicklingError, msg,
/* Stack is ... cls argtuple, and we want to call use_kwargs ? "NEWOBJ_EX" : "NEWOBJ",
* cls.__new__(cls, *argtuple). Py_TYPE(arg)->tp_name);
*/
PDATA_POP(self->stack, args);
if (args == NULL)
goto error;
if (!PyTuple_Check(args)) {
PyErr_SetString(st->UnpicklingError,
"NEWOBJ expected an arg " "tuple.");
goto error;
}
PDATA_POP(self->stack, clsraw);
cls = (PyTypeObject *)clsraw;
if (cls == NULL)
goto error;
if (!PyType_Check(cls)) {
PyErr_SetString(st->UnpicklingError, "NEWOBJ class argument "
"isn't a type object");
goto error;
}
if (cls->tp_new == NULL) {
PyErr_SetString(st->UnpicklingError, "NEWOBJ class argument "
"has NULL tp_new");
goto error;
}
/* Call __new__. */
obj = cls->tp_new(cls, args, NULL);
if (obj == NULL)
goto error;
Py_DECREF(args);
Py_DECREF(clsraw);
PDATA_PUSH(self->stack, obj, -1);
return 0;
error:
Py_XDECREF(args);
Py_XDECREF(clsraw);
return -1;
} }
static int static int
load_newobj_ex(UnpicklerObject *self) load_newobj(UnpicklerObject *self, int use_kwargs)
{ {
PyObject *cls, *args, *kwargs; PyObject *cls, *args, *kwargs = NULL;
PyObject *obj; PyObject *obj;
PickleState *st = _Pickle_GetGlobalState();
PDATA_POP(self->stack, kwargs); /* Stack is ... cls args [kwargs], and we want to call
if (kwargs == NULL) { * cls.__new__(cls, *args, **kwargs).
return -1; */
if (use_kwargs) {
PDATA_POP(self->stack, kwargs);
if (kwargs == NULL) {
return -1;
}
} }
PDATA_POP(self->stack, args); PDATA_POP(self->stack, args);
if (args == NULL) { if (args == NULL) {
Py_DECREF(kwargs); Py_XDECREF(kwargs);
return -1; return -1;
} }
PDATA_POP(self->stack, cls); PDATA_POP(self->stack, cls);
if (cls == NULL) { if (cls == NULL) {
Py_DECREF(kwargs); Py_XDECREF(kwargs);
Py_DECREF(args); Py_DECREF(args);
return -1; return -1;
} }
if (!PyType_Check(cls)) { if (!PyType_Check(cls)) {
PyErr_Format(st->UnpicklingError, newobj_unpickling_error("%s class argument must be a type, not %.200s",
"NEWOBJ_EX class argument must be a type, not %.200s", use_kwargs, cls);
Py_TYPE(cls)->tp_name);
goto error; goto error;
} }
if (((PyTypeObject *)cls)->tp_new == NULL) { if (((PyTypeObject *)cls)->tp_new == NULL) {
PyErr_SetString(st->UnpicklingError, newobj_unpickling_error("%s class argument '%.200s' doesn't have __new__",
"NEWOBJ_EX class argument doesn't have __new__"); use_kwargs, cls);
goto error; goto error;
} }
if (!PyTuple_Check(args)) { if (!PyTuple_Check(args)) {
PyErr_Format(st->UnpicklingError, newobj_unpickling_error("%s args argument must be a tuple, not %.200s",
"NEWOBJ_EX args argument must be a tuple, not %.200s", use_kwargs, args);
Py_TYPE(args)->tp_name);
goto error; goto error;
} }
if (!PyDict_Check(kwargs)) { if (use_kwargs && !PyDict_Check(kwargs)) {
PyErr_Format(st->UnpicklingError, newobj_unpickling_error("%s kwargs argument must be a dict, not %.200s",
"NEWOBJ_EX kwargs argument must be a dict, not %.200s", use_kwargs, kwargs);
Py_TYPE(kwargs)->tp_name);
goto error; goto error;
} }
obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs); obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
Py_DECREF(kwargs); if (obj == NULL) {
goto error;
}
Py_XDECREF(kwargs);
Py_DECREF(args); Py_DECREF(args);
Py_DECREF(cls); Py_DECREF(cls);
if (obj == NULL) {
return -1;
}
PDATA_PUSH(self->stack, obj, -1); PDATA_PUSH(self->stack, obj, -1);
return 0; return 0;
error: error:
Py_DECREF(kwargs); Py_XDECREF(kwargs);
Py_DECREF(args); Py_DECREF(args);
Py_DECREF(cls); Py_DECREF(cls);
return -1; return -1;
@ -6956,8 +6913,8 @@ load(UnpicklerObject *self)
OP(FROZENSET, load_frozenset) OP(FROZENSET, load_frozenset)
OP(OBJ, load_obj) OP(OBJ, load_obj)
OP(INST, load_inst) OP(INST, load_inst)
OP(NEWOBJ, load_newobj) OP_ARG(NEWOBJ, load_newobj, 0)
OP(NEWOBJ_EX, load_newobj_ex) OP_ARG(NEWOBJ_EX, load_newobj, 1)
OP(GLOBAL, load_global) OP(GLOBAL, load_global)
OP(STACK_GLOBAL, load_stack_global) OP(STACK_GLOBAL, load_stack_global)
OP(APPEND, load_append) OP(APPEND, load_append)