Skip to content

Commit 38f099e

Browse files
committed
Avoid calling strerror[_r] in PQcancel().
PQcancel() is supposed to be safe to call from a signal handler, and indeed psql uses it that way. All of the library functions it uses are specified to be async-signal-safe by POSIX ... except for strerror. Neither plain strerror nor strerror_r are considered safe. When this code was written, back in the dark ages, we probably figured "oh, strerror will just index into a constant array of strings" ... but in any locale except C, that's unlikely to be true. Probably the reason we've not heard complaints is that (a) this error-handling code is unlikely to be reached in normal use, and (b) in many scenarios, localized error strings would already have been loaded, after which maybe it's safe to call strerror here. Still, this is clearly unacceptable. The best we can do without relying on strerror is to print the decimal value of errno, so make it do that instead. (This is probably not much loss of user-friendliness, given that it is hard to get a failure here.) Back-patch to all supported branches. Discussion: https://postgr.es/m/2937814.1641960929@sss.pgh.pa.us
1 parent 9d1bcf5 commit 38f099e

File tree

1 file changed

+19
-3
lines changed

1 file changed

+19
-3
lines changed

src/interfaces/libpq/fe-connect.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4292,7 +4292,6 @@ internal_cancel(SockAddr *raddr, int be_pid, int be_key,
42924292
{
42934293
int save_errno = SOCK_ERRNO;
42944294
pgsocket tmpsock = PGINVALID_SOCKET;
4295-
char sebuf[PG_STRERROR_R_BUFLEN];
42964295
int maxlen;
42974296
struct
42984297
{
@@ -4371,8 +4370,25 @@ internal_cancel(SockAddr *raddr, int be_pid, int be_key,
43714370
maxlen = errbufsize - strlen(errbuf) - 2;
43724371
if (maxlen >= 0)
43734372
{
4374-
strncat(errbuf, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)),
4375-
maxlen);
4373+
/*
4374+
* We can't invoke strerror here, since it's not signal-safe. Settle
4375+
* for printing the decimal value of errno. Even that has to be done
4376+
* the hard way.
4377+
*/
4378+
int val = SOCK_ERRNO;
4379+
char buf[32];
4380+
char *bufp;
4381+
4382+
bufp = buf + sizeof(buf) - 1;
4383+
*bufp = '\0';
4384+
do
4385+
{
4386+
*(--bufp) = (val % 10) + '0';
4387+
val /= 10;
4388+
} while (val > 0);
4389+
bufp -= 6;
4390+
memcpy(bufp, "error ", 6);
4391+
strncat(errbuf, bufp, maxlen);
43764392
strcat(errbuf, "\n");
43774393
}
43784394
if (tmpsock != PGINVALID_SOCKET)

0 commit comments

Comments
 (0)