bpo-30243: Fixed the possibility of a crash in _json. (#1420)

It was possible to get a core dump by using uninitialized
_json objects. Now __new__ methods create initialized objects.
__init__ methods are removed.
This commit is contained in:
Serhiy Storchaka 2017-05-05 10:08:49 +03:00 committed by GitHub
parent 898ff03e1e
commit 76a3e51a40
2 changed files with 24 additions and 66 deletions

View File

@ -317,6 +317,10 @@ Extension Modules
Library Library
------- -------
- bpo-30243: Removed the __init__ methods of _json's scanner and encoder.
Misusing them could cause memory leaks or crashes. Now scanner and encoder
objects are completely initialized in the __new__ methods.
- bpo-30215: Compiled regular expression objects with the re.LOCALE flag no - bpo-30215: Compiled regular expression objects with the re.LOCALE flag no
longer depend on the locale at compile time. Only the locale at matching longer depend on the locale at compile time. Only the locale at matching
time affects the result of matching. time affects the result of matching.

View File

@ -89,16 +89,12 @@ static PyObject *
_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx); _build_rval_index_tuple(PyObject *rval, Py_ssize_t idx);
static PyObject * static PyObject *
scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds); scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int
scanner_init(PyObject *self, PyObject *args, PyObject *kwds);
static void static void
scanner_dealloc(PyObject *self); scanner_dealloc(PyObject *self);
static int static int
scanner_clear(PyObject *self); scanner_clear(PyObject *self);
static PyObject * static PyObject *
encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int
encoder_init(PyObject *self, PyObject *args, PyObject *kwds);
static void static void
encoder_dealloc(PyObject *self); encoder_dealloc(PyObject *self);
static int static int
@ -1200,38 +1196,21 @@ static PyObject *
scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds) scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
PyScannerObject *s; PyScannerObject *s;
s = (PyScannerObject *)type->tp_alloc(type, 0);
if (s != NULL) {
s->strict = NULL;
s->object_hook = NULL;
s->object_pairs_hook = NULL;
s->parse_float = NULL;
s->parse_int = NULL;
s->parse_constant = NULL;
}
return (PyObject *)s;
}
static int
scanner_init(PyObject *self, PyObject *args, PyObject *kwds)
{
/* Initialize Scanner object */
PyObject *ctx; PyObject *ctx;
static char *kwlist[] = {"context", NULL}; static char *kwlist[] = {"context", NULL};
PyScannerObject *s;
assert(PyScanner_Check(self));
s = (PyScannerObject *)self;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx)) if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx))
return -1; return NULL;
if (s->memo == NULL) { s = (PyScannerObject *)type->tp_alloc(type, 0);
s->memo = PyDict_New(); if (s == NULL) {
if (s->memo == NULL) return NULL;
goto bail;
} }
s->memo = PyDict_New();
if (s->memo == NULL)
goto bail;
/* All of these will fail "gracefully" so we don't need to verify them */ /* All of these will fail "gracefully" so we don't need to verify them */
s->strict = PyObject_GetAttrString(ctx, "strict"); s->strict = PyObject_GetAttrString(ctx, "strict");
if (s->strict == NULL) if (s->strict == NULL)
@ -1252,16 +1231,11 @@ scanner_init(PyObject *self, PyObject *args, PyObject *kwds)
if (s->parse_constant == NULL) if (s->parse_constant == NULL)
goto bail; goto bail;
return 0; return (PyObject *)s;
bail: bail:
Py_CLEAR(s->strict); Py_DECREF(s);
Py_CLEAR(s->object_hook); return NULL;
Py_CLEAR(s->object_pairs_hook);
Py_CLEAR(s->parse_float);
Py_CLEAR(s->parse_int);
Py_CLEAR(s->parse_constant);
return -1;
} }
PyDoc_STRVAR(scanner_doc, "JSON scanner object"); PyDoc_STRVAR(scanner_doc, "JSON scanner object");
@ -1303,7 +1277,7 @@ PyTypeObject PyScannerType = {
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
0, /* tp_dictoffset */ 0, /* tp_dictoffset */
scanner_init, /* tp_init */ 0, /* tp_init */
0,/* PyType_GenericAlloc, */ /* tp_alloc */ 0,/* PyType_GenericAlloc, */ /* tp_alloc */
scanner_new, /* tp_new */ scanner_new, /* tp_new */
0,/* PyObject_GC_Del, */ /* tp_free */ 0,/* PyObject_GC_Del, */ /* tp_free */
@ -1312,25 +1286,6 @@ PyTypeObject PyScannerType = {
static PyObject * static PyObject *
encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
PyEncoderObject *s;
s = (PyEncoderObject *)type->tp_alloc(type, 0);
if (s != NULL) {
s->markers = NULL;
s->defaultfn = NULL;
s->encoder = NULL;
s->indent = NULL;
s->key_separator = NULL;
s->item_separator = NULL;
s->sort_keys = NULL;
s->skipkeys = NULL;
}
return (PyObject *)s;
}
static int
encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
{
/* initialize Encoder object */
static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", NULL}; static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", NULL};
PyEncoderObject *s; PyEncoderObject *s;
@ -1338,22 +1293,23 @@ encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *item_separator, *sort_keys, *skipkeys; PyObject *item_separator, *sort_keys, *skipkeys;
int allow_nan; int allow_nan;
assert(PyEncoder_Check(self));
s = (PyEncoderObject *)self;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUOOp:make_encoder", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUOOp:make_encoder", kwlist,
&markers, &defaultfn, &encoder, &indent, &markers, &defaultfn, &encoder, &indent,
&key_separator, &item_separator, &key_separator, &item_separator,
&sort_keys, &skipkeys, &allow_nan)) &sort_keys, &skipkeys, &allow_nan))
return -1; return NULL;
if (markers != Py_None && !PyDict_Check(markers)) { if (markers != Py_None && !PyDict_Check(markers)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"make_encoder() argument 1 must be dict or None, " "make_encoder() argument 1 must be dict or None, "
"not %.200s", Py_TYPE(markers)->tp_name); "not %.200s", Py_TYPE(markers)->tp_name);
return -1; return NULL;
} }
s = (PyEncoderObject *)type->tp_alloc(type, 0);
if (s == NULL)
return NULL;
s->markers = markers; s->markers = markers;
s->defaultfn = defaultfn; s->defaultfn = defaultfn;
s->encoder = encoder; s->encoder = encoder;
@ -1380,7 +1336,7 @@ encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
Py_INCREF(s->item_separator); Py_INCREF(s->item_separator);
Py_INCREF(s->sort_keys); Py_INCREF(s->sort_keys);
Py_INCREF(s->skipkeys); Py_INCREF(s->skipkeys);
return 0; return (PyObject *)s;
} }
static PyObject * static PyObject *
@ -1911,7 +1867,7 @@ PyTypeObject PyEncoderType = {
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
0, /* tp_dictoffset */ 0, /* tp_dictoffset */
encoder_init, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
encoder_new, /* tp_new */ encoder_new, /* tp_new */
0, /* tp_free */ 0, /* tp_free */
@ -1954,10 +1910,8 @@ PyInit__json(void)
PyObject *m = PyModule_Create(&jsonmodule); PyObject *m = PyModule_Create(&jsonmodule);
if (!m) if (!m)
return NULL; return NULL;
PyScannerType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyScannerType) < 0) if (PyType_Ready(&PyScannerType) < 0)
goto fail; goto fail;
PyEncoderType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyEncoderType) < 0) if (PyType_Ready(&PyEncoderType) < 0)
goto fail; goto fail;
Py_INCREF((PyObject*)&PyScannerType); Py_INCREF((PyObject*)&PyScannerType);