Skip to content

Commit 8a14566

Browse files
author
Nikita Glukhov
committed
Fix memleaks and error handling jsonb_plpython
1 parent 4b7d637 commit 8a14566

File tree

1 file changed

+100
-46
lines changed

1 file changed

+100
-46
lines changed

contrib/jsonb_plpython/jsonb_plpython.c

Lines changed: 100 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -169,53 +169,80 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
169169
if (!result)
170170
return NULL;
171171

172-
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
172+
PG_TRY();
173173
{
174-
if (r == WJB_ELEM)
174+
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
175175
{
176-
PyObject *elem = PLyObject_FromJsonbValue(&v);
176+
if (r == WJB_ELEM)
177+
{
178+
PyObject *elem = PLyObject_FromJsonbValue(&v);
179+
180+
if (!elem || PyList_Append(result, elem))
181+
{
182+
Py_XDECREF(elem);
183+
Py_DECREF(result);
184+
return NULL;
185+
}
177186

178-
PyList_Append(result, elem);
179-
Py_XDECREF(elem);
187+
Py_DECREF(elem);
188+
}
180189
}
181190
}
191+
PG_CATCH();
192+
{
193+
Py_DECREF(result);
194+
PG_RE_THROW();
195+
}
196+
PG_END_TRY();
182197
}
183198
break;
184199

185200
case WJB_BEGIN_OBJECT:
186-
result = PyDict_New();
187-
if (!result)
188-
return NULL;
189-
190-
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
191201
{
192-
if (r == WJB_KEY)
193-
{
194-
PyObject *key = PLyString_FromJsonbValue(&v);
195-
196-
if (!key)
197-
return NULL;
202+
PyObject *volatile key = NULL;
198203

199-
r = JsonbIteratorNext(&it, &v, true);
204+
result = PyDict_New();
205+
if (!result)
206+
return NULL;
200207

201-
if (r == WJB_VALUE)
208+
PG_TRY();
209+
{
210+
while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
202211
{
203-
PyObject *value = PLyObject_FromJsonbValue(&v);
212+
JsonbValue v2;
213+
PyObject *val = NULL;
214+
215+
if (r != WJB_KEY)
216+
continue;
217+
218+
if ((r = JsonbIteratorNext(&it, &v2, true)) != WJB_VALUE)
219+
elog(ERROR, "unexpected jsonb token: %d", r);
204220

205-
if (!value)
221+
if (!(key = PLyString_FromJsonbValue(&v)) ||
222+
!(val = PLyObject_FromJsonbValue(&v2)) ||
223+
PyDict_SetItem(result, key, val))
206224
{
207225
Py_XDECREF(key);
226+
Py_XDECREF(val);
227+
Py_DECREF(result);
208228
return NULL;
209229
}
210230

211-
PyDict_SetItem(result, key, value);
212-
Py_XDECREF(value);
231+
Py_DECREF(val);
232+
Py_DECREF(key);
233+
key = NULL;
213234
}
214-
235+
}
236+
PG_CATCH();
237+
{
215238
Py_XDECREF(key);
239+
Py_DECREF(result);
240+
PG_RE_THROW();
216241
}
242+
PG_END_TRY();
243+
244+
break;
217245
}
218-
break;
219246

220247
default:
221248
elog(ERROR, "unexpected jsonb token: %d", r);
@@ -233,30 +260,40 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
233260
static JsonbValue *
234261
PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
235262
{
236-
Py_ssize_t pcount;
237-
JsonbValue *out = NULL;
263+
JsonbValue *out;
264+
PyObject *items;
265+
Py_ssize_t pcount = PyMapping_Size(obj);
266+
267+
if (pcount < 0)
268+
PLy_elog(ERROR, "PyMapping_Size() failed, while converting mapping into jsonb");
238269

239-
/* We need it volatile, since we use it after longjmp */
240-
volatile PyObject *items_v = NULL;
270+
items = PyMapping_Items(obj);
241271

242-
pcount = PyMapping_Size(obj);
243-
items_v = PyMapping_Items(obj);
272+
if (!items)
273+
PLy_elog(ERROR, "PyMapping_Items() failed, while converting mapping into jsonb");
244274

245275
PG_TRY();
246276
{
247277
Py_ssize_t i;
248-
PyObject *items;
249-
250-
items = (PyObject *) items_v;
251278

252279
pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
253280

254281
for (i = 0; i < pcount; i++)
255282
{
256283
JsonbValue jbvKey;
257-
PyObject *item = PyList_GetItem(items, i);
258-
PyObject *key = PyTuple_GetItem(item, 0);
259-
PyObject *value = PyTuple_GetItem(item, 1);
284+
PyObject *item;
285+
PyObject *key;
286+
PyObject *value;
287+
288+
item = PyList_GetItem(items, i); /* borrowed reference */
289+
if (!item)
290+
PLy_elog(ERROR, "PyList_GetItem() failed, while converting mapping into jsonb");
291+
292+
key = PyTuple_GetItem(item, 0); /* borrowed references */
293+
value = PyTuple_GetItem(item, 1);
294+
295+
if (!key || !value)
296+
PLy_elog(ERROR, "PyTuple_GetItem() failed, while converting mapping into jsonb");
260297

261298
/* Python dictionary can have None as key */
262299
if (key == Py_None)
@@ -279,11 +316,13 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
279316
}
280317
PG_CATCH();
281318
{
282-
Py_DECREF(items_v);
319+
Py_DECREF(items);
283320
PG_RE_THROW();
284321
}
285322
PG_END_TRY();
286323

324+
Py_DECREF(items);
325+
287326
return out;
288327
}
289328

@@ -296,21 +335,36 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
296335
static JsonbValue *
297336
PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
298337
{
299-
Py_ssize_t i;
300-
Py_ssize_t pcount;
338+
PyObject *seq = PySequence_Fast(obj, "object is not a sequence");
301339

302-
pcount = PySequence_Size(obj);
340+
if (!seq)
341+
PLy_elog(ERROR, "PySequence_Fast() failed, while converting sequence into jsonb");
303342

304-
pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
305-
306-
for (i = 0; i < pcount; i++)
343+
PG_TRY();
307344
{
308-
PyObject *value = PySequence_GetItem(obj, i);
345+
Py_ssize_t i;
346+
Py_ssize_t pcount = PySequence_Fast_GET_SIZE(seq);
309347

310-
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
348+
pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
311349

312-
Py_XDECREF(value);
350+
for (i = 0; i < pcount; i++)
351+
{
352+
PyObject *value = PySequence_Fast_GET_ITEM(seq, i); /* borrowed reference */
353+
354+
if (!value)
355+
PLy_elog(ERROR, "PySequence_Fast_GET_ITEM() failed, while converting sequence into jsonb");
356+
357+
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
358+
}
313359
}
360+
PG_CATCH();
361+
{
362+
Py_DECREF(seq);
363+
PG_RE_THROW();
364+
}
365+
PG_END_TRY();
366+
367+
Py_DECREF(seq);
314368

315369
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
316370
}

0 commit comments

Comments
 (0)