Skip to content

Instantly share code, notes, and snippets.

@larskanis
Last active November 22, 2023 20:03
Show Gist options
  • Save larskanis/5546a20365b0ca64e294a32b138f441e to your computer and use it in GitHub Desktop.
Save larskanis/5546a20365b0ca64e294a32b138f441e to your computer and use it in GitHub Desktop.
postgresql-bug #18210 reproducer
/*
* Run this program in a Kerberos capable environment and it should fail like so:
* $ gcc -I /usr/include/postgresql bug-gssapi-caller.c -o bug-gssapi-caller -l pq
* $ ./bug-gssapi-caller
* PQputCopyData text2 command failed: GSSAPI caller failed to retransmit all data needing to be retried
*/
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <libpq-fe.h>
static void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
static void
wait_socket(PGconn *conn)
{
/* Quit after four notifies are received. */
while (PQisBusy(conn)) {
int sock;
fd_set input_mask;
PQflush(conn);
sock = PQsocket(conn);
if (sock < 0)
break; /* shouldn't happen */
FD_ZERO(&input_mask);
FD_SET(sock, &input_mask);
if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
{
fprintf(stderr, "select() failed: %s\n", strerror(errno));
exit_nicely(conn);
}
/* Now check for input */
PQconsumeInput(conn);
}
}
int
main(int argc, char **argv)
{
PGconn *conn;
PGresult *res;
PGnotify *notify;
int nnotifies;
/* Make a connection to the database
* With gssencmode=disable the program finishes.
* With gssencmode=require it fails after some loops.
*/
conn = PQconnectdb("host=comdb2 dbname=Entwicklung gssencmode=require");
/* Check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn,
"CREATE TEMP TABLE mycopy (id SERIAL PRIMARY KEY, data TEXT)");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "CREATE TABLE failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
if(PQsetnonblocking(conn, 1) == -1) {
fprintf(stderr, "PQsetnonblocking failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQsendQuery(conn, "COPY mycopy (data) FROM STDIN");
/* wait_socket is called for completeness only.
* Otherwise PQgetResult() just blocks even in nonblocking mode. */
wait_socket(conn);
res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_COPY_IN) {
fprintf(stderr, "COPY command failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
char *text1 = malloc(27000);
char *text2 = malloc(180);
for(int i = 0; i < 100000; i++) {
if( PQputCopyData(conn, text1, 27000) != 1) {
fprintf(stderr, "PQputCopyData text1 command failed: %s", PQerrorMessage(conn));
exit_nicely(conn);
}
if( PQputCopyData(conn, text2, 180) != 1) {
fprintf(stderr, "PQputCopyData text2 command failed: %s", PQerrorMessage(conn));
exit_nicely(conn);
}
}
fprintf(stderr, "Done.\n");
/* close the connection to the database and cleanup */
PQfinish(conn);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment