8000 Fix significant memory leak in contrib/xml2 functions. · justtesting112233/postgres@61f8618 · GitHub
[go: up one dir, main page]

Skip to content

Commit 61f8618

Browse files
committed
Fix significant memory leak in contrib/xml2 functions.
Most of the functions that execute XPath queries leaked the data structures created by libxml2. This memory would not be recovered until end of session, so it mounts up pretty quickly in any serious use of the feature. Per report from Pavel Stehule, though this isn't his patch. Back-patch to all supported branches.
1 parent ec66f65 commit 61f8618

File tree

1 file changed

+90
-72
lines changed

1 file changed

+90
-72
lines changed

contrib/xml2/xpath.c

Lines changed: 90 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
4040

4141
void pgxml_parser_init(void);
4242

43+
/* workspace for pgxml_xpath() */
44+
45+
typedef struct
46+
{
47+
xmlDocPtr doctree;
48+
xmlXPathContextPtr ctxt;
49+
xmlXPathObjectPtr res;
50+
} xpath_workspace;
51+
4352
/* local declarations */
4453

4554
static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
@@ -51,7 +60,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
5160

5261
static xmlChar *pgxml_texttoxmlchar(text *textstring);
5362

54-
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
63+
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
64+
xpath_workspace *workspace);
65+
66+
static void cleanup_workspace(xpath_workspace *workspace);
5567

5668

5769
/*
@@ -214,25 +226,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
214226
Datum
215227
xpath_nodeset(PG_FUNCTION_ARGS)
216228
{
217-
xmlChar *xpath,
218-
*toptag,
219-
*septag;
220-
int32 pathsize;
221-
text *xpathsupp,
222-
*xpres;
223-
224-
/* PG_GETARG_TEXT_P(0) is document buffer */
225-
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
229+
text *document = PG_GETARG_TEXT_P(0);
230+
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
231+
xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
232+
xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
233+
xmlChar *xpath;
234+
text *xpres;
235+
xmlXPathObjectPtr res;
236+
xpath_workspace workspace;
226237

227-
toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
228-
septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
238+
xpath = pgxml_texttoxmlchar(xpathsupp);
229239

230-
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
240+
res = pgxml_xpath(document, xpath, &workspace);
231241

232-
xpath = pgxml_texttoxmlchar(xpathsupp);
242+
xpres = pgxml_result_to_text(res, toptag, septag, NULL);
233243

234-
xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
235-
toptag, septag, NULL);
244+
cleanup_workspace(&workspace);
236245

237246
pfree(xpath);
238247

@@ -250,23 +259,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
250259
Datum
251260
xpath_list(PG_FUNCTION_ARGS)
252261
{
253-
xmlChar *xpath,
254-
*plainsep;
255-
int32 pathsize;
256-
text *xpathsupp,
257-
*xpres;
258-
259-
/* PG_GETARG_TEXT_P(0) is document buffer */
260-
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
262+
text *document = PG_GETARG_TEXT_P(0);
263+
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
264+
xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
265+
xmlChar *xpath;
266+
text *xpres;
267+
xmlXPathObjectPtr res;
268+
xpath_workspace workspace;
261269

262-
plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
270+
xpath = pgxml_texttoxmlchar(xpathsupp);
263271

264-
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
272+
res = pgxml_xpath(document, xpath, &workspace);
265273

266-
xpath = pgxml_texttoxmlchar(xpathsupp);
274+
xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
267275

268-
xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
269-
NULL, NULL, plainsep);
276+
cleanup_workspace(&workspace);
270277

271278
pfree(xpath);
272279

@@ -281,13 +288,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
281288
Datum
282289
xpath_string(PG_FUNCTION_ARGS)
283290
{
291+
text *document = PG_GETARG_TEXT_P(0);
292+
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
284293
xmlChar *xpath;
285294
int32 pathsize;
286-
text *xpathsupp,
287-
*xpres;
288-
289-
/* PG_GETARG_TEXT_P(0) is document buffer */
290-
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
295+
text *xpres;
296+
xmlXPathObjectPtr res;
297+
xpath_workspace workspace;
291298

292299
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
293300

@@ -298,13 +305,16 @@ xpath_string(PG_FUNCTION_ARGS)
298305
/* We could try casting to string using the libxml function? */
299306

300307
xpath = (xmlChar *) palloc(pathsize + 9);
301-
memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
302308
strncpy((char *) xpath, "string(", 7);
309+
memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
303310
xpath[pathsize + 7] = ')';
304311
xpath[pathsize + 8] = '\0';
305312

306-
xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
307-
NULL, NULL, NULL);
313+
res = pgxml_xpath(document, xpath, &workspace);
314+
315+
xpres = pgxml_result_to_text(res, NULL, NULL, NULL);
316+
317+
cleanup_workspace(&workspace);
308318

309319
pfree(xpath);
310320

@@ -319,28 +329,26 @@ PG_FUNCTION_INFO_V1(xpath_number);
319329
Datum
320330
xpath_number(PG_FUNCTION_ARGS)
321331
{
332+
text *document = PG_GETARG_TEXT_P(0);
333+
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
322334
xmlChar *xpath;
323-
int32 pathsize;
324-
text *xpathsupp;
325335
float4 fRes;
326-
327336
xmlXPathObjectPtr res;
328-
329-
/* PG_GETARG_TEXT_P(0) is document buffer */
330-
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
331-
332-
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
337+
xpath_workspace workspace;
333338

334339
xpath = pgxml_texttoxmlchar(xpathsupp);
335340

336-
res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
341+
res = pgxml_xpath(document, xpath, &workspace);
342+
337343
pfree(xpath);
338344

339345
if (res == NULL)
340346
PG_RETURN_NULL();
341347

342348
fRes = xmlXPathCastToNumber(res);
343349

350+
cleanup_workspace(&workspace);
351+
344352
if (xmlXPathIsNaN(fRes))
345353
PG_RETURN_NULL();
346354

@@ -353,28 +361,26 @@ PG_FUNCTION_INFO_V1(xpath_bool);
353361
Datum
354362
xpath_bool(PG_FUNCTION_ARGS)
355363
{
364+
text *document = PG_GETARG_TEXT_P(0);
365+
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
356366
xmlChar *xpath;
357-
int32 pathsize;
358-
text *xpathsupp;
359367
int bRes;
360-
361368
xmlXPathObjectPtr res;
362-
363-
/* PG_GETARG_TEXT_P(0) is document buffer */
364-
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
365-
366-
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
369+
xpath_workspace workspace;
367370

368371
xpath = pgxml_texttoxmlchar(xpathsupp);
369372

370-
res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
373+
res = pgxml_xpath(document, xpath, &workspace);
374+
371375
pfree(xpath);
372376

373377
if (res == NULL)
374378
PG_RETURN_BOOL(false);
375379

376380
bRes = xmlXPathCastToBoolean(res);
377381

382+
cleanup_workspace(&workspace);
383+
378384
PG_RETURN_BOOL(bRes);
379385
}
380386

@@ -383,49 +389,61 @@ xpath_bool(PG_FUNCTION_ARGS)
383389
/* Core function to evaluate XPath query */
384390

385391
static xmlXPathObjectPtr
386-
pgxml_xpath(text *document, xmlChar *xpath)
392+
pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
387393
{
388-
xmlDocPtr doctree;
389-
xmlXPathContextPtr ctxt;
394+
int32 docsize = VARSIZE(document) - VARHDRSZ;
390395
xmlXPathObjectPtr res;
391396
xmlXPathCompExprPtr comppath;
392-
int32 docsize;
393397

394-
docsize = VARSIZE(document) - VARHDRSZ;
398+
workspace->doctree = NULL;
399+
workspace->ctxt = NULL;
400+
workspace->res = NULL;
395401

396402
pgxml_parser_init();
397403

398-
doctree = xmlParseMemory((char *) VARDATA(document), docsize);
399-
if (doctree == NULL)
404+
workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize);
405+
if (workspace->doctree == NULL)
400406
return NULL; /* not well-formed */
401407

402-
ctxt = xmlXPathNewContext(doctree);
403-
ctxt->node = xmlDocGetRootElement(doctree);
408+
workspace->ctxt = xmlXPathNewContext(workspace->doctree);
409+
workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
404410

405411
/* compile the path */
406412
comppath = xmlXPathCompile(xpath);
407413
if (comppath == NULL)
408414
{
409-
xmlFreeDoc(doctree);
415+
cleanup_workspace(workspace);
410416
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
411417
"XPath Syntax Error");
412418
}
413419

414420
/* Now evaluate the path expression. */
415-
res = xmlXPathCompiledEval(comppath, ctxt);
421+
res = xmlXPathCompiledEval(comppath, workspace->ctxt);
422+
workspace->res = res;
423+
416424
xmlXPathFreeCompExpr(comppath);
417425

418426
if (res == NULL)
419-
{
420-
xmlXPathFreeContext(ctxt);
421-
xmlFreeDoc(doctree);
427+
cleanup_workspace(workspace);
422428

423-
return NULL;
424-
}
425-
/* xmlFreeDoc(doctree); */
426429
return res;
427430
}
428431

432+
/* Clean up after processing the result of pgxml_xpath() */
433+
static void
434+
cleanup_workspace(xpath_workspace *workspace)
435+
{
436+
if (workspace->res)
437+
xmlXPathFreeObject(workspace->res);
438+
workspace->res = NULL;
439+
if (workspace->ctxt)
440+
xmlXPathFreeContext(workspace->ctxt);
441+
workspace->ctxt = NULL;
442+
if (workspace->doctree)
443+
xmlFreeDoc(workspace->doctree);
444+
workspace->doctree = NULL;
445+
}
446+
429447
static text *
430448
pgxml_result_to_text(xmlXPathObjectPtr res,
431449
xmlChar *toptag,

0 commit comments

Comments
 (0)
0