Subject: [postgresql-interfaces/psqlodbc] issue #189: Possible double-free / heap corruption in psqlODBC during SQLDisconnect cleanup

From: "cipriani-ivan (@cipriani-ivan)" <[email-masked]>
Date: Thu, 21 May 2026 12:35:22 +0000

Dear psqlODBC maintainers,
I would like to report a potential memory corruption issue in the PostgreSQL ODBC driver and ask whether this is a known or tracked problem.

Summary
We are observing repeatable heap corruption (0xC0000374) in a .NET application using:

PostgreSQL: 17.9
psqlODBC: 17.0.0.4
Windows: x64
Driver: PostgreSQL Unicode (x64)

The failure occurs during connection teardown after a failed connection.

Observed behavior
With Application Verifier + Page Heap, the crash consistently reports:
HEAP_CORRUPTION_ACTIONABLE_BlockNotBusy_DOUBLE_FREE

Stack trace
Below is the stack trace captured in WinDbg:
ucrtbase!free_base
psqlodbc35w!SC_clear_error
psqlodbc35w!PGAPI_FreeStmt
psqlodbc35w!SQLFreeStmt
odbc32!SQLDisconnect
System.Data.Odbc.OdbcConnection.Close()

This suggests a double free during statement/connection cleanup, likely in an error path.

Reproduction scenario
The issue appears under the following conditions:

Connection attempt fails (e.g. SQLSTATE 08S01, connection down)
Application immediately disposes the connection
Cleanup invokes SQLDisconnect / SQLFreeStmt
Occurs more frequently under:

Release builds
Parallel workloads
Forced cleanup paths

Analysis / suspicion

Multiple cleanup layers (SC_clear_error, PGAPI_FreeStmt) appear to release overlapping resources
The issue occurs in a failure path (connection already down)
Recent release notes do not indicate changes in this cleanup logic
Similar memory-safety fixes exist historically but not in this code path

Questions

Is this behavior a known issue in current psqlODBC versions?
Is there ongoing work related to cleanup safety in error paths?
Are there recommended usage constraints (threading / disposal patterns) to avoid this?

Context
This occurs in a modern multithreaded .NET application, where:

Failed connections are disposed immediately
Cleanup may occur under concurrency
Robust handling of failure paths is required

We understand the complexity of ODBC lifecycle semantics, but this appears to expose a double-free condition under certain cleanup scenarios.

Thank you for your time and for maintaining psqlODBC.
Best regards,
Ivan Cipriani

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Fri, 22 May 2026 14:55:32 +0000

I have a possible solution in #190 Is it possible for you to test without me publishing a release?

---

From: "cipriani-ivan (@cipriani-ivan)" <[email-masked]>
Date: Tue, 26 May 2026 13:14:40 +0000

Thank you for the proposed solution in [#190](https://github.com/postgresql-interfaces/psqlodbc/pull/190). I’ll attempt to test it, though I’m not certain I’ll be able to set it up successfully.
Do you have an estimated timeline for the release?

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Sat, 30 May 2026 16:03:27 +0000

No real ETA. Was hoping to release soon though

---

From: "cipriani-ivan (@cipriani-ivan)" <[email-masked]>
Date: Mon, 01 Jun 2026 08:39:10 +0000

Hi @davecramer,
Thank you again for providing the proposed fix in #190.
I’ve been able to build and test the driver from the branch. Unfortunately, we are still able to reproduce a crash during the same teardown scenario. The behavior has changed slightly, though:

The process still terminates during cleanup after a failed connection
Instead of the previous heap corruption signature, we now consistently see:
FATAL: terminating connection due to administrator command

The crash still occurs in the same general flow (connection failure → immediate disposal → cleanup)

In addition, we are observing similar instability in a few other failure scenarios, particularly in situations where a connection is closed and a new one is created shortly after.
So while the symptom has changed, it seems the underlying issue is not fully resolved yet.

Thanks again for your work on this.
Best regards,

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Wed, 03 Jun 2026 13:45:21 +0000

@cipriani-ivan any way you could provide a reproducer for this ? Or even logs from PostgreSQL ? Are you able to get a stack trace ?