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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy