8000 Improve JsonLexContext's freeability · postgres/postgres@1c99cde · GitHub
[go: up one dir, main page]

Skip to content 8000

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
  • bin/pg_verifybackup
  • common
  • include
  • 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)
    0