Skip to content

Commit cac32a9

Browse files
author
Nikita Glukhov
committed
Fix memory leaks in jsonb_toaster methods using cached temporary context
1 parent cdceadf commit cac32a9

File tree

1 file changed

+116
-15
lines changed

1 file changed

+116
-15
lines changed

contrib/jsonb_toaster/jsonb_toaster.c

Lines changed: 116 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3652,6 +3652,103 @@ jsonb_toaster_default_toast(Relation rel, Oid toasterid, char cmethod,
36523652
NULL, options, NULL, NULL, false);
36533653
}
36543654

3655+
/* #define JSONB_TOASTER_TRACK_NESTING 1 FIXME this needs PG_TRY/PG_CATCH */
3656+
3657+
#ifdef JSONB_TOASTER_TRACK_NESTING
3658+
static int jsonb_toaster_nesting_level;
3659+
#endif
3660+
3661+
static MemoryContext jsonb_toaster_parent_cxt;
3662+
static MemoryContext jsonb_toaster_temp_cxt;
3663+
3664+
static void
3665+
jsonb_toaster_temp_context_reset_callback(void *arg)
3666+
{
3667+
if (jsonb_toaster_temp_cxt == arg)
3668+
jsonb_toaster_temp_cxt = NULL;
3669+
}
3670+
3671+
static void
3672+
jsonb_toaster_register_temp_context_callback(MemoryContext temp_cxt)
3673+
{
3674+
MemoryContextCallback *cb;
3675+
3676+
cb = MemoryContextAlloc(temp_cxt, sizeof(*cb));
3677+
cb->func = jsonb_toaster_temp_context_reset_callback;
3678+
cb->arg = temp_cxt;
3679+
3680+
MemoryContextRegisterResetCallback(temp_cxt, cb);
3681+
}
3682+
3683+
static void
3684+
jsonb_toaster_init_temp_context()
3685+
{
3686+
#ifdef JSONB_TOASTER_TRACK_NESTING
3687+
if (jsonb_toaster_nesting_level++ > 0)
3688+
return;
3689+
#endif
3690+
3691+
if (!jsonb_toaster_temp_cxt ||
3692+
jsonb_toaster_parent_cxt != CurrentMemoryContext)
3693+
{
3694+
MemoryContext temp_cxt;
3695+
3696+
if (jsonb_toaster_temp_cxt)
3697+
{
3698+
temp_cxt = jsonb_toaster_temp_cxt;
3699+
jsonb_toaster_temp_cxt = NULL;
3700+
MemoryContextDelete(temp_cxt);
3701+
}
3702+
3703+
temp_cxt = AllocSetContextCreate(CurrentMemoryContext,
3704+
"jsonb_toaster temp context",
3705+
ALLOCSET_DEFAULT_SIZES);
3706+
3707+
jsonb_toaster_register_temp_context_callback(temp_cxt);
3708+
3709+
jsonb_toaster_parent_cxt = CurrentMemoryContext;
3710+
jsonb_toaster_temp_cxt = temp_cxt;
3711+
}
3712+
3713+
MemoryContextSwitchTo(jsonb_toaster_temp_cxt);
3714+
3715+
jsonbInitIterators();
3716+
}
3717+
3718+
static Datum
3719+
jsonb_toaster_free_temp_context(Datum result)
3720+
{
3721+
MemoryContext temp_cxt;
3722+
3723+
#ifdef JSONB_TOASTER_TRACK_NESTING
3724+
if (jsonb_toaster_nesting_level-- > 1)
3725+
return;
3726+
#endif
3727+
3728+
Assert(CurrentMemoryContext == jsonb_toaster_temp_cxt);
3729+
3730+
jsonbFreeIterators();
3731+
3732+
MemoryContextSwitchTo(jsonb_toaster_parent_cxt);
3733+
3734+
/* Copy result from from temporary context, if any */
3735+
if (result)
3736+
{
3737+
int size = VARSIZE_ANY(result);
3738+
3739+
result = PointerGetDatum(memcpy(palloc(size), DatumGetPointer(result), size));
3740+
}
3741+
3742+
temp_cxt = jsonb_toaster_temp_cxt;
3743+
MemoryContextReset(temp_cxt);
3744+
3745+
/* Restore jsonb_toaster_temp_cxt after reset callback execution */
3746+
jsonb_toaster_temp_cxt = temp_cxt;
3747+
jsonb_toaster_register_temp_context_callback(temp_cxt);
3748+
3749+
return result;
3750+
}
3751+
36553752
static Datum
36563753
jsonb_toaster_toast(Relation rel, Oid toasterid,
36573754
Datum new_val, Datum old_val,
@@ -3661,7 +3758,7 @@ jsonb_toaster_toast(Relation rel, Oid toasterid,
36613758
Datum res;
36623759
char cmethod = TOAST_PGLZ_COMPRESSION;
36633760

3664-
jsonbInitIterators();
3761+
jsonb_toaster_init_temp_context();
36653762

36663763
new_js = DatumGetJsonbPC(new_val, NULL /* FIXME alloca */, false);
36673764

@@ -3674,9 +3771,13 @@ jsonb_toaster_toast(Relation rel, Oid toasterid,
36743771
new_val, new_js,
36753772
max_inline_size, options);
36763773

3677-
res = res == (Datum) 0 ? new_val : res;
3678-
3679-
jsonbFreeIterators();
3774+
if (res == (Datum) 0 || res == new_val)
3775+
{
3776+
res = new_val;
3777+
jsonb_toaster_free_temp_context(0);
3778+
}
3779+
else
3780+
res = jsonb_toaster_free_temp_context(res);
36803781

36813782
return res;
36823783
}
@@ -3691,13 +3792,13 @@ jsonb_toaster_update_toast(Relation rel, Oid toasterid,
36913792
Datum res;
36923793
char cmethod = TOAST_PGLZ_COMPRESSION;
36933794

3694-
jsonbInitIterators();
3795+
jsonb_toaster_init_temp_context();
36953796

36963797
new_js = DatumGetJsonbPC(new_val, NULL, false);
36973798
old_js = DatumGetJsonbPC(old_val, NULL, false);
36983799
res = jsonb_toaster_cmp(rel, toasterid, JsonRoot(new_js), JsonRoot(old_js), cmethod);
36993800

3700-
jsonbFreeIterators();
3801+
res = jsonb_toaster_free_temp_context(res);
37013802

37023803
return res;
37033804
}
@@ -3710,12 +3811,12 @@ jsonb_toaster_copy_toast(Relation rel, Oid toasterid,
37103811
Datum res;
37113812
char cmethod = TOAST_PGLZ_COMPRESSION;
37123813

3713-
jsonbInitIterators();
3814+
jsonb_toaster_init_temp_context();
37143815

37153816
new_js = DatumGetJsonbPC(new_val, NULL, false);
37163817
res = jsonb_toaster_copy(rel, toasterid, JsonRoot(new_js), cmethod, true);
37173818

3718-
jsonbFreeIterators();
3819+
res = jsonb_toaster_free_temp_context(res);
37193820

37203821
return res;
37213822
}
@@ -3725,12 +3826,12 @@ jsonb_toaster_delete_toast(Datum val, bool is_speculative)
37253826
{
37263827
Json *js;
37273828

3728-
jsonbInitIterators();
3829+
jsonb_toaster_init_temp_context();
37293830

37303831
js = DatumGetJsonbPC(val, NULL, false);
37313832
jsonb_toaster_delete_recursive(NULL /* XXX rel */, JsonRoot(js), false, is_speculative);
37323833

3733-
jsonbFreeIterators();
3834+
jsonb_toaster_free_temp_context(0);
37343835
}
37353836

37363837
static Datum
@@ -3742,10 +3843,11 @@ jsonb_toaster_detoast(Datum toastptr, int sliceoffset, int slicelength)
37423843
JsonValue bin;
37433844
void *detoasted;
37443845
int len;
3846+
MemoryContext mcxt = CurrentMemoryContext;
37453847

37463848
Assert(VARATT_IS_CUSTOM(toastptr));
37473849

3748-
jsonbInitIterators();
3850+
jsonb_toaster_init_temp_context();
37493851

37503852
//js = DatumGetJson(toastptr, &jsonxContainerOps, &jsbuf);
37513853
js = JsonExpand(NULL /* FIXME &jsbuf */, toastptr, false, &jsonxContainerOps);
@@ -3755,10 +3857,8 @@ jsonb_toaster_detoast(Datum toastptr, int sliceoffset, int slicelength)
37553857
detoasted = JsonEncode(&bin, JsonbEncode, NULL);
37563858
len = VARSIZE_ANY_EXHDR(detoasted);
37573859

3758-
jsonbFreeIterators();
3759-
37603860
if (sliceoffset == 0 && (slicelength < 0 || slicelength >= len))
3761-
return PointerGetDatum(detoasted);
3861+
return jsonb_toaster_free_temp_context(PointerGetDatum(detoasted));
37623862

37633863
if (sliceoffset < 0)
37643864
sliceoffset = 0;
@@ -3768,11 +3868,12 @@ jsonb_toaster_detoast(Datum toastptr, int sliceoffset, int slicelength)
37683868
if (slicelength < 0 || sliceoffset + slicelength > len)
37693869
slicelength = len - sliceoffset;
37703870

3771-
result = palloc(VARHDRSZ + slicelength);
3871+
result = MemoryContextAlloc(mcxt, VARHDRSZ + slicelength);
37723872
SET_VARSIZE(result, VARHDRSZ + slicelength);
37733873
memcpy(VARDATA(result), (char *) VARDATA_ANY(detoasted) + sliceoffset, slicelength);
37743874

37753875
pfree(detoasted);
3876+
jsonb_toaster_free_temp_context(0);
37763877

37773878
return PointerGetDatum(result);
37783879
}

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