Subject: Re: jsonapi: scary new warnings with LTO enabled

From: Tom Lane <[email-masked]>
Date: Wed, 16 Apr 2025 18:12:44 -0400

Daniel Gustafsson <[email-masked]> writes:
>> On 16 Apr 2025, at 23:42, Tom Lane <[email-masked]> wrote:
>> I'm not sure
>> how other than giving up on stack allocation of JsonLexContexts,
>> though, especially if we consider the jsonapi API frozen.  But seeing
>> that there are only three such call sites and none of them seem in the
>> least performance-critical, maybe we should just do that?

> I can't see any other option really, and there is no performance angle really
> so that should be safe.  Since I committed at least one of these, let me know
> if you want me to tackle it.

The only alternative I can see that might stop the warning is if we
can find a way to make it clearer to the optimizer that the FREE()
isn't reached.  But I'm not sure about a trustworthy way to make that
happen.  Maybe it'd work to change the signature of freeJsonLexContext
(or perhaps better, add a separate entry point) so that the caller is
passing a bool constant that controls whether to free the struct.
We could have an Assert that compares that to the state of the
JSONLEX_FREE_STRUCT flag to catch mistakes.  This seems kind of messy
though.

			regards, tom lane

---

From: Daniel Gustafsson <[email-masked]>
Date: Thu, 17 Apr 2025 00:18:23 +0200

> On 17 Apr 2025, at 00:12, Tom Lane <[email-masked]> wrote:
> 

Yeah, that seems messy enough that someone down the line will go "why on earth"
and we'll have to revisit this discussion.  It can probably be made to work but
I doubt it will be worth it compared to allocating on the heap.

--
Daniel Gustafsson

---

From: Tom Lane <[email-masked]>
Date: Wed, 16 Apr 2025 19:04:50 -0400

Daniel Gustafsson <[email-masked]> writes:
>> happen.

> I doubt it will be worth it compared to allocating on the heap.

Looking through all of the callers of freeJsonLexContext, quite
a lot of them use local JsonLexContext structs, and probably some
of them are more performance-critical than these.  So that raises
the question of why are we seeing warnings for only these call
sites?  Maybe there is a more elegant way to suppress them.

Still, I think that observation refutes my initial thought that
we should rip out support for local JsonLexContext structs
altogether.  I'm inclined now to just do the minimal thing of
changing these callers to use an allocated struct, and call it
a day.  (BTW, there seem to be only 2 places to change not 3;
two of the warnings are pointing at the same variable.)

			regards, tom lane

---

From: Jacob Champion <[email-masked]>
Date: Wed, 16 Apr 2025 16:09:40 -0700

On Wed, Apr 16, 2025 at 4:04 PM Tom Lane <[email-masked]> wrote:
> sites?

Yeah, I had the same question...

> Maybe there is a more elegant way to suppress them.

Can we brute-force ignore this particular warning site with a #pragma
(suggested in [1])?

--Jacob

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98753

---

From: Tom Lane <[email-masked]>
Date: Wed, 16 Apr 2025 19:28:44 -0400

> Yeah, I had the same question...

After making another pass through the callers of freeJsonLexContext,
I observe that the warnings appear in callers that use a local
variable *and* contain goto statements.  So I'm betting that the
presence of goto's causes the LTO optimizer to pull in its horns
quite a bit and thereby fail to detect the flag correlation.

> Can we brute-force ignore this particular warning site with a #pragma

That's surely not elegant :-(.  However, I don't especially want to
rewrite away the goto's in these callers ...

			regards, tom lane

---

From: Daniel Gustafsson <[email-masked]>
Date: Thu, 17 Apr 2025 13:43:18 +0200

> On 17 Apr 2025, at 01:28, Tom Lane <[email-masked]> wrote:
> 

That seems plausible given the selective warnings.

> rewrite away the goto's in these callers ...

Agreed, moving to heap allocated structures for these callsites seem much
better. Something like the attached should be enough I think?

--
Daniel Gustafsson

---

From: Jacob Champion <[email-masked]>
Date: Thu, 17 Apr 2025 08:48:05 -0700

On Thu, Apr 17, 2025 at 8:20 AM Tom Lane <[email-masked]> wrote:
> I confirm this silences those warnings on my Fedora 41 box.

Instead of doing

    lex = calloc(...);
    /* (error out on NULL return) */
    makeJsonLexContextCstringLen(lex, ...);

we need to do

    lex = makeJsonLexContextCstringLen(NULL, ...);
    /* (error out on NULL return) */

so that JSONLEX_FREE_STRUCT is set correctly. Otherwise we'll leak the
main allocation:

    ==12550==ERROR: LeakSanitizer: detected memory leaks
    Direct leak of 120 byte(s) in 1 object(s) allocated from:
        #0 0xaaaae34d2a84 in __interceptor_calloc
(/home/jacob/src/postgres/worktree-oauth/build-clang/src/interfaces/libpq/fuzz_libpq_handle_oauth_sasl_error+0x112a84)
(BuildId: 359bf20b63a97771ccb3bd2c238485920485521f)
        #1 0xaaaae3510ff0 in handle_oauth_sasl_error
/home/jacob/src/postgres/worktree-oauth/build-clang/../src/interfaces/libpq/fe-auth-oauth.c:511:8

> I'm content to do it like this, but maybe Jacob wants to
> investigate alternatives?

I was more worried about it when you said you wanted to get rid of the
stack allocation API. (I like having the flexibility to choose between
the two forms, not just for performance but also for struct
embedding.) But I'm perfectly happy with just adjusting these sites.

Thanks!
--Jacob

---

From: Jacob Champion <[email-masked]>
Date: Mon, 21 Apr 2025 08:33:28 -0700

On Sat, Apr 19, 2025 at 2:15 PM Daniel Gustafsson <[email-masked]> wrote:
> Since there is no way to determine if the allocation succeeded from outside of
> the JSON api it might be better to keep the calloc and explicitly free it?

I don't think so; pg_parse_json() will error out quickly, so I don't
see much advantage to the extra code. Raw performance isn't much of a
concern for the out-of-memory case, IMO.

> (Could a JsonLexContextBroken() function be useful perhaps?)

Maybe if there's ever a client that absolutely must initialize a
context before doing a bunch of independent work? But I don't think
that's true here. (Any callers we're converting from the stack API are
going to have short-lived contexts.)

--Jacob

---

From: Daniel Gustafsson <[email-masked]>
Date: Mon, 21 Apr 2025 20:20:00 +0200

> On 21 Apr 2025, at 17:33, Jacob Champion <[email-masked]> wrote:
> 

Sure, but I fear we'll get an endless stream of static analysis reports for the
allocation leaking if we don't free it.

--
Daniel Gustafsson

---

From: Jacob Champion <[email-masked]>
Date: Mon, 21 Apr 2025 11:28:43 -0700

> allocation leaking if we don't free it.

But we do free it, in freeJsonLexContext(). That usage of the API goes
back to 2023, with 1c99cde2f344. Or am I misunderstanding?

--Jacob

---

From: Jacob Champion <[email-masked]>
Date: Mon, 21 Apr 2025 11:58:34 -0700

On Mon, Apr 21, 2025 at 11:46 AM Daniel Gustafsson <[email-masked]> wrote:
> We do, but with the current coding we call setJsonLexContextOwnsTokens
> immediately after creation which derefences the pointer without checkinf for
> allocation failure.

Right. (The flag does nothing on the OOM sentinel.)

> This means we dereference the pointer before we can check
> for an OOM return from pg_parse_json which even if safe seems to violate code
> readability no?

Personally, I'm fine with can't-fail APIs, as long as they're
documented as such. (I think the deferred error API was probably
chosen so that src/common JSON clients could be written without a lot
of pain?)

--Jacob

---

From: Jacob Champion <[email-masked]>
Date: Tue, 22 Apr 2025 17:01:44 -0700

On Tue, Apr 22, 2025 at 3:10 AM Daniel Gustafsson <[email-masked]> wrote:
> My preference is that no operation can silently work on a failed object, but
> it's not a hill (even more so given where we are in the cycle).

Hm, okay. Something to talk about with Andrew and Peter, maybe.

> The attached
> v3 allocates via the JSON api, no specific error handling should be required as
> it's already handled today.

pgindent shows one whitespace change on my machine (comment
indentation), but other than that, LGTM! Fuzzers are happy too.

Thanks,
--Jacob