Skip to content

Commit

Permalink
Fix segmentation faults when handling unserialisable objects
Browse files Browse the repository at this point in the history
Errors during `__repr__` itself as well as ones during the conversion to a bytes object were not handled, resulting in NULL pointer dereferencing.

Cf. #382
  • Loading branch information
JustAnotherArchivist authored and bwoodsend committed Apr 18, 2022
1 parent 7799498 commit b3f8754
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 5 deletions.
11 changes: 9 additions & 2 deletions python/objToJSON.c
Expand Up @@ -670,8 +670,15 @@ static void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObject
PyErr_Clear();

objRepr = PyObject_Repr(obj);
PyObject* str = PyUnicode_AsEncodedString(objRepr, "utf-8", "~E~");
PyErr_Format (PyExc_TypeError, "%s is not JSON serializable", PyBytes_AsString(str));
if (!objRepr)
{
goto INVALID;
}
PyObject* str = PyUnicode_AsEncodedString(objRepr, "utf-8", "strict");
if (str)
{
PyErr_Format (PyExc_TypeError, "%s is not JSON serializable", PyBytes_AsString(str));
}
Py_XDECREF(str);
Py_DECREF(objRepr);

Expand Down
15 changes: 12 additions & 3 deletions tests/test_ujson.py
Expand Up @@ -636,22 +636,31 @@ def test_dumps(test_input, expected):


class SomeObject:
def __init__(self, message, exception=None):
self._message = message
self._exception = exception

def __repr__(self):
return "Some Object"
if self._exception:
raise self._exception
return self._message


@pytest.mark.parametrize(
"test_input, expected_exception, expected_message",
[
(set(), TypeError, "set() is not JSON serializable"),
({1, 2, 3}, TypeError, "{1, 2, 3} is not JSON serializable"),
(SomeObject(), TypeError, "Some Object is not JSON serializable"),
(SomeObject("Some Object"), TypeError, "Some Object is not JSON serializable"),
(SomeObject("\ud800"), UnicodeEncodeError, None),
(SomeObject(None, KeyboardInterrupt), KeyboardInterrupt, None),
],
)
def test_dumps_raises(test_input, expected_exception, expected_message):
with pytest.raises(expected_exception) as e:
ujson.dumps(test_input)
assert str(e.value) == expected_message
if expected_message:
assert str(e.value) == expected_message


@pytest.mark.parametrize(
Expand Down

0 comments on commit b3f8754

Please sign in to comment.