From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 17 Jan 2022 18:30:04 +0000 (-0500)
Subject: Avoid calling gettext() in signal handlers.
X-Git-Tag: REL_10_20~27
X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=62bfa554b285f34e7d3ec3675fa87ba0d71f7268;p=postgresql.git

Avoid calling gettext() in signal handlers.

It seems highly unlikely that gettext() can be relied on to be
async-signal-safe.  psql used to understand that, but someone got
it wrong long ago in the src/bin/scripts/ version of handle_sigint,
and then the bad idea was perpetuated when those two versions were
unified into src/fe_utils/cancel.c.

I'm unsure why there have not been field complaints about this
... maybe gettext() is signal-safe once it's translated at least
one message?  But we have no business assuming any such thing.

In cancel.c (v13 and up), I preserved our ability to localize
"Cancel request sent" messages by invoking gettext() before
the signal handler is set up.  In earlier branches I just made
src/bin/scripts/ not localize those messages, as psql did then.

(Just for extra unsafety, the src/bin/scripts/ version was
invoking fprintf() from a signal handler.  Sigh.)

Noted while fixing signal-safety issues in PQcancel() itself.
Back-patch to all supported branches.

Discussion: https://postgr.es/m/2937814.1641960929@sss.pgh.pa.us
---

diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
index 797a97f5dd5..a2fb209f750 100644
--- a/src/bin/scripts/common.c
+++ b/src/bin/scripts/common.c
@@ -21,6 +21,19 @@
 #include "fe_utils/connect.h"
 #include "fe_utils/string_utils.h"
 
+/*
+ * Write a simple string to stderr --- must be safe in a signal handler.
+ * We ignore the write() result since there's not much we could do about it.
+ * Certain compilers make that harder than it ought to be.
+ */
+#define write_stderr(str) \
+	do { \
+		const char *str_ = (str); \
+		int		rc_; \
+		rc_ = write(fileno(stderr), str_, strlen(str_)); \
+		(void) rc_; \
+	} while (0)
+
 #define PQmblenBounded(s, e)  strnlen(s, PQmblen(s, e))
 
 
@@ -490,10 +503,13 @@ handle_sigint(SIGNAL_ARGS)
 		if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
 		{
 			CancelRequested = true;
-			fprintf(stderr, _("Cancel request sent\n"));
+			write_stderr("Cancel request sent\n");
 		}
 		else
-			fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
+		{
+			write_stderr("Could not send cancel request: ");
+			write_stderr(errbuf);
+		}
 	}
 	else
 		CancelRequested = true;
@@ -527,11 +543,14 @@ consoleHandler(DWORD dwCtrlType)
 		{
 			if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
 			{
-				fprintf(stderr, _("Cancel request sent\n"));
 				CancelRequested = true;
+				write_stderr("Cancel request sent\n");
 			}
 			else
-				fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
+			{
+				write_stderr("Could not send cancel request: ");
+				write_stderr(errbuf);
+			}
 		}
 		else
 			CancelRequested = true;