1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +03:00

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
This commit is contained in:
Alvaro Herrera
2023-10-05 10:59:08 +02:00
parent a8a968a821
commit 1c99cde2f3
7 changed files with 153 additions and 86 deletions

View File

@ -135,26 +135,62 @@ IsValidJsonNumber(const char *str, int len)
/*
* makeJsonLexContextCstringLen
* Initialize the given JsonLexContext object, or create one
*
* lex constructor, with or without StringInfo object for de-escaped lexemes.
* If a valid 'lex' pointer is given, it is initialized. This can
* be used for stack-allocated structs, saving overhead. If NULL is
* given, a new struct is allocated.
*
* Without is better as it makes the processing faster, so only make one
* if really required.
* If need_escapes is true, ->strval stores the unescaped lexemes.
* Unescaping is expensive, so only request it when necessary.
*
* If need_escapes is true or lex was given as NULL, then caller is
* responsible for freeing the returned struct, either by calling
* freeJsonLexContext() or (in backend environment) via memory context
* cleanup.
*/
JsonLexContext *
makeJsonLexContextCstringLen(char *json, int len, int encoding, bool need_escapes)
makeJsonLexContextCstringLen(JsonLexContext *lex, char *json,
int len, int encoding, bool need_escapes)
{
JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
if (lex == NULL)
{
lex = palloc0(sizeof(JsonLexContext));
lex->flags |= JSONLEX_FREE_STRUCT;
}
else
memset(lex, 0, sizeof(JsonLexContext));
lex->input = lex->token_terminator = lex->line_start = json;
lex->line_number = 1;
lex->input_length = len;
lex->input_encoding = encoding;
if (need_escapes)
{
lex->strval = makeStringInfo();
lex->flags |= JSONLEX_FREE_STRVAL;
}
return lex;
}
/*
* Free memory in a JsonLexContext. There's no need for this if a *lex
* pointer was given when the object was made and need_escapes was false,
* or (in backend environment) a memory context delete/reset is imminent.
*/
void
freeJsonLexContext(JsonLexContext *lex)
{
if (lex->flags & JSONLEX_FREE_STRVAL)
{
pfree(lex->strval->data);
pfree(lex->strval);
}
if (lex->flags & JSONLEX_FREE_STRUCT)
pfree(lex);
}
/*
* pg_parse_json
*