Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 09a8931

Browse files
committed
Repair bug that would allow libpq to think a command had succeeded when
it really hadn't, due to double output of previous command's response. Fix prevents recursive entry to libpq routines. Found by Jan Wieck.
1 parent 26b5d53 commit 09a8931

File tree

3 files changed

+93
-21
lines changed

3 files changed

+93
-21
lines changed

src/backend/libpq/pqcomm.c

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
3131
* Portions Copyright (c) 1994, Regents of the University of California
3232
*
33-
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.171 2004/08/29 05:06:43 momjian Exp $
33+
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.172 2004/09/26 00:26:19 tgl Exp $
3434
*
3535
*-------------------------------------------------------------------------
3636
*/
@@ -44,6 +44,7 @@
4444
* StreamClose - Close a client/backend connection
4545
* TouchSocketFile - Protect socket file against /tmp cleaners
4646
* pq_init - initialize libpq at backend startup
47+
* pq_comm_reset - reset libpq during error recovery
4748
* pq_close - shutdown libpq at backend exit
4849
*
4950
* low-level I/O:
@@ -88,21 +89,17 @@
8889
#include "storage/ipc.h"
8990

9091

91-
static void pq_close(int code, Datum arg);
92-
93-
#ifdef HAVE_UNIX_SOCKETS
94-
static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
95-
static int Setup_AF_UNIX(void);
96-
#endif /* HAVE_UNIX_SOCKETS */
97-
98-
9992
/*
10093
* Configuration options
10194
*/
10295
int Unix_socket_permissions;
10396
char *Unix_socket_group;
10497

10598

99+
/* Where the Unix socket file is */
100+
static char sock_path[MAXPGPATH];
101+
102+
106103
/*
107104
* Buffers for low-level I/O
108105
*/
@@ -121,9 +118,20 @@ static int PqRecvLength; /* End of data available in PqRecvBuffer */
121118
/*
122119
* Message status
123120
*/
121+
static bool PqCommBusy;
124122
static bool DoingCopyOut;
125123

126124

125+
/* Internal functions */
126+
static void pq_close(int code, Datum arg);
127+
static int internal_putbytes(const char *s, size_t len);
128+
static int internal_flush(void);
129+
#ifdef HAVE_UNIX_SOCKETS
130+
static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
131+
static int Setup_AF_UNIX(void);
132+
#endif /* HAVE_UNIX_SOCKETS */
133+
134+
127135
/* --------------------------------
128136
* pq_init - initialize libpq at backend startup
129137
* --------------------------------
@@ -132,10 +140,27 @@ void
132140
pq_init(void)
133141
{
134142
PqSendPointer = PqRecvPointer = PqRecvLength = 0;
143+
PqCommBusy = false;
135144
DoingCopyOut = false;
136145
on_proc_exit(pq_close, 0);
137146
}
138147

148+
/* --------------------------------
149+
* pq_comm_reset - reset libpq during error recovery
150+
*
151+
* This is called from error recovery at the outer idle loop. It's
152+
* just to get us out of trouble if we somehow manage to elog() from
153+
* inside a pqcomm.c routine (which ideally will never happen, but...)
154+
* --------------------------------
155+
*/
156+
void
157+
pq_comm_reset(void)
158+
{
159+
/* Do not throw away pending data, but do reset the busy flag */
160+
PqCommBusy = false;
161+
/* We can abort any old-style COPY OUT, too */
162+
pq_endcopyout(true);
163+
}
139164

140165
/* --------------------------------
141166
* pq_close - shutdown libpq at backend exit
@@ -174,8 +199,6 @@ pq_close(int code, Datum arg)
174199
* Stream functions are used for vanilla TCP connection protocol.
175200
*/
176201

177-
static char sock_path[MAXPGPATH];
178-
179202

180203
/* StreamDoUnlink()
181204
* Shutdown routine for backend connection
@@ -885,13 +908,30 @@ pq_getmessage(StringInfo s, int maxlen)
885908
*/
886909
int
887910
pq_putbytes(const char *s, size_t len)
911+
{
912+
int res;
913+
914+
/* Should only be called by old-style COPY OUT */
915+
Assert(DoingCopyOut);
916+
/* No-op if reentrant call */
917+
if (PqCommBusy)
918+
return 0;
919+
PqCommBusy = true;
920+
res = internal_putbytes(s, len);
921+
PqCommBusy = false;
922+
return res;
923+
}
924+
925+
static int
926+
internal_putbytes(const char *s, size_t len)
888927
{
889928
size_t amount;
890929

891930
while (len > 0)
892931
{
932+
/* If buffer is full, then flush it out */
893933
if (PqSendPointer >= PQ_BUFFER_SIZE)
894-
if (pq_flush()) /* If buffer is full, then flush it out */
934+
if (internal_flush())
895935
return EOF;
896936
amount = PQ_BUFFER_SIZE - PqSendPointer;
897937
if (amount > len)
@@ -912,6 +952,20 @@ pq_putbytes(const char *s, size_t len)
912952
*/
913953
int
914954
pq_flush(void)
955+
{
956+
int res;
957+
958+
/* No-op if reentrant call */
959+
if (PqCommBusy)
960+
return 0;
961+
PqCommBusy = true;
962+
res = internal_flush();
963+
PqCommBusy = false;
964+
return res;
965+
}
966+
967+
static int
968+
internal_flush(void)
915969
{
916970
static int last_reported_send_errno = 0;
917971

@@ -988,26 +1042,40 @@ pq_flush(void)
9881042
* then; dropping them is annoying, but at least they will still appear
9891043
* in the postmaster log.)
9901044
*
1045+
* We also suppress messages generated while pqcomm.c is busy. This
1046+
* avoids any possibility of messages being inserted within other
1047+
* messages. The only known trouble case arises if SIGQUIT occurs
1048+
* during a pqcomm.c routine --- quickdie() will try to send a warning
1049+
* message, and the most reasonable approach seems to be to drop it.
1050+
*
9911051
* returns 0 if OK, EOF if trouble
9921052
* --------------------------------
9931053
*/
9941054
int
9951055
pq_putmessage(char msgtype, const char *s, size_t len)
9961056
{
997-
if (DoingCopyOut)
1057+
if (DoingCopyOut || PqCommBusy)
9981058
return 0;
1059+
PqCommBusy = true;
9991060
if (msgtype)
1000-
if (pq_putbytes(&msgtype, 1))
1001-
return EOF;
1061+
if (internal_putbytes(&msgtype, 1))
1062+
goto fail;
10021063
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
10031064
{
10041065
uint32 n32;
10051066

10061067
n32 = htonl((uint32) (len + 4));
1007-
if (pq_putbytes((char *) &n32, 4))
1008-
return EOF;
1068+
if (internal_putbytes((char *) &n32, 4))
1069+
goto fail;
10091070
}
1010-
return pq_putbytes(s, len);
1071+
if (internal_putbytes(s, len))
1072+
goto fail;
1073+
PqCommBusy = false;
1074+
return 0;
1075+
1076+
fail:
1077+
PqCommBusy = false;
1078+
return EOF;
10111079
}
10121080

10131081
/* --------------------------------
@@ -1036,8 +1104,8 @@ pq_endcopyout(bool errorAbort)
10361104
{
10371105
if (!DoingCopyOut)
10381106
return;
1039-
DoingCopyOut = false;
10401107
if (errorAbort)
10411108
pq_putbytes("\n\n\\.\n", 5);
10421109
/* in non-error case, copy.c will have emitted the terminator line */
1110+
DoingCopyOut = false;
10431111
}

src/backend/tcop/postgres.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.432 2004/09/13 20:07:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.433 2004/09/26 00:26:25 tgl Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -2811,6 +2811,9 @@ PostgresMain(int argc, char *argv[], const char *username)
28112811
DisableNotifyInterrupt();
28122812
DisableCatchupInterrupt();
28132813

2814+
/* Make sure libpq is in a good state */
2815+
pq_comm_reset();
2816+
28142817
/* Report the error to the client and/or server log */
28152818
EmitErrorReport();
28162819

src/include/libpq/libpq.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/libpq/libpq.h,v 1.62 2004/08/29 04:13:07 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/libpq/libpq.h,v 1.63 2004/09/26 00:26:28 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -52,6 +52,7 @@ extern int StreamConnection(int server_fd, Port *port);
5252
extern void StreamClose(int sock);
5353
extern void TouchSocketFile(void);
5454
extern void pq_init(void);
55+
extern void pq_comm_reset(void);
5556
extern int pq_getbytes(char *s, size_t len);
5657
extern int pq_getstring(StringInfo s);
5758
extern int pq_getmessage(StringInfo s, int maxlen);

0 commit comments

Comments
 (0)