| Bug #15248 | Memory allocation bug in SQLDriverConnect | ||
|---|---|---|---|
| Submitted: | 25 Nov 2005 16:15 | Modified: | 8 Mar 2007 1:25 |
| Reporter: | Stéphane Donzé | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | Connector / ODBC | Severity: | S2 (Serious) |
| Version: | 3.51.12 | OS: | Linux (Linux (32 and 64)) |
| Assigned to: | Bogdan Degtyariov | CPU Architecture: | Any |
[25 Nov 2005 16:16]
Stéphane Donzé
First valgrind output
Attachment: exa.3log.652 (application/octet-stream, text), 11.48 KiB.
[25 Nov 2005 16:17]
Stéphane Donzé
Second valgrind output (after changing the login/password in the connection string)
Attachment: exa.3log.1431 (application/octet-stream, text), 11.67 KiB.
[25 Nov 2005 16:17]
Stéphane Donzé
valgrind: http://valgrind.org/
[26 Nov 2005 8:23]
Vasily Kishkin
Sorry...I was not able to reproduce the bug. Could you please build and run my test case ? My test case is attached.
[26 Nov 2005 8:23]
Vasily Kishkin
Test case
Attachment: test.c (text/plain), 5.28 KiB.
[28 Nov 2005 22:39]
Stéphane Donzé
I was able to reproduce the bug with your test case (slightly modified to make it compile and use an existing table on my side: cf file test2.c)
I ran the test on a Linux 64 machine (Linux version 2.4.21-32.0.1.ELsmp (bhcompile@thor.perf.redhat.com) (gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-52)) #1 SMP Tue May 17 17:46:36 EDT 2005)
The test case is working without any error with the 3.51.10 driver.
When ran against the 3.51.12, it dumps a core at the second connection:
[Thread debugging using libthread_db enabled]
[New Thread 182906365120 (LWP 5246)]
Connect....
Test....
Fetched...
Disconnect....
Connect....
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 182906365120 (LWP 5246)]
0x0000002a95f56160 in strcasecmp () from /lib64/tls/libc.so.6
(gdb) where
#0 0x0000002a95f56160 in strcasecmp () from /lib64/tls/libc.so.6
#1 0x0000002a96574e4e in MYODBCUtilReadConnectStr ()
from /ng/lib/amd64-linux/libmyodbc3_r.3.51.12.so
#2 0x0000002a9656a0db in my_SQLDriverConnect ()
from /ng/lib/amd64-linux/libmyodbc3_r.3.51.12.so
#3 0x0000002a9656a504 in SQLDriverConnect ()
from /ng/lib/amd64-linux/libmyodbc3_r.3.51.12.so
#4 0x0000002a95684996 in SQLDriverConnect (hdbc=0x2a98b02200, hwnd=0x0,
conn_str_in=0x7fbffff8a5 "DSN=logs;User=logsuser;Password=xxxxxxx;Server=ng5;Database=logs", len_conn_str_in=-3,
conn_str_out=0x5023c0 "DATABASE=logs;DESCRIPTION=Site logs;DSN=logs;OPTION=3;PWD=xxxxxxx;PORT=0;SERVER=ng5;UID=logsuser", conn_str_out_max=255,
ptr_conn_str_out=0x5024c0, driver_completion=0) at SQLDriverConnect.c:1155
#5 0x0000000000401413 in main (argc=-1733211584, argv=0x2a9657a60f)
at /ng/src/donze/ng/src/tmp/test.c:123
(gdb) quit
I also attach the valgrind output corresponding to this test case.
[28 Nov 2005 22:40]
Stéphane Donzé
Test case producing a SEGV in strcasecmp
Attachment: test2.c (application/octet-stream, text), 5.21 KiB.
[28 Nov 2005 22:42]
Stéphane Donzé
valgrind output for the test case
Attachment: sqltest.3log.5294 (application/octet-stream, text), 5.57 KiB.
[7 Dec 2005 12:09]
Vasily Kishkin
I was able to reproduce the bug on Linux Suse 9.3. Thanks for correct test case. I would like to notice test case works fine on Windows.
[13 Mar 2006 10:51]
Bogdan Degtyariov
I was able to repeat this bug with MyODBC 3.51.06 (threadsafe library only). Both versions of MyODBC 3.51.12 worked well on SuSE 9.2 (unixODBC 2.1.11)
[31 Mar 2006 13:27]
Pierre MARC
Have the same trouble on linux RedHat entreprise 4. I cannot make the MyOdbc
driver run correctly in a multithread environment. I wrote also a little test
program. sometimes it runs, sometimes it fails with the "Character set 'latin1'
..." message, sometimes it fails with a segmentation fault.
I used MySql 5.0.19, MyOdbc 3.51.12 and UnixOdbc 2.2.11.
My ODBC DSN uses the /usr/lib/libmyodbc3_r.so.
I also tried recompiling myodbc but the compilation failed with error telling
that there are multiple definition of adler32.
Is there any workarround to that blocking situation ?
to reproduce the pb:
testodbc -s sourcename -u user -p password -h numthreads
Here is the source of my testodbc program:
#include <pthread.h>
#include <stdio.h>
#include <sql.h> // core
#include <sqlext.h> // extensions
#include <string>
using namespace std;
// Thread mutex
pthread_mutex_t m_mMutex;
// End Thread flag
int EndThread = 0;
int NumErrors = 0;
// Num threads
int NumThreads = 1;
SQLCHAR Source[255]; // Data source name
SQLCHAR User[255]; // Data source user
SQLCHAR Password[255]; // Data source password
SQLCHAR Table[255]; // Data source table
void DisplaySqlError(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt);
int DisplaySqlStringInfo(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT InfoType);
int DoConnect(bool WithInfo, bool WithSearch);
void* ThreadMain(void *Value);
int main(int argc, char* argv[])
{
if(argc <=1)
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
Source[0] = '\0';
User[0] = '\0';
Password[0] = '\0';
int i;
for(i=1;i<argc;i++)
{
if(strcmp(argv[i], "-s") == 0)
{
if(i==(argc-1))
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
i++;
strcpy((char *) Source, argv[i]);
}
else if(strcmp(argv[i], "-u") == 0)
{
if(i==(argc-1))
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
i++;
strcpy((char *) User, argv[i]);
}
else if(strcmp(argv[i], "-p") == 0)
{
if(i==(argc-1))
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
i++;
strcpy((char *) Password, argv[i]);
}
else if(strcmp(argv[i], "-t") == 0)
{
if(i==(argc-1))
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
i++;
strcpy((char *) Table, argv[i]);
}
else if(strcmp(argv[i], "-h") == 0)
{
if(i==(argc-1))
{
printf("usage: testodbc -s DataSource -u User [-p Password] [-t Table] [-h
NumThreads]\n");
return 0;
}
i++;
NumThreads = atoi(argv[i]);
if(NumThreads <= 0)
NumThreads = 1;
if(NumThreads > 500)
NumThreads = 500;
}
}
if(!DoConnect(true, false))
return 0;
pthread_mutex_init(&m_mMutex, NULL);
EndThread = NumThreads;
int EndThreadHere = EndThread;
for(i=0;i<NumThreads;i++)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); // the unix thread has a
system scope for best performances
pthread_t thid;
pthread_create(&thid, &attr, ThreadMain, NULL);
pthread_attr_destroy(&attr);
}
while(EndThreadHere)
{
pthread_mutex_lock(&m_mMutex);
EndThreadHere = EndThread;
pthread_mutex_unlock(&m_mMutex);
}
if(NumErrors)
printf("\nProgram terminated with %d errors\n", NumErrors);
else
printf("\nProgram terminated successfully\n");
pthread_mutex_unlock(&m_mMutex);
pthread_mutex_destroy(&m_mMutex);
return 0;
}
void* ThreadMain(void *Value)
{
int RetVal = DoConnect(false, true);
pthread_mutex_lock(&m_mMutex);
if(!RetVal)
NumErrors++;
EndThread--;
pthread_mutex_unlock(&m_mMutex);
pthread_detach(pthread_self());
pthread_exit(NULL);
return (void *)(0); // end of thread (unix)
}
int DoConnect(bool WithInfo, bool WithSearch)
{
SQLHENV henv; /* environment handle */
SQLHDBC hdbc; /* connection handle */
SQLHSTMT hstmt; /* statement handle */
SQLRETURN retcode; /* return code */
SQLCHAR SQLStmt[255];
henv = NULL;
hdbc = NULL;
hstmt = NULL;
retcode = SQLAllocEnv(&henv);
retcode = SQLAllocConnect(henv, &hdbc);
retcode = SQLConnect(hdbc, Source, SQL_NTS, User, SQL_NTS, Password, SQL_NTS);
if (retcode != SQL_SUCCESS)
{
printf("*** Cannot connect data source\n");
DisplaySqlError(henv, hdbc, hstmt);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
return 0;
}
if(WithInfo)
{
printf("Database name: ");
DisplaySqlStringInfo(henv, hdbc,SQL_DBMS_NAME);
printf("\nDatabase version: ");
DisplaySqlStringInfo(henv, hdbc,SQL_DBMS_VER);
printf("\nDriver name: ");
DisplaySqlStringInfo(henv, hdbc,SQL_DRIVER_NAME);
printf("\nDriver version: ");
DisplaySqlStringInfo(henv, hdbc,SQL_DRIVER_VER);
printf("\nDriver ODBC version: ");
DisplaySqlStringInfo(henv, hdbc,SQL_ODBC_VER);
printf("\n");
}
if(WithSearch)
{
if(strlen((char *)Table))
{
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc,&hstmt);
if (retcode == SQL_SUCCESS)
{
strcpy((char *)SQLStmt, "SELECT * FROM ");
strcat((char *)SQLStmt, (char *)Table);
retcode = SQLExecDirect(hstmt, SQLStmt, SQL_NTS);
// Display The Results Of The SQL Query
if (retcode == SQL_SUCCESS)
printf("Database search successful\n");
else
{
printf("*** Error searching database\n");
DisplaySqlError(henv, hdbc, hstmt);
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
return 0;
}
}
// Free The SQL Statement Handle
if(hstmt != NULL)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
}
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
return 1;
}
void DisplaySqlError(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt)
{
SQLCHAR Message[SQL_MAX_MESSAGE_LENGTH + 1];
SQLCHAR State[10];
SQLINTEGER NativeError;
SQLSMALLINT TextLength;
Message[0] = '\0';
SQLError(henv, hdbc, hstmt, State, &NativeError, Message,
SQL_MAX_MESSAGE_LENGTH+1, &TextLength);
printf("SQL error: %s\n", (const char *)Message);
}
int DisplaySqlStringInfo(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT InfoType)
{
SQLRETURN retcode; /* return code */
SQLCHAR info[255]; /* info string for SQLGetInfo */
SQLSMALLINT cbInfoValue;
info[0] = '\0';
retcode = SQLGetInfo(hdbc,InfoType, &info, sizeof(info),&cbInfoValue);
if (retcode == SQL_SUCCESS)
printf((const char *)info);
else
{
printf("*** Cannot get info from data source\n");
DisplaySqlError(henv, hdbc, NULL);
return 0;
}
return 1;
}
makefile:
CXX = g++
CXXFLAGS = -I- -I./ -D_REENTRANT -D_GNU_SOURCE -DLINUX
LDFLAGS = -L./ -lpthread -ldl -lodbc
testodbc :: testodbc.o
$(CXX) -o $@ $^ $(LDFLAGS)
strip $@
testodbc.o : testodbc.cpp
$(CXX) -c -o $@ $< $(CXXFLAGS)
[13 Apr 2006 19:29]
Mark Smith
I am 95% sure this is a duplicate of bug 11892 (I have been debugging this same problem for a day now).
[11 May 2006 16:50]
Paul DuBois
Not enough information is given to produce a changelog entry. What is the version number for the fix? Is the problem reported actually the bug that was fixed? Thanks.
[8 Mar 2007 1:25]
Jim Winstead
This is a duplicate of Bug #11892.

Description: After opening and closing an ODBC connection with SQLDriverConnect several times, random errors occur in the driver, such as SEGV crashes or error messages like "Character set 'latin1' is not a compiled character set". These errors seem to be related to a memory block free'd at some point in the code and yet used later (see the valgrind output attached to this bug report). The 3.51.10 version is working fine and produces a clean valgrind output when run on exactly the same program. We are using the unixODBC-2.1.11 driver manager, but the bug was also observed with the DataDirect Connect for ODBC driver manager. Our database server is a 4.0.24 How to repeat: odbc.ini: [logs] Driver=/ng/lib/amd64-linux/libmyodbc3_r.so Description=Site logs Database=logs Option=3 Server=ssss program: for (int i = 0; i < 4; i++) { SQLAllocHandle(env); SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3); SQLDriverConnect("DSN=logs;User=xxxx;Password=yyyyy;Server=ssss;Database=logs"); SQLSetStmtAttr(SQL_ATTR_MAX_ROWS, 10); SQLExecDirect("SELECT * FROM table"); SQLNumResultCols() for each column: SQLDescribeCol() for each row: SQLFetch(); SQLGetData(); ... SQLDisconnect(); SQLFreeHandle(); SQLFreeEnv(); Suggested fix: cf the valgrind output: the get_charset_number() function reads data from a memory block that has been freed in SQLGetPrivateProfileString