commit 409c6d4006fdea27e746ea397124f98c92a41a92 Author: Joakim Hamren Date: Sat Feb 4 04:21:05 2017 +0100 Fix for overflowing long causing invalid json This was caused by checking for "__json__" using PyObject_HasAttrString which clears the error set by a previous long overflow. Thus this was dependent on the order of processing of dict items, which explains why it was seemingly random as the dict items are likely ordered by a hash of the key. This fixes GH224 and GH240. diff --git a/python/objToJSON.c b/python/objToJSON.c index 8133fb5..adea2f6 100644 --- a/python/objToJSON.c +++ b/python/objToJSON.c @@ -226,6 +226,21 @@ static void *PyDateToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size return NULL; } +static int PyHasAttrStringPreserveErr(PyObject *obj, const char *attr) +{ + int res; + PyObject *excType = NULL, *excValue, *excTraceback; + + if (!PyErr_Occurred()) + return PyObject_HasAttrString(obj, "__json__"); + + PyErr_Fetch(&excType, &excValue, &excTraceback); + res = PyObject_HasAttrString(obj, "__json__"); + PyErr_Restore(excType, excValue, excTraceback); + + return res; +} + static int Tuple_iterNext(JSOBJ obj, JSONTypeContext *tc) { PyObject *item; @@ -471,21 +486,21 @@ static int Dict_iterNext(JSOBJ obj, JSONTypeContext *tc) GET_TC(tc)->itemName = PyUnicode_AsUTF8String (GET_TC(tc)->itemName); } else - if (!PyString_Check(GET_TC(tc)->itemName)) - { - GET_TC(tc)->itemName = PyObject_Str(GET_TC(tc)->itemName); + if (!PyString_Check(GET_TC(tc)->itemName)) + { + GET_TC(tc)->itemName = PyObject_Str(GET_TC(tc)->itemName); #if PY_MAJOR_VERSION >= 3 - itemNameTmp = GET_TC(tc)->itemName; - GET_TC(tc)->itemName = PyUnicode_AsUTF8String (GET_TC(tc)->itemName); - Py_DECREF(itemNameTmp); + itemNameTmp = GET_TC(tc)->itemName; + GET_TC(tc)->itemName = PyUnicode_AsUTF8String (GET_TC(tc)->itemName); + Py_DECREF(itemNameTmp); #endif - } - else - { - Py_INCREF(GET_TC(tc)->itemName); - } - PRINTMARK(); - return 1; + } + else + { + Py_INCREF(GET_TC(tc)->itemName); + } + PRINTMARK(); + return 1; } static void Dict_iterEnd(JSOBJ obj, JSONTypeContext *tc) @@ -728,7 +743,7 @@ static void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObject return; } else - if (PyString_Check(obj) && !PyObject_HasAttrString(obj, "__json__")) + if (PyString_Check(obj) && !PyHasAttrStringPreserveErr(obj, "__json__")) { PRINTMARK(); pc->PyTypeToJSON = PyStringToUTF8; tc->type = JT_UTF8;