public inbox for [email protected]  
help / color / mirror / Atom feed
From: Daniel Gustafsson <[email protected]>
To: Tom Lane <[email protected]>
Cc: Jacob Champion <[email protected]>
Cc: [email protected]
Subject: Re: jsonapi: scary new warnings with LTO enabled
Date: Thu, 17 Apr 2025 13:43:18 +0200
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
	<[email protected]>
	<[email protected]>
	<[email protected]>
	<[email protected]>
	<CAOYmi+n+DHpaEV5hymhufutTgc+S=+pDQfXEUi4hMAV1eO8aTw@mail.gmail.com>
	<[email protected]>

> On 17 Apr 2025, at 01:28, Tom Lane <[email protected]> wrote:
> 
> Jacob Champion <[email protected]> writes:
>> On Wed, Apr 16, 2025 at 4:04 PM Tom Lane <[email protected]> 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



Attachments:

  [application/octet-stream] 0001-Allocate-JsonLexContexts-on-the-heap-to-avoid-warnin.patch (5.4K, ../[email protected]/2-0001-Allocate-JsonLexContexts-on-the-heap-to-avoid-warnin.patch)
  download | inline diff:
From c5b661e24aff9d6ae54f922a289b92d39383322d Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <[email protected]>
Date: Thu, 17 Apr 2025 13:38:05 +0200
Subject: [PATCH] Allocate JsonLexContexts on the heap to avoid warnings

The stack allocated JsonLexContexts, in combination with codepaths
using goto, were causing warnings when compiling with LTO enabled
as the optimizer is unable to figure out that is safe.  Rather than
contort the code with workarounds for this simply heap allocate the
structs instead as these are not in any performance critical paths.

Reported-by: Tom Lane <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
 src/interfaces/libpq/fe-auth-oauth.c          | 23 ++++++++++++++-----
 .../test_json_parser_incremental.c            | 22 ++++++++++--------
 2 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/interfaces/libpq/fe-auth-oauth.c b/src/interfaces/libpq/fe-auth-oauth.c
index cf1a25e2ccc..b4d69874c83 100644
--- a/src/interfaces/libpq/fe-auth-oauth.c
+++ b/src/interfaces/libpq/fe-auth-oauth.c
@@ -476,7 +476,7 @@ issuer_from_well_known_uri(PGconn *conn, const char *wkuri)
 static bool
 handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
 {
-	JsonLexContext lex = {0};
+	JsonLexContext *lex;
 	JsonSemAction sem = {0};
 	JsonParseErrorType err;
 	struct json_ctx ctx = {0};
@@ -504,8 +504,19 @@ handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
 		return false;
 	}
 
-	makeJsonLexContextCstringLen(&lex, msg, msglen, PG_UTF8, true);
-	setJsonLexContextOwnsTokens(&lex, true);	/* must not leak on error */
+	/*
+	 * Later error paths need to go via the cleanup label but since ctx hasn't
+	 * been initiated yet we return immediately here.
+	 */
+	lex = calloc(1, sizeof(JsonLexContext));
+	if (!lex)
+	{
+		libpq_append_conn_error(conn, "out of memory");
+		return false;
+	}
+
+	makeJsonLexContextCstringLen(lex, msg, msglen, PG_UTF8, true);
+	setJsonLexContextOwnsTokens(lex, true);	/* must not leak on error */
 
 	initPQExpBuffer(&ctx.errbuf);
 	sem.semstate = &ctx;
@@ -516,7 +527,7 @@ handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
 	sem.array_start = oauth_json_array_start;
 	sem.scalar = oauth_json_scalar;
 
-	err = pg_parse_json(&lex, &sem);
+	err = pg_parse_json(lex, &sem);
 
 	if (err == JSON_SEM_ACTION_FAILED)
 	{
@@ -535,7 +546,7 @@ handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
 		}
 	}
 	else if (err != JSON_SUCCESS)
-		errmsg = json_errdetail(err, &lex);
+		errmsg = json_errdetail(err, lex);
 
 	if (errmsg)
 		libpq_append_conn_error(conn,
@@ -544,7 +555,7 @@ handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
 
 	/* Don't need the error buffer or the JSON lexer anymore. */
 	termPQExpBuffer(&ctx.errbuf);
-	freeJsonLexContext(&lex);
+	freeJsonLexContext(lex);
 
 	if (errmsg)
 		goto cleanup;
diff --git a/src/test/modules/test_json_parser/test_json_parser_incremental.c b/src/test/modules/test_json_parser/test_json_parser_incremental.c
index a529ee47e9b..357152e0ae0 100644
--- a/src/test/modules/test_json_parser/test_json_parser_incremental.c
+++ b/src/test/modules/test_json_parser/test_json_parser_incremental.c
@@ -84,7 +84,7 @@ main(int argc, char **argv)
 	char		buff[BUFSIZE];
 	FILE	   *json_file;
 	JsonParseErrorType result;
-	JsonLexContext lex;
+	JsonLexContext *lex;
 	StringInfoData json;
 	int			n_read;
 	size_t		chunk_size = DEFAULT_CHUNK_SIZE;
@@ -98,6 +98,10 @@ main(int argc, char **argv)
 
 	pg_logging_init(argv[0]);
 
+	lex = calloc(1, sizeof(JsonLexContext));
+	if (!lex)
+		pg_fatal("out of memory");
+
 	while ((c = getopt(argc, argv, "c:os")) != -1)
 	{
 		switch (c)
@@ -113,7 +117,7 @@ main(int argc, char **argv)
 			case 's':			/* do semantic processing */
 				testsem = &sem;
 				sem.semstate = palloc(sizeof(struct DoState));
-				((struct DoState *) sem.semstate)->lex = &lex;
+				((struct DoState *) sem.semstate)->lex = lex;
 				((struct DoState *) sem.semstate)->buf = makeStringInfo();
 				need_strings = true;
 				break;
@@ -131,8 +135,8 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	makeJsonLexContextIncremental(&lex, PG_UTF8, need_strings);
-	setJsonLexContextOwnsTokens(&lex, lex_owns_tokens);
+	makeJsonLexContextIncremental(lex, PG_UTF8, need_strings);
+	setJsonLexContextOwnsTokens(lex, lex_owns_tokens);
 	initStringInfo(&json);
 
 	if ((json_file = fopen(testfile, PG_BINARY_R)) == NULL)
@@ -165,12 +169,12 @@ main(int argc, char **argv)
 		bytes_left -= n_read;
 		if (bytes_left > 0)
 		{
-			result = pg_parse_json_incremental(&lex, testsem,
+			result = pg_parse_json_incremental(lex, testsem,
 											   json.data, n_read,
 											   false);
 			if (result != JSON_INCOMPLETE)
 			{
-				fprintf(stderr, "%s\n", json_errdetail(result, &lex));
+				fprintf(stderr, "%s\n", json_errdetail(result, lex));
 				ret = 1;
 				goto cleanup;
 			}
@@ -178,12 +182,12 @@ main(int argc, char **argv)
 		}
 		else
 		{
-			result = pg_parse_json_incremental(&lex, testsem,
+			result = pg_parse_json_incremental(lex, testsem,
 											   json.data, n_read,
 											   true);
 			if (result != JSON_SUCCESS)
 			{
-				fprintf(stderr, "%s\n", json_errdetail(result, &lex));
+				fprintf(stderr, "%s\n", json_errdetail(result, lex));
 				ret = 1;
 				goto cleanup;
 			}
@@ -195,7 +199,7 @@ main(int argc, char **argv)
 
 cleanup:
 	fclose(json_file);
-	freeJsonLexContext(&lex);
+	freeJsonLexContext(lex);
 	free(json.data);
 
 	return ret;
-- 
2.39.3 (Apple Git-146)



view thread (7+ messages)

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected]
  Subject: Re: jsonapi: scary new warnings with LTO enabled
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox