Skip to content

Commit

Permalink
bpo-30243: Fixed the possibility of a crash in _json. (#1420)
Browse files Browse the repository at this point in the history
It was possible to get a core dump by using uninitialized
_json objects. Now __new__ methods create initialized objects.
__init__ methods are removed.
  • Loading branch information
serhiy-storchaka committed May 5, 2017
1 parent 898ff03 commit 76a3e51
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 66 deletions.
4 changes: 4 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ Extension Modules
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
longer depend on the locale at compile time. Only the locale at matching
time affects the result of matching.
Expand Down
86 changes: 20 additions & 66 deletions Modules/_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,12 @@ static PyObject *
_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx);
static PyObject *
scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int
scanner_init(PyObject *self, PyObject *args, PyObject *kwds);
static void
scanner_dealloc(PyObject *self);
static int
scanner_clear(PyObject *self);
static PyObject *
encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int
encoder_init(PyObject *self, PyObject *args, PyObject *kwds);
static void
encoder_dealloc(PyObject *self);
static int
Expand Down Expand Up @@ -1200,38 +1196,21 @@ static PyObject *
scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
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;
static char *kwlist[] = {"context", NULL};
PyScannerObject *s;

assert(PyScanner_Check(self));
s = (PyScannerObject *)self;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx))
return -1;
return NULL;

if (s->memo == NULL) {
s->memo = PyDict_New();
if (s->memo == NULL)
goto bail;
s = (PyScannerObject *)type->tp_alloc(type, 0);
if (s == NULL) {
return NULL;
}

s->memo = PyDict_New();
if (s->memo == NULL)
goto bail;

/* All of these will fail "gracefully" so we don't need to verify them */
s->strict = PyObject_GetAttrString(ctx, "strict");
if (s->strict == NULL)
Expand All @@ -1252,16 +1231,11 @@ scanner_init(PyObject *self, PyObject *args, PyObject *kwds)
if (s->parse_constant == NULL)
goto bail;

return 0;
return (PyObject *)s;

bail:
Py_CLEAR(s->strict);
Py_CLEAR(s->object_hook);
Py_CLEAR(s->object_pairs_hook);
Py_CLEAR(s->parse_float);
Py_CLEAR(s->parse_int);
Py_CLEAR(s->parse_constant);
return -1;
Py_DECREF(s);
return NULL;
}

PyDoc_STRVAR(scanner_doc, "JSON scanner object");
Expand Down Expand Up @@ -1303,7 +1277,7 @@ PyTypeObject PyScannerType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
scanner_init, /* tp_init */
0, /* tp_init */
0,/* PyType_GenericAlloc, */ /* tp_alloc */
scanner_new, /* tp_new */
0,/* PyObject_GC_Del, */ /* tp_free */
Expand All @@ -1312,48 +1286,30 @@ PyTypeObject PyScannerType = {
static PyObject *
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};

PyEncoderObject *s;
PyObject *markers, *defaultfn, *encoder, *indent, *key_separator;
PyObject *item_separator, *sort_keys, *skipkeys;
int allow_nan;

assert(PyEncoder_Check(self));
s = (PyEncoderObject *)self;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUOOp:make_encoder", kwlist,
&markers, &defaultfn, &encoder, &indent,
&key_separator, &item_separator,
&sort_keys, &skipkeys, &allow_nan))
return -1;
return NULL;

if (markers != Py_None && !PyDict_Check(markers)) {
PyErr_Format(PyExc_TypeError,
"make_encoder() argument 1 must be dict or None, "
"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->defaultfn = defaultfn;
s->encoder = encoder;
Expand All @@ -1380,7 +1336,7 @@ encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
Py_INCREF(s->item_separator);
Py_INCREF(s->sort_keys);
Py_INCREF(s->skipkeys);
return 0;
return (PyObject *)s;
}

static PyObject *
Expand Down Expand Up @@ -1911,7 +1867,7 @@ PyTypeObject PyEncoderType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
encoder_init, /* tp_init */
0, /* tp_init */
0, /* tp_alloc */
encoder_new, /* tp_new */
0, /* tp_free */
Expand Down Expand Up @@ -1954,10 +1910,8 @@ PyInit__json(void)
PyObject *m = PyModule_Create(&jsonmodule);
if (!m)
return NULL;
PyScannerType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyScannerType) < 0)
goto fail;
PyEncoderType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyEncoderType) < 0)
goto fail;
Py_INCREF((PyObject*)&PyScannerType);
Expand Down

0 comments on commit 76a3e51

Please sign in to comment.