Subject Client C program with Embedded SQL Crashing on Firebird 2.5/CentOS 5.5
Author jbovitzii
Hi All,

I am porting a program that has been working fine on Solaris 8-10 /Firebird 1.5 to Linux (Centos 5.5) and Firebird 2.5.

The problem is that the SIGTERM signal is causing the client C program to crash at random points but only when the program has created an actual database connection. I have simplified the program to be as short as possible and have included it below. The program is first processed by gpre and then compiled as usual. I verified that the output (C code) that gpre creates for the connectToDb() function is identical for the version 1.5 gpre and the version 2.5 gpre. Running valgrind on the process before sending SIGTERM to it indicates that the program is trying to access memory that does not exist after the signal is handled. From that, my suspicion is that something in the firebird library that handles the database attachment is trashing memory in some way.

Oddly enough, if I use a different signal (e.g SIGSTOP) but the same signal handler, the program works fine. The only problem with that is that I can't get the program to ignore SIGTERM (again only when it has an active connection to the database) so if that signal is sent to the program, it still crashes in the same way.

Thanks in advance for any much appreciated help.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>

int okToLive = 1;
int dbConnected = 0;
char dbUser[100] = "qduser";
char dbPasswd[100] = "qdpasswd";
char dataBase[256] = "/usr/mprint/qdirect/server/db/qdirect.gdb";

EXEC SQL SET DATABASE db1 =
COMPILETIME 'localhost:/usr/mprint/qdirect/server/db/qdirect.gdb'
RUNTIME :dataBase;

void
dbDisconnect()
{
fprintf(stderr, "Begin: dbDisconnect()\n");
EXEC SQL ROLLBACK;
EXEC SQL DISCONNECT ALL;
fprintf(stderr, "End: dbDisconnect()\n");
}

void
dbErrCheck(fn, opr)
char *fn, *opr;
{
if ( (SQLCODE != 0) && (SQLCODE != 100) )
{
char buf[1000] = { '\0' };

fprintf(stderr, "func: %s, opr: %s, SQLCODE: %d\n", fn, opr, SQLCODE);
isc_sql_interprete(SQLCODE, buf, sizeof(buf));
fprintf(0, "-SQLMSG: %s\n", buf);
if (SQLCODE < -1)
{
ISC_STATUS *v;
char buf2[1000] = { '\0' };

v = isc_status;
while (isc_interprete(buf2, &v))
fprintf(stderr, "-ISCMSG: %s\n", buf2);
}
fprintf(stderr, "program aborted.\n");
exit(-1);
}
else
{
/* for some reason, some of the embedded EXEC SQL statements
* generate non zero errno's even if they succeed. Since we
* are only interested in ERRORS if SQLCODE is not 0 or 100,
* always reset errno to 0 in all other cases so output
* messages do not reflect false values of errno.
*/
errno = 0;
}
fprintf(stderr, "func: %s, opr: %s, SQLCODE: %d.\n", fn, opr, SQLCODE);
}

void
connectToDb()
{
fprintf(stderr, "Begin: connectToDb()\n");
EXEC SQL CONNECT db1 USER :dbUser PASSWORD :dbPasswd;
dbErrCheck("connectToDb", "CONNECT");
dbConnected = 1;
fprintf(stderr, "connected to database %s\n", dataBase);
fprintf(stderr, "End: connectToDb()\n");
}

void
stopServer(int sig)
{
okToLive = 0;
}

int
main()
{
struct sigaction act;

fprintf(stderr, "okToLive is %d. errno=%d\n", okToLive, errno);
bzero(&act, sizeof(act));

act.sa_handler = stopServer;
act.sa_flags = SA_RESTART;
sigaction(SIGTERM, &act, NULL);

/* comment out this call to make program work without crash */
connectToDb();

while(okToLive)
{
fprintf(stderr, "TOP: okToLive is %d. errno=%d\n", okToLive, errno);
sleep(2);
fprintf(stderr, "AFTER: okToLive is %d. errno=%d\n", okToLive, errno);
}

fprintf(stderr, "AFTER LOOP1: okToLive is %d. errno=%d\n", okToLive, errno);
errno = 0;
fprintf(stderr, "AFTER LOOP2: okToLive is %d. errno=%d\n", okToLive, errno);
fprintf(stderr, "AFTER LOOP3: okToLive is %d. errno=%d\n", okToLive, errno);
sleep(5);
fprintf(stderr, "AFTER SLEEP: okToLive is %d. errno=%d\n", okToLive, errno);
dbDisconnect();
fprintf(stderr, "LAST LINE: okToLive is %d. errno=%d\n", okToLive, errno);
exit(0);
}