Thread: jsonapi: scary new warnings with LTO enabled

jsonapi: scary new warnings with LTO enabled

From
Tom Lane
Date:
I noticed some new warnings from buildfarm member chafer,
which I'm able to reproduce locally on a Fedora 41 box
by building with "meson setup build -Db_lto=true":

ninja: Entering directory `build'
[1515/2472] Linking target src/interfaces/libpq/libpq.so.5.18
In function 'freeJsonLexContext',
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'handle_oauth_sasl_error' at ../src/interfaces/libpq/fe-auth-oauth.c:547:2:
../src/common/jsonapi.c:723:17: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  723 |                 FREE(lex);
      |                 ^
../src/interfaces/libpq/fe-auth-oauth.c: In function 'handle_oauth_sasl_error':
../src/interfaces/libpq/fe-auth-oauth.c:479:24: note: declared here
  479 |         JsonLexContext lex = {0};
      |                        ^
[2407/2472] Linking target src/test/modules/test_json_parser/test_json_parser_incremental_shlib
In function 'freeJsonLexContext',
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'main' at ../src/test/modules/test_json_parser/test_json_parser_incremental.c:198:2:
../src/common/jsonapi.c:723:17: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  723 |                 FREE(lex);
      |                 ^
../src/test/modules/test_json_parser/test_json_parser_incremental.c: In function 'main':
../src/test/modules/test_json_parser/test_json_parser_incremental.c:87:24: note: declared here
   87 |         JsonLexContext lex;
      |                        ^
[2426/2472] Linking target src/test/modules/test_json_parser/test_json_parser_incremental
In function 'pg_free',
    inlined from 'pfree' at ../src/common/fe_memutils.c:135:2,
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:723:3,
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'main' at ../src/test/modules/test_json_parser/test_json_parser_incremental.c:198:2:
../src/common/fe_memutils.c:107:9: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  107 |         free(ptr);
      |         ^
../src/test/modules/test_json_parser/test_json_parser_incremental.c: In function 'main':
../src/test/modules/test_json_parser/test_json_parser_incremental.c:87:24: note: declared here
   87 |         JsonLexContext lex;
      |                        ^

AFAICT there is no actual bug here: the FREE() call is reached only if
the JSONLEX_FREE_STRUCT flag is set, which it should not be for these
call sites.  But evidently the LTO optimizer is not quite smart enough
to realize that.

It seems fairly dangerous to ignore -Wfree-nonheap-object warnings.
I feel like we ought to move to prevent these somehow.  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?

            regards, tom lane



Re: jsonapi: scary new warnings with LTO enabled

From
Daniel Gustafsson
Date:
> On 16 Apr 2025, at 23:42, Tom Lane <tgl@sss.pgh.pa.us> wrote:

> It seems fairly dangerous to ignore -Wfree-nonheap-object warnings.
> I feel like we ought to move to prevent these somehow.

Absolutely agree.

> 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.

--
Daniel Gustafsson




Re: jsonapi: scary new warnings with LTO enabled

From
Tom Lane
Date:
Daniel Gustafsson <daniel@yesql.se> writes:
>> On 16 Apr 2025, at 23:42, Tom Lane <tgl@sss.pgh.pa.us> 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



Re: jsonapi: scary new warnings with LTO enabled

From
Ranier Vilela
Date:


Em qua., 16 de abr. de 2025 às 18:42, Tom Lane <tgl@sss.pgh.pa.us> escreveu:
I noticed some new warnings from buildfarm member chafer,
which I'm able to reproduce locally on a Fedora 41 box
by building with "meson setup build -Db_lto=true":

ninja: Entering directory `build'
[1515/2472] Linking target src/interfaces/libpq/libpq.so.5.18
In function 'freeJsonLexContext',
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'handle_oauth_sasl_error' at ../src/interfaces/libpq/fe-auth-oauth.c:547:2:
../src/common/jsonapi.c:723:17: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  723 |                 FREE(lex);
      |                 ^
../src/interfaces/libpq/fe-auth-oauth.c: In function 'handle_oauth_sasl_error':
../src/interfaces/libpq/fe-auth-oauth.c:479:24: note: declared here
  479 |         JsonLexContext lex = {0};
      |                        ^
[2407/2472] Linking target src/test/modules/test_json_parser/test_json_parser_incremental_shlib
In function 'freeJsonLexContext',
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'main' at ../src/test/modules/test_json_parser/test_json_parser_incremental.c:198:2:
../src/common/jsonapi.c:723:17: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  723 |                 FREE(lex);
      |                 ^
../src/test/modules/test_json_parser/test_json_parser_incremental.c: In function 'main':
../src/test/modules/test_json_parser/test_json_parser_incremental.c:87:24: note: declared here
   87 |         JsonLexContext lex;
      |                        ^
[2426/2472] Linking target src/test/modules/test_json_parser/test_json_parser_incremental
In function 'pg_free',
    inlined from 'pfree' at ../src/common/fe_memutils.c:135:2,
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:723:3,
    inlined from 'freeJsonLexContext' at ../src/common/jsonapi.c:688:1,
    inlined from 'main' at ../src/test/modules/test_json_parser/test_json_parser_incremental.c:198:2:
../src/common/fe_memutils.c:107:9: warning: 'free' called on unallocated object 'lex' [-Wfree-nonheap-object]
  107 |         free(ptr);
      |         ^
../src/test/modules/test_json_parser/test_json_parser_incremental.c: In function 'main':
../src/test/modules/test_json_parser/test_json_parser_incremental.c:87:24: note: declared here
   87 |         JsonLexContext lex;
      |                        ^

AFAICT there is no actual bug here: the FREE() call is reached only if
the JSONLEX_FREE_STRUCT flag is set, which it should not be for these
call sites.  
See the function *makeJsonLexContextCstringLen* (line 400)
The JSONLEX_FREE_STRUCT  is enabled, no?

fe-auth-oauth.c (line 507)
makeJsonLexContextCstringLen(&lex, msg, msglen, PG_UTF8, true);

Worst, on a second call, with lex not NULL, the flags is reseted
and the struct will no longer be released?

best regards,
Ranier Vilela

Re: jsonapi: scary new warnings with LTO enabled

From
Daniel Gustafsson
Date:
> On 17 Apr 2025, at 00:12, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Daniel Gustafsson <daniel@yesql.se> writes:
>>> On 16 Apr 2025, at 23:42, Tom Lane <tgl@sss.pgh.pa.us> 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.

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




Re: jsonapi: scary new warnings with LTO enabled

From
Tom Lane
Date:
Daniel Gustafsson <daniel@yesql.se> writes:
> On 17 Apr 2025, at 00:12, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> 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.

> 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.

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



Re: jsonapi: scary new warnings with LTO enabled

From
Jacob Champion
Date:
On Wed, Apr 16, 2025 at 4:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> 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?

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



Re: jsonapi: scary new warnings with LTO enabled

From
Tom Lane
Date:
Jacob Champion <jacob.champion@enterprisedb.com> writes:
> On Wed, Apr 16, 2025 at 4:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> 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?

> 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.

>> 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])?

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

            regards, tom lane



Re: jsonapi: scary new warnings with LTO enabled

From
Daniel Gustafsson
Date:
> On 17 Apr 2025, at 01:28, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Jacob Champion <jacob.champion@enterprisedb.com> writes:
>> On Wed, Apr 16, 2025 at 4:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>>> 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?
>
>> 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.

That seems plausible given the selective warnings.

>>> 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])?
>
> That's surely not elegant :-(.  However, I don't especially want to
> 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


Attachment

Re: jsonapi: scary new warnings with LTO enabled

From
Tom Lane
Date:
Daniel Gustafsson <daniel@yesql.se> writes:
> Agreed, moving to heap allocated structures for these callsites seem much
> better. Something like the attached should be enough I think?

I confirm this silences those warnings on my Fedora 41 box.

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

            regards, tom lane



Re: jsonapi: scary new warnings with LTO enabled

From
Jacob Champion
Date:
On Thu, Apr 17, 2025 at 8:20 AM Tom Lane <tgl@sss.pgh.pa.us> 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



Re: jsonapi: scary new warnings with LTO enabled

From
Daniel Gustafsson
Date:
> On 17 Apr 2025, at 17:48, Jacob Champion <jacob.champion@enterprisedb.com> wrote:
>
> On Thu, Apr 17, 2025 at 8:20 AM Tom Lane <tgl@sss.pgh.pa.us> 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:

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?

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

--
Daniel Gustafsson


Attachment