diff options
author | Tom Lane | 2019-04-06 21:54:29 +0000 |
---|---|---|
committer | Tom Lane | 2019-04-06 21:54:29 +0000 |
commit | 9e360f0e8327bcf4b7c5ce957024fdff8f95f7de (patch) | |
tree | 711fd8b72f19017ee54e43ed8def208911441e1e /contrib/jsonb_plpython | |
parent | 46e3442c9ec858071d60a1c0fae2e9868aeaa0c8 (diff) |
Avoid Python memory leaks in hstore_plpython and jsonb_plpython.
Fix some places where we might fail to do Py_DECREF() on a Python
object (thereby leaking it for the rest of the session). Almost
all of the risks were in error-recovery paths, which we don't really
expect to hit anyway. Hence, while this is definitely a bug fix,
it doesn't quite seem worth back-patching.
Nikita Glukhov, Michael Paquier, Tom Lane
Discussion: https://postgr.es/m/[email protected]
Diffstat (limited to 'contrib/jsonb_plpython')
-rw-r--r-- | contrib/jsonb_plpython/jsonb_plpython.c | 108 |
1 files changed, 77 insertions, 31 deletions
diff --git a/contrib/jsonb_plpython/jsonb_plpython.c b/contrib/jsonb_plpython/jsonb_plpython.c index 1bc984d5c4d..24e7c6559d6 100644 --- a/contrib/jsonb_plpython/jsonb_plpython.c +++ b/contrib/jsonb_plpython/jsonb_plpython.c @@ -164,56 +164,91 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb) } else { - /* array in v */ + PyObject *volatile elem = NULL; + result = PyList_New(0); if (!result) return NULL; - while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) + PG_TRY(); { - if (r == WJB_ELEM) + while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { - PyObject *elem = PLyObject_FromJsonbValue(&v); + if (r != WJB_ELEM) + continue; + + elem = PLyObject_FromJsonbValue(&v); PyList_Append(result, elem); Py_XDECREF(elem); + elem = NULL; } } + PG_CATCH(); + { + Py_XDECREF(elem); + Py_XDECREF(result); + PG_RE_THROW(); + } + PG_END_TRY(); } break; case WJB_BEGIN_OBJECT: - result = PyDict_New(); - if (!result) - return NULL; - - while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { - if (r == WJB_KEY) - { - PyObject *key = PLyString_FromJsonbValue(&v); + PyObject *volatile result_v = PyDict_New(); + PyObject *volatile key = NULL; + PyObject *volatile val = NULL; - if (!key) - return NULL; - - r = JsonbIteratorNext(&it, &v, true); + if (!result_v) + return NULL; - if (r == WJB_VALUE) + PG_TRY(); + { + while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { - PyObject *value = PLyObject_FromJsonbValue(&v); + if (r != WJB_KEY) + continue; - if (!value) + key = PLyString_FromJsonbValue(&v); + if (!key) + { + Py_XDECREF(result_v); + result_v = NULL; + break; + } + + if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_VALUE) + elog(ERROR, "unexpected jsonb token: %d", r); + + val = PLyObject_FromJsonbValue(&v); + if (!val) { Py_XDECREF(key); - return NULL; + key = NULL; + Py_XDECREF(result_v); + result_v = NULL; + break; } - PyDict_SetItem(result, key, value); - Py_XDECREF(value); - } + PyDict_SetItem(result_v, key, val); + Py_XDECREF(key); + key = NULL; + Py_XDECREF(val); + val = NULL; + } + } + PG_CATCH(); + { + Py_XDECREF(result_v); Py_XDECREF(key); + Py_XDECREF(val); + PG_RE_THROW(); } + PG_END_TRY(); + + result = result_v; } break; @@ -234,10 +269,8 @@ static JsonbValue * PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state) { Py_ssize_t pcount; - JsonbValue *out = NULL; - - /* We need it volatile, since we use it after longjmp */ - PyObject *volatile items = NULL; + PyObject *volatile items; + JsonbValue *volatile out; pcount = PyMapping_Size(obj); items = PyMapping_Items(obj); @@ -281,6 +314,8 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state) } PG_END_TRY(); + Py_DECREF(items); + return out; } @@ -295,19 +330,30 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state) { Py_ssize_t i; Py_ssize_t pcount; + PyObject *volatile value = NULL; pcount = PySequence_Size(obj); pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL); - for (i = 0; i < pcount; i++) + PG_TRY(); { - PyObject *value = PySequence_GetItem(obj, i); - - (void) PLyObject_ToJsonbValue(value, jsonb_state, true); + for (i = 0; i < pcount; i++) + { + value = PySequence_GetItem(obj, i); + Assert(value); + (void) PLyObject_ToJsonbValue(value, jsonb_state, true); + Py_XDECREF(value); + value = NULL; + } + } + PG_CATCH(); + { Py_XDECREF(value); + PG_RE_THROW(); } + PG_END_TRY(); return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL); } |