Skip to content

Commit

Permalink
Fix possible seg faults with SQLAPI and pooling
Browse files Browse the repository at this point in the history
  • Loading branch information
lurcher committed May 31, 2023
1 parent 458833b commit 2a73009
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 39 deletions.
104 changes: 89 additions & 15 deletions DriverManager/SQLAllocHandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,13 +308,86 @@ SQLRETURN __SQLAllocHandle( SQLSMALLINT handle_type,
{
pooling_enabled = 1;
}
else

#ifdef SHARED_POOLED_ENV
if ( pooling_enabled )
{
pooling_enabled = 0;
int first;

SQLGetPrivateProfileString( "ODBC", "PoolMaxSize", "0",
pool_max_size_string, sizeof( pool_max_size_string ),
"ODBCINST.INI" );
pool_max_size = atoi( pool_max_size_string );

SQLGetPrivateProfileString( "ODBC", "PoolWaitTimeout", "30",
pool_wait_timeout_string, sizeof( pool_wait_timeout_string ),
"ODBCINST.INI" );
pool_wait_timeout = atoi( pool_wait_timeout_string );

if ( !( environment = __share_env( &first )))
{
*output_handle = SQL_NULL_HENV;
return SQL_ERROR;
}
*output_handle = (SQLHANDLE) environment;

if ( first ) {
/*
* setup environment state
*/

environment -> state = STATE_E1;
environment -> requested_version = requested_version;
environment -> version_set = !!requested_version;
environment -> sql_driver_count = -1;

/*
* if SQLAllocEnv is called then it's probable that
* the application wants ODBC2.X type behaviour
*
* In this case we don't need to set the version via
* SQLSetEnvAttr()
*
*/

environment -> connection_count = 0;
}
}
else {

if ( !( environment = __alloc_env()))
{
*output_handle = SQL_NULL_HENV;
return SQL_ERROR;
}
*output_handle = (SQLHANDLE) environment;

/*
* setup environment state
*/

environment -> state = STATE_E1;
environment -> requested_version = requested_version;
environment -> version_set = !!requested_version;
environment -> sql_driver_count = -1;

/*
* if SQLAllocEnv is called then it's probable that
* the application wants ODBC2.X type behaviour
*
* In this case we don't need to set the version via
* SQLSetEnvAttr()
*
*/

environment -> connection_count = 0;
}
#else

if ( pooling_enabled )
{
int first;

SQLGetPrivateProfileString( "ODBC", "PoolMaxSize", "0",
pool_max_size_string, sizeof( pool_max_size_string ),
"ODBCINST.INI" );
Expand All @@ -334,26 +407,27 @@ SQLRETURN __SQLAllocHandle( SQLSMALLINT handle_type,
*output_handle = (SQLHANDLE) environment;

/*
* setup environment state
*/
* setup environment state
*/

environment -> state = STATE_E1;
environment -> requested_version = requested_version;
environment -> version_set = !!requested_version;
environment -> sql_driver_count = -1;
environment -> sql_driver_count = -1;

/*
* if SQLAllocEnv is called then it's probable that
* the application wants ODBC2.X type behaviour
*
* In this case we don't need to set the version via
* SQLSetEnvAttr()
*
*/

* if SQLAllocEnv is called then it's probable that
* the application wants ODBC2.X type behaviour
*
* In this case we don't need to set the version via
* SQLSetEnvAttr()
*
*/
environment -> connection_count = 0;

return SQL_SUCCESS;
#endif

return SQL_SUCCESS;
}
break;

Expand Down
101 changes: 96 additions & 5 deletions DriverManager/SQLConnect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2900,6 +2900,10 @@ static void close_pooled_connection( CPOOLENT *ptr )
SQLRETURN ret;
DMHDBC conn = &ptr -> connection;

if ( conn -> driver_dbc == NULL ) {
return;
}

/*
* disconnect from the driver
*/
Expand Down Expand Up @@ -3075,7 +3079,7 @@ static void close_pooled_connection( CPOOLENT *ptr )

/*
* if a environment gets released from the application, we need to remove any referenvce to that environment
* in pooled connections that belong to that environment
* in pooled connections that belong to that environment. Also if needed call the release in the driver itself
*/

void __strip_from_pool( DMHENV env )
Expand All @@ -3084,17 +3088,18 @@ void __strip_from_pool( DMHENV env )

mutex_pool_entry();

/*
* look in the list of connections for one that matches
*/

for( ptrh = pool_head; ptrh; ptrh = ptrh -> next )
{
CPOOLENT *ptre;
for ( ptre = ptrh -> entries; ptre; ptre = ptre -> next )
{
if ( ptre -> connection.environment == env )
{
/*
* disconnect driver side connection, and when the last the driver side env
*/
close_pooled_connection( ptre );

ptre -> connection.environment = NULL;
}
}
Expand Down Expand Up @@ -3210,6 +3215,49 @@ static int pool_match( CPOOLHEAD *pooh,
return match;
}

/*
int display_pool( void )
{
printf( "pool_head: %p\n", pool_head );
if ( pool_head ) {
CPOOLHEAD *pptr;
CPOOLENT *pent;
pptr = pool_head;
while( pptr ) {
printf( "\tpptr: %p\n", pptr );
printf( "\t\tdsn: %s\n", pptr -> _driver_connect_string );
printf( "\t\tnum_entries: %d\n", pptr -> num_entries );
printf( "\t\tentries: %p\n", pptr -> entries );
printf( "\t\tnext: %p\n", pptr -> next );
pent = pptr -> entries;
while( pent ) {
printf( "\t\t\tpent: %p\n", pent );
printf( "\t\t\texpiry_time: %d\n", pent -> expiry_time );
printf( "\t\t\tttl: %d\n", pent -> ttl );
printf( "\t\t\tin_use: %d\n", pent -> in_use );
printf( "\t\t\thead: %p\n", pent -> head );
printf( "\t\t\tcursors: %d\n", pent -> cursors );
printf( "\t\t\tconnection -> env: %p\n", pent -> connection.environment );
printf( "\t\t\tconnection -> driver_env: %p\n", pent -> connection.driver_env );
printf( "\t\t\tnext: %p\n", pent -> next );
printf( "\n" );
pent = pent -> next;
}
pptr = pptr -> next;
printf( "\n" );
}
}
}
*/

/*
* Search for a matching connection from the pool
* Removes expired connections too
Expand Down Expand Up @@ -3277,6 +3325,40 @@ restart:;
continue;
}

/*
* has it been previously stripped
*/

if ( ptre -> connection.environment == NULL )
{
if ( ptre == ptrh -> entries ) /* head of the list ? */
{
ptrh -> entries = ptre -> next;
}
else
{
preve -> next = ptre -> next;
}
free( ptre );
ptrh -> num_entries --;
pool_signal();

if ( ! ptrh -> num_entries ) /* free the head too */
{
if ( prevh )
{
prevh -> next = ptrh -> next;
}
else
{
pool_head = ptrh -> next;
}
free( ptrh -> _driver_connect_string );
free( ptrh );
}
goto restart;
}

/*
* has it expired ? Do some cleaning up first
*/
Expand Down Expand Up @@ -3347,6 +3429,15 @@ restart:;
continue;
}

/*
* we are spanning env's
*/

if ( ptre -> connection.environment && ptre -> connection.environment != connection -> environment )
{
continue;
}

/*
* ok so far, is it still alive ?
*/
Expand Down
22 changes: 17 additions & 5 deletions DriverManager/SQLFreeHandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@

static char const rcsid[]= "$RCSfile: SQLFreeHandle.c,v $ $Revision: 1.12 $";

extern int pooling_enabled;

SQLRETURN __SQLFreeHandle( SQLSMALLINT handle_type,
SQLHANDLE handle )
{
Expand All @@ -193,10 +195,13 @@ SQLRETURN __SQLFreeHandle( SQLSMALLINT handle_type,
DMHENV environment = (DMHENV)handle;

/*
* check environment
* check environment, the mark_released addition is to catch what seems to be a
* race error in SQLAPI where it uses a env handle in one thread while its being released
* in another. releasing the handle at the end of this function is not fast enough for
* the normal validation process to catch it.
*/

if ( !__validate_env( environment ))
if ( !__validate_env_mark_released( environment ))
{
dm_log_write( __FILE__,
__LINE__,
Expand Down Expand Up @@ -245,12 +250,19 @@ SQLRETURN __SQLFreeHandle( SQLSMALLINT handle_type,

thread_release( SQL_HANDLE_ENV, environment );

/*
* release any pooled connections that are using this environment
*/
#ifdef SHARED_POOLED_ENV
if ( pooling_enabled == 0 ) {
/*
* release any pooled connections that are using this environment
*/
__strip_from_pool( environment );
}
#else
__strip_from_pool( environment );
#endif

__release_env( environment );

return SQL_SUCCESS;
}
break;
Expand Down
11 changes: 7 additions & 4 deletions DriverManager/SQLSetEnvAttr.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@

static char const rcsid[]= "$RCSfile: SQLSetEnvAttr.c,v $ $Revision: 1.9 $";

extern int pooling_enabled;

SQLRETURN SQLSetEnvAttr( SQLHENV environment_handle,
SQLINTEGER attribute,
SQLPOINTER value,
Expand All @@ -145,14 +147,15 @@ SQLRETURN SQLSetEnvAttr( SQLHENV environment_handle,
DMHENV environment = (DMHENV) environment_handle;
SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];

/*
* we may do someting with these later
*/

if ( !environment_handle &&
( attribute == SQL_ATTR_CONNECTION_POOLING ||
attribute == SQL_ATTR_CP_MATCH ))
{
if ( attribute == SQL_ATTR_CONNECTION_POOLING ) {
if ((SQLLEN) value == SQL_CP_ONE_PER_DRIVER || (SQLLEN) value == SQL_CP_ONE_PER_HENV ) {
pooling_enabled = 1;
}
}
return SQL_SUCCESS;
}

Expand Down
Loading

0 comments on commit 2a73009

Please sign in to comment.