mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
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/28053a7d-10d8-fc23-b05c-b4749c873f63@postgrespro.ru
This commit is contained in:
parent
46e3442c9e
commit
9e360f0e83
@ -128,9 +128,9 @@ Datum
|
|||||||
plpython_to_hstore(PG_FUNCTION_ARGS)
|
plpython_to_hstore(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
PyObject *volatile items = NULL;
|
PyObject *volatile items;
|
||||||
int32 pcount;
|
Py_ssize_t pcount;
|
||||||
HStore *out;
|
HStore *volatile out;
|
||||||
|
|
||||||
dict = (PyObject *) PG_GETARG_POINTER(0);
|
dict = (PyObject *) PG_GETARG_POINTER(0);
|
||||||
if (!PyMapping_Check(dict))
|
if (!PyMapping_Check(dict))
|
||||||
@ -144,7 +144,7 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
|
|||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
int32 buflen;
|
int32 buflen;
|
||||||
int32 i;
|
Py_ssize_t i;
|
||||||
Pairs *pairs;
|
Pairs *pairs;
|
||||||
|
|
||||||
pairs = palloc(pcount * sizeof(*pairs));
|
pairs = palloc(pcount * sizeof(*pairs));
|
||||||
@ -176,7 +176,6 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
|
|||||||
pairs[i].isnull = false;
|
pairs[i].isnull = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(items);
|
|
||||||
|
|
||||||
pcount = hstoreUniquePairs(pairs, pcount, &buflen);
|
pcount = hstoreUniquePairs(pairs, pcount, &buflen);
|
||||||
out = hstorePairs(pairs, pcount, buflen);
|
out = hstorePairs(pairs, pcount, buflen);
|
||||||
@ -188,5 +187,7 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
|
||||||
|
Py_DECREF(items);
|
||||||
|
|
||||||
PG_RETURN_POINTER(out);
|
PG_RETURN_POINTER(out);
|
||||||
}
|
}
|
||||||
|
@ -164,56 +164,91 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* array in v */
|
PyObject *volatile elem = NULL;
|
||||||
|
|
||||||
result = PyList_New(0);
|
result = PyList_New(0);
|
||||||
if (!result)
|
if (!result)
|
||||||
return NULL;
|
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);
|
PyList_Append(result, elem);
|
||||||
Py_XDECREF(elem);
|
Py_XDECREF(elem);
|
||||||
|
elem = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
Py_XDECREF(elem);
|
||||||
|
Py_XDECREF(result);
|
||||||
|
PG_RE_THROW();
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WJB_BEGIN_OBJECT:
|
case WJB_BEGIN_OBJECT:
|
||||||
result = PyDict_New();
|
|
||||||
if (!result)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
|
|
||||||
{
|
{
|
||||||
if (r == WJB_KEY)
|
PyObject *volatile result_v = PyDict_New();
|
||||||
|
PyObject *volatile key = NULL;
|
||||||
|
PyObject *volatile val = NULL;
|
||||||
|
|
||||||
|
if (!result_v)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PG_TRY();
|
||||||
{
|
{
|
||||||
PyObject *key = PLyString_FromJsonbValue(&v);
|
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
|
||||||
|
|
||||||
if (!key)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
r = JsonbIteratorNext(&it, &v, true);
|
|
||||||
|
|
||||||
if (r == WJB_VALUE)
|
|
||||||
{
|
{
|
||||||
PyObject *value = PLyObject_FromJsonbValue(&v);
|
if (r != WJB_KEY)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!value)
|
key = PLyString_FromJsonbValue(&v);
|
||||||
|
if (!key)
|
||||||
{
|
{
|
||||||
Py_XDECREF(key);
|
Py_XDECREF(result_v);
|
||||||
return NULL;
|
result_v = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDict_SetItem(result, key, value);
|
if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_VALUE)
|
||||||
Py_XDECREF(value);
|
elog(ERROR, "unexpected jsonb token: %d", r);
|
||||||
}
|
|
||||||
|
|
||||||
Py_XDECREF(key);
|
val = PLyObject_FromJsonbValue(&v);
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
Py_XDECREF(key);
|
||||||
|
key = NULL;
|
||||||
|
Py_XDECREF(result_v);
|
||||||
|
result_v = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
@ -234,10 +269,8 @@ static JsonbValue *
|
|||||||
PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||||
{
|
{
|
||||||
Py_ssize_t pcount;
|
Py_ssize_t pcount;
|
||||||
JsonbValue *out = NULL;
|
PyObject *volatile items;
|
||||||
|
JsonbValue *volatile out;
|
||||||
/* We need it volatile, since we use it after longjmp */
|
|
||||||
PyObject *volatile items = NULL;
|
|
||||||
|
|
||||||
pcount = PyMapping_Size(obj);
|
pcount = PyMapping_Size(obj);
|
||||||
items = PyMapping_Items(obj);
|
items = PyMapping_Items(obj);
|
||||||
@ -281,6 +314,8 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
|||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
|
||||||
|
Py_DECREF(items);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,19 +330,30 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
|||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
Py_ssize_t pcount;
|
Py_ssize_t pcount;
|
||||||
|
PyObject *volatile value = NULL;
|
||||||
|
|
||||||
pcount = PySequence_Size(obj);
|
pcount = PySequence_Size(obj);
|
||||||
|
|
||||||
pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
|
pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
|
||||||
|
|
||||||
for (i = 0; i < pcount; i++)
|
PG_TRY();
|
||||||
{
|
{
|
||||||
PyObject *value = PySequence_GetItem(obj, i);
|
for (i = 0; i < pcount; i++)
|
||||||
|
{
|
||||||
|
value = PySequence_GetItem(obj, i);
|
||||||
|
Assert(value);
|
||||||
|
|
||||||
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
|
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
|
||||||
|
Py_XDECREF(value);
|
||||||
Py_XDECREF(value);
|
value = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
Py_XDECREF(value);
|
||||||
|
PG_RE_THROW();
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
|
|
||||||
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user