]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Avoid calling gettext() in signal handlers.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jan 2022 18:30:04 +0000 (13:30 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jan 2022 18:30:04 +0000 (13:30 -0500)
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

src/bin/scripts/common.c

index 797a97f5dd5f883327f3bfaffc9e7c4c55d9a13a..a2fb209f750246333925877e60275a5d666b6bc7 100644 (file)
 #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;