summaryrefslogtreecommitdiff
path: root/contrib/jsonb_plpython
diff options
context:
space:
mode:
authorTom Lane2019-04-06 21:54:29 +0000
committerTom Lane2019-04-06 21:54:29 +0000
commit9e360f0e8327bcf4b7c5ce957024fdff8f95f7de (patch)
tree711fd8b72f19017ee54e43ed8def208911441e1e /contrib/jsonb_plpython
parent46e3442c9ec858071d60a1c0fae2e9868aeaa0c8 (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.c108
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);
}