Message-ID: From: "jarvis24young (@jarvis24young)" To: "postgresql-interfaces/psqlodbc" Date: Fri, 15 May 2026 06:15:21 +0000 Subject: [postgresql-interfaces/psqlodbc] PR #188: Clear PGresults from per-query rollback List-Id: X-GitHub-Author-Id: 48787405 X-GitHub-Author-Login: jarvis24young X-GitHub-Issue: 188 X-GitHub-Repo: postgresql-interfaces/psqlodbc X-GitHub-State: merged X-GitHub-Type: pull_request X-GitHub-Url: https://github.com/postgresql-interfaces/psqlodbc/pull/188 Content-Type: text/plain; charset=utf-8 ## Problem CC_internal_rollback() drains all PGresults returned by PQgetResult() in the PER_QUERY_ROLLBACK path, but did not clear each non-NULL result inside the loop. The command sent in this path contains two statements, ROLLBACK TO _per_query_svp_ and RELEASE _per_query_svp_, so libpq can return more than one result. Overwriting pgres on the next iteration loses the previous result and leaks it. ## Fix Clear each PGresult immediately after handling it, matching the pattern already used by other PQgetResult() loops in connection.c. ## Verification Built the driver in WSL with ASan/UBSan and exercised the real unixODBC + psqlODBC + PostgreSQL path. The black-box reproducer used Protocol=7.4-2 and UseServerSidePrepare=1, prepared and executed a statement, ran DEALLOCATE ALL through ODBC, then freed the prepared ODBC statement. That makes the driver's internal DEALLOCATE fail, logs SAVEPOINT _per_query_svp_ followed by ROLLBACK TO _per_query_svp_; RELEASE _per_query_svp_, and reaches CC_internal_rollback(PER_QUERY_ROLLBACK). Before this patch, LSan reported: SUMMARY: AddressSanitizer: 432 byte(s) leaked in 2 allocation(s), with the stack PQgetResult -> CC_internal_rollback -> CC_send_query_append -> SC_set_prepared. After this patch, the same reproducer exits with no LSan leak report. I also reran test/exe/error-rollback-test under the same ASan build; it passed.