Skip to content

Commit 1c99cde

Browse files
committed
Improve JsonLexContext's freeability
Previously, the JSON code didn't have to worry too much about freeing JsonLexContext, because it was never too long-lived. With new features being added for SQL/JSON this is no longer the case. Add a routine that knows how to free this struct and apply that to a few places, to prevent this from becoming problematic. At the same time, we change the API of makeJsonLexContextCstringLen to make it receive a pointer to JsonLexContext for callers that want it to be stack-allocated; it can also be passed as NULL to get the original behavior of a palloc'ed one. This also causes an ABI break due to the addition of flags to JsonLexContext, so we can't easily backpatch it. AFAICS that's not much of a problem; apparently some leaks might exist in JSON usage of text-search, for example via json_to_tsvector, but I haven't seen any complaints about that. Per Coverity complaint about datum_to_jsonb_internal(). Discussion: https://postgr.es/m/20230808174110.oq3iymllsv6amkih@alvherre.pgsql
1 parent a8a968a commit 1c99cde

File tree

7 files changed

+153
-86
lines changed

7 files changed

+153
-86
lines changed

src/backend/utils/adt/json.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ json_in(PG_FUNCTION_ARGS)
106106
{
107107
char *json = PG_GETARG_CSTRING(0);
108108
text *result = cstring_to_text(json);
109-
JsonLexContext *lex;
109+
JsonLexContext lex;
110110

111111
/* validate it */
112-
lex = makeJsonLexContext(result, false);
113-
if (!pg_parse_json_or_errsave(lex, &nullSemAction, fcinfo->context))
112+
makeJsonLexContext(&lex, result, false);
113+
if (!pg_parse_json_or_errsave(&lex, &nullSemAction, fcinfo->context))
114114
PG_RETURN_NULL();
115115

116116
/* Internal representation is the same as text */
@@ -152,13 +152,14 @@ json_recv(PG_FUNCTION_ARGS)
152152
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
153153
char *str;
154154
int nbytes;
155-
JsonLexContext *lex;
155+
JsonLexContext lex;
156156

157157
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
158158

159159
/* Validate it. */
160-
lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false);
161-
pg_parse_json_or_ereport(lex, &nullSemAction);
160+
makeJsonLexContextCstringLen(&lex, str, nbytes, GetDatabaseEncoding(),
161+
false);
162+
pg_parse_json_or_ereport(&lex, &nullSemAction);
162163

163164
PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
164165
}
@@ -1625,14 +1626,16 @@ json_unique_object_field_start(void *_state, char *field, bool isnull)
16251626
bool
16261627
json_validate(text *json, bool check_unique_keys, bool throw_error)
16271628
{
1628-
JsonLexContext *lex = makeJsonLexContext(json, check_unique_keys);
1629+
JsonLexContext lex;
16291630
JsonSemAction uniqueSemAction = {0};
16301631
JsonUniqueParsingState state;
16311632
JsonParseErrorType result;
16321633

1634+
makeJsonLexContext(&lex, json, check_unique_keys);
1635+
16331636
if (check_unique_keys)
16341637
{
1635-
state.lex = lex;
1638+
state.lex = &lex;
16361639
state.stack = NULL;
16371640
state.id_counter = 0;
16381641
state.unique = true;
@@ -1644,12 +1647,12 @@ json_validate(text *json, bool check_unique_keys, bool throw_error)
16441647
uniqueSemAction.object_end = json_unique_object_end;
16451648
}
16461649

1647-
result = pg_parse_json(lex, check_unique_keys ? &uniqueSemAction : &nullSemAction);
1650+
result = pg_parse_json(&lex, check_unique_keys ? &uniqueSemAction : &nullSemAction);
16481651

16491652
if (result != JSON_SUCCESS)
16501653
{
16511654
if (throw_error)
1652-
json_errsave_error(result, lex, NULL);
1655+
json_errsave_error(result, &lex, NULL);
16531656

16541657
return false; /* invalid json */
16551658
}
@@ -1664,6 +1667,9 @@ json_validate(text *json, bool check_unique_keys, bool throw_error)
16641667
return false; /* not unique keys */
16651668
}
16661669

1670+
if (check_unique_keys)
1671+
freeJsonLexContext(&lex);
1672+
16671673
return true; /* ok */
16681674
}
16691675

@@ -1683,18 +1689,17 @@ Datum
16831689
json_typeof(PG_FUNCTION_ARGS)
16841690
{
16851691
text *json = PG_GETARG_TEXT_PP(0);
1686-
JsonLexContext *lex = makeJsonLexContext(json, false);
1692+
JsonLexContext lex;
16871693
char *type;
1688-
JsonTokenType tok;
16891694
JsonParseErrorType result;
16901695

16911696
/* Lex exactly one token from the input and check its type. */
1692-
result = json_lex(lex);
1697+
makeJsonLexContext(&lex, json, false);
1698+
result = json_lex(&lex);
16931699
if (result != JSON_SUCCESS)
1694-
json_errsave_error(result, lex, NULL);
1695-
tok = lex->token_type;
1700+
json_errsave_error(result, &lex, NULL);
16961701

1697-
switch (tok)
1702+
switch (lex.token_type)
16981703
{
16991704
case JSON_TOKEN_OBJECT_START:
17001705
type = "object";
@@ -1716,7 +1721,7 @@ json_typeof(PG_FUNCTION_ARGS)
17161721
type = "null";
17171722
break;
17181723
default:
1719-
elog(ERROR, "unexpected json token: %d", tok);
1724+
elog(ERROR, "unexpected json token: %d", lex.token_type);
17201725
}
17211726

17221727
PG_RETURN_TEXT_P(cstring_to_text(type));

src/backend/utils/adt/jsonb.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,13 @@ jsonb_typeof(PG_FUNCTION_ARGS)
252252
static inline Datum
253253
jsonb_from_cstring(char *json, int len, bool unique_keys, Node *escontext)
254254
{
255-
JsonLexContext *lex;
255+
JsonLexContext lex;
256256
JsonbInState state;
257257
JsonSemAction sem;
258258

259259
memset(&state, 0, sizeof(state));
260260
memset(&sem, 0, sizeof(sem));
261-
lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
261+
makeJsonLexContextCstringLen(&lex, json, len, GetDatabaseEncoding(), true);
262262

263263
state.unique_keys = unique_keys;
264264
state.escontext = escontext;
@@ -271,7 +271,7 @@ jsonb_from_cstring(char *json, int len, bool unique_keys, Node *escontext)
271271
sem.scalar = jsonb_in_scalar;
272272
sem.object_field_start = jsonb_in_object_field_start;
273273

274-
if (!pg_parse_json_or_errsave(lex, &sem, escontext))
274+
if (!pg_parse_json_or_errsave(&lex, &sem, escontext))
275275
return (Datum) 0;
276276

277277
/* after parsing, the item member has the composed jsonb structure */
@@ -755,11 +755,11 @@ datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result,
755755
case JSONTYPE_JSON:
756756
{
757757
/* parse the json right into the existing result object */
758-
JsonLexContext *lex;
758+
JsonLexContext lex;
759759
JsonSemAction sem;
760760
text *json = DatumGetTextPP(val);
761761

762-
lex = makeJsonLexContext(json, true);
762+
makeJsonLexContext(&lex, json, true);
763763

764764
memset(&sem, 0, sizeof(sem));
765765

@@ -772,7 +772,8 @@ datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result,
772772
sem.scalar = jsonb_in_scalar;
773773
sem.object_field_start = jsonb_in_object_field_start;
774774

775-
pg_parse_json_or_ereport(lex, &sem);
775+
pg_parse_json_or_ereport(&lex, &sem);
776+
freeJsonLexContext(&lex);
776777
}
777778
break;
778779
case JSONTYPE_JSONB:

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