(This is split off from my work on OAUTHBEARER [1].)

The jsonapi in src/common can't currently be compiled into libpq. The
first patch here removes the dependency on pg_log_fatal(), which is not
available to the sharedlib. The second patch makes sure that all of the
return values from json_errdetail() can be pfree'd, to avoid long-
running leaks.

In the original thread, Michael Paquier commented:

> +#  define check_stack_depth()
> +#  ifdef JSONAPI_NO_LOG
> +#    define json_log_and_abort(...) \
> +   do { fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
> +#  else
> In patch 0002, this is the wrong approach.  libpq will not be able to
> feed on such reports, and you cannot use any of the APIs from the
> palloc() family either as these just fail on OOM.  libpq should be
> able to know about the error, and would fill in the error back to the
> application.  This abstraction is not necessary on HEAD as
> pg_verifybackup is fine with this level of reporting.  My rough guess
> is that we will need to split the existing jsonapi.c into two files,
> one that can be used in shared libraries and a second that handles the 
> errors.

Hmm. I'm honestly hesitant to start splitting files apart, mostly
because json_log_and_abort() is only called from two places, and both
those places are triggered by programmer error as opposed to user
error.

Would it make more sense to switch to an fprintf-and-abort case, to
match the approach taken by PGTHREAD_ERROR and the out-of-memory
conditions in fe-print.c? Or is there already precedent for handling
can't-happen code paths with in-band errors, through the PGconn?

--Jacob

[1] 
https://www.postgresql.org/message-id/d1b467a78e0e36ed85a09adf979d04cf124a9d4b.ca...@vmware.com
From 0541598e4f0bad1b9ff41a4640ec69491b393d54 Mon Sep 17 00:00:00 2001
From: Jacob Champion <pchamp...@vmware.com>
Date: Mon, 3 May 2021 11:15:15 -0700
Subject: [PATCH 2/7] src/common: remove logging from jsonapi for shlib

The can't-happen code in jsonapi was pulling in logging code, which for
libpq is not included.
---
 src/common/Makefile  |  4 ++++
 src/common/jsonapi.c | 11 ++++++++---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/common/Makefile b/src/common/Makefile
index 38a8599337..6f1039bc78 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -28,6 +28,10 @@ subdir = src/common
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
+# For use in shared libraries, jsonapi needs to not link in any logging
+# functions.
+override CFLAGS_SL += -DJSONAPI_NO_LOG
+
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
 STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
diff --git a/src/common/jsonapi.c b/src/common/jsonapi.c
index 1bf38d7b42..6b6001b118 100644
--- a/src/common/jsonapi.c
+++ b/src/common/jsonapi.c
@@ -27,11 +27,16 @@
 #endif
 
 #ifdef FRONTEND
-#define check_stack_depth()
-#define json_log_and_abort(...) \
+#  define check_stack_depth()
+#  ifdef JSONAPI_NO_LOG
+#    define json_log_and_abort(...) \
+	do { fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
+#  else
+#    define json_log_and_abort(...) \
 	do { pg_log_fatal(__VA_ARGS__); exit(1); } while(0)
+#  endif
 #else
-#define json_log_and_abort(...) elog(ERROR, __VA_ARGS__)
+#  define json_log_and_abort(...) elog(ERROR, __VA_ARGS__)
 #endif
 
 /*
-- 
2.25.1

From 5ad4b3c7835fe9e0f284702ec7b827c27770854e Mon Sep 17 00:00:00 2001
From: Jacob Champion <pchamp...@vmware.com>
Date: Mon, 3 May 2021 15:38:26 -0700
Subject: [PATCH 3/7] common/jsonapi: always palloc the error strings

...so that client code can pfree() to avoid memory leaks in long-running
operations.
---
 src/common/jsonapi.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/common/jsonapi.c b/src/common/jsonapi.c
index 6b6001b118..f7304f584f 100644
--- a/src/common/jsonapi.c
+++ b/src/common/jsonapi.c
@@ -1089,7 +1089,7 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
 			return psprintf(_("Expected JSON value, but found \"%s\"."),
 							extract_token(lex));
 		case JSON_EXPECTED_MORE:
-			return _("The input string ended unexpectedly.");
+			return pstrdup(_("The input string ended unexpectedly."));
 		case JSON_EXPECTED_OBJECT_FIRST:
 			return psprintf(_("Expected string or \"}\", but found \"%s\"."),
 							extract_token(lex));
@@ -1103,16 +1103,16 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
 			return psprintf(_("Token \"%s\" is invalid."),
 							extract_token(lex));
 		case JSON_UNICODE_CODE_POINT_ZERO:
-			return _("\\u0000 cannot be converted to text.");
+			return pstrdup(_("\\u0000 cannot be converted to text."));
 		case JSON_UNICODE_ESCAPE_FORMAT:
-			return _("\"\\u\" must be followed by four hexadecimal digits.");
+			return pstrdup(_("\"\\u\" must be followed by four hexadecimal digits."));
 		case JSON_UNICODE_HIGH_ESCAPE:
 			/* note: this case is only reachable in frontend not backend */
-			return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
+			return pstrdup(_("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8."));
 		case JSON_UNICODE_HIGH_SURROGATE:
-			return _("Unicode high surrogate must not follow a high surrogate.");
+			return pstrdup(_("Unicode high surrogate must not follow a high surrogate."));
 		case JSON_UNICODE_LOW_SURROGATE:
-			return _("Unicode low surrogate must follow a high surrogate.");
+			return pstrdup(_("Unicode low surrogate must follow a high surrogate."));
 	}
 
 	/*
-- 
2.25.1

Reply via email to