Skip to content

SQLFreeStmt(stmt,SQL_DROP) now returns an error when it's conn has been disconnected. #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

harukat
Copy link
Contributor

@harukat harukat commented Apr 24, 2025

SQLFreeStmt(stmt, SQL_DROP) now returns an error before trying to free statement resources
when its connection already has been closed.

A crash occurred when the PostgreSQL server terminated and a connection was subsequently attempted from an application when connection pooling by the driver manager was enabled and several pooled connections existed. In such cases, an invalid memory access would occur in ENTER_CONN_CS(conn) in SQLFreeStmt(), or an invalid address free() would be attempted in SC_clear_error() via PGAPI_FreeStmt().

"CC_cleanup()" doing "conn->status = CONN_NOT_CONNECTED" releases all statements belonging to the connection, so this change will probably not cause a resource leak.

… statement resources when its connection already has been closed.

A crash occurred when the PostgreSQL server terminated and a connection was
subsequently attempted from an application when connection pooling by the
driver manager was enabled and several pooled connections existed.
In such cases, an invalid memory access would occur in ENTER_CONN_CS(conn)
in SQLFreeStmt(), or an invalid address free() would be attempted in
SC_clear_error() via PGAPI_FreeStmt().

"CC_cleanup()" doing "conn->status = CONN_NOT_CONNECTED" releases all
statements belonging to the connection, so this change will probably not cause
a resource leak.
After continued testing, I found that the earlier fix alone caused
crashes in similar attempts, so we improved the fix.
@davecramer davecramer merged commit cc5d02a into postgresql-interfaces:main Apr 24, 2025
1 check passed
@davecramer
Copy link
Contributor

@harukat has this fixed the issue for you ?

@harukat
Copy link
Contributor Author

harukat commented Apr 30, 2025

@harukat has this fixed the issue for you ?

Yes.
At least in the crash reproduction steps that I am aware of, it no longer reproduces after applying this fix.

However, we have subsequently received reports of psqlodbc crashing under similar circumstances after applying this fix. I have not yet been able to analyze this issue and have not established a procedure to reproduce it.

@harukat
Copy link
Contributor Author

harukat commented Apr 30, 2025

@davecramer
Information was obtained about the crash after the fix.

Although this fix reduces the frequency of occurrence, it does not seem to completely prevent the driver manager from attempting to execute SQLFreeStmt(hstmt,SQL_DROP) twice for same hstmt.

When connection pooling was enabled and clients were repeatedly connecting, querying, and disconnecting, stopping the PostgreSQL server and having clients repeatedly try to connect could cause hstmt dereference to fail or double free.

The following is an excerpt from the call stack as it occurs:

(hstmt dereference failure case)
podbc35w!SQLFreeStmt
odbc32!DisconnectCleanup
odbc32!SQLDisconnect
System_Data_6e170000
clr!CallDescrWorkerInternal

(double free case)
ntdll!RtlpLogHeapFailure
ntdll!RtlFreeHeap
ucrtbase!_free_base
ucrtbase!free
podbc35w!SC_clear_error
podbc35w!PGAPI_FreeStmt
podbc35w!SQLFreeStmt
odbc32!DisconnectCleanup
odbc32!SQLDisconnect
System_Data_6da30000
clr!CallDescrWorkerInternal

The following is the tail of debug log as it occurs: (hstmt dereference failure case)

[1096-27.344]odbcapi30w[SQLGetConnectAttrW]76: Entering
[1096-27.344] pgapi30.c[PGAPI_GetConnectAttr]411: entering 1209
[1096-27.344] odbcapi.c[SQLMoreResults]1189: Entering
[1096-27.344]statement.[SC_log_error]2502: STATEMENT ERROR: func=SQLMoreResults, desc='', errnum=35, errmsg='SQLMoreResults unable due to the connection lost'
[1096-27.344]connection[CC_log_error]2641: CONN ERROR: func=SQLMoreResults, desc='', errnum=0, errmsg='(NULL)'
[1096-27.344] odbcapi.c[SQLFreeStmt]395: Entering
[1096-27.344]statement.[PGAPI_FreeStmt]248: entering...hstmt=06D925A0, fOption=0
[1096-27.344]statement.[SC_recycle_statement]881: entering self=06D925A0
[1096-27.344] qresult.c[QR_Destructor]356: entering
[1096-27.344]    bind.c[PDATA_free_params]676: entering self=06D92780
[1096-27.344]odbcapi30.[SQLFreeHandle]264: Entering
[1096-27.344]statement.[PGAPI_FreeStmt]248: entering...hstmt=06D925A0, fOption=1
[1096-27.344] qresult.c[QR_Destructor]356: entering
[1096-27.344]statement.[SC_init_Result]555: leaving(06D925A0)
[1096-27.344]statement.[SC_Destructor]491: entering self=06D925A0, self->result=00000000, self->hdbc=06D932F8
[1096-27.344]statement.[SC_log_error]2502: STATEMENT ERROR: func=SC_Destructor, desc='', errnum=35, errmsg='connection error.'
[1096-27.344]connection[CC_log_error]2641: CONN ERROR: func=SC_Destructor, desc='', errnum=0, errmsg='(NULL)'
[1096-27.344]    bind.c[APD_free_params]656: entering self=06D926B8
[1096-27.344]    bind.c[IPD_free_params]711: entering self=06D926F8
[1096-27.344]    bind.c[PDATA_free_params]676: entering self=06D92780
[1096-27.344]statement.[SC_Destructor]545: leaving
[1096-28.015] odbcapi.c[SQLFreeStmt]395: Entering
[1096-28.015]statement.[PGAPI_FreeStmt]248: entering...hstmt=06D925A0, fOption=1

@davecramer
Copy link
Contributor

I created a new PR which attempts to solve your problem see #115

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants