postgresql-interfaces/psqlodbc GitHub issues and pull requests (mirror)
help / color / mirror / Atom feedFrom: davecramer (@davecramer) <[email protected]>
To: postgresql-interfaces/psqlodbc <[email protected]>
Subject: Re: [postgresql-interfaces/psqlodbc] PR #179: Handle ARD bookmark allocation failure
Date: Wed, 29 Apr 2026 13:44:46 +0000
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
AI review
Summary
This PR adds NULL-check handling for ARD_AllocBookmark() across all its call sites. Previously, if
malloc failed inside ARD_AllocBookmark(), the code would dereference NULL via
pg_memset(ardopts->bookmark, 0, ...), crashing the process. The fix propagates the failure as
proper ODBC errors.
The Bug
In the existing ARD_AllocBookmark():
BindInfoClass *ARD_AllocBookmark(ARDFields *ardopts)
{
if (!ardopts->bookmark) {
ardopts->bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
pg_memset(ardopts->bookmark, 0, sizeof(BindInfoClass)); // NULL deref if malloc fails
}
return ardopts->bookmark;
}
If malloc returns NULL, pg_memset dereferences it — instant crash. This is called from:
1. PGAPI_AllocStmt() — every statement allocation
2. PGAPI_BindCol() (bind.c) — bookmark column binding
3. ARDSetField() (pgapi30.c) — descriptor field updates
4. ARDFields_copy() — descriptor copy (already handled NULL)
The Fix
descriptor.c — Core fix:
ardopts->bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
+if (!ardopts->bookmark)
+ return NULL;
pg_memset(ardopts->bookmark, 0, sizeof(BindInfoClass));
statement.c — PGAPI_AllocStmt caller:
-ARD_AllocBookmark(ardopts);
+if (!ARD_AllocBookmark(ardopts))
+{
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory...", func);
+ CC_remove_statement(conn, stmt);
+ SC_Destructor(stmt);
+ *phstmt = SQL_NULL_HSTMT;
+ return SQL_ERROR;
+}
bind.c — SQLBindCol bookmark path:
bookmark = ARD_AllocBookmark(opts);
+if (!bookmark)
+{
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bookmark binding.",
func);
+ ret = SQL_ERROR;
+ goto cleanup;
+}
pgapi30.c — ARDSetField descriptor path:
BindInfoClass *bookmark = ARD_AllocBookmark(opts);
+if (!bookmark)
+{
+ DC_set_error(desc, DESC_NO_MEMORY_ERROR, "Could not allocate memory for bookmark descriptor");
+ return SQL_ERROR;
+}
Assessment
Correctness: ✅ Good
Each call site uses the appropriate error-reporting mechanism for its context:
- PGAPI_AllocStmt → CC_set_error on the connection (correct, since the statement is being
- PGAPI_BindCol → SC_set_error on the statement + goto cleanup (follows existing pattern in that
function)
- ARDSetField → DC_set_error on the descriptor (correct for descriptor operations)
Cleanup in PGAPI_AllocStmt: ✅ Thorough
The failure path does CC_remove_statement → SC_Destructor → clear *phstmt. This is the right
sequence — the statement was already added to the connection via CC_add_statement earlier in the
function, so it must be removed before destruction. This matches the pattern used for the
CC_add_statement failure case just above it in the existing code.
ARDFields_copy already handled: ✅ Noted
Looking at the existing code in ARDFields_copy():
BindInfoClass *bookmark = ARD_AllocBookmark(target);
if (bookmark)
BindInfoClass_copy(src->bookmark, bookmark);
This already silently handles NULL — it just skips the copy. The PR doesn't change this, which is
correct since PGAPI_CopyDesc doesn't have a clean way to propagate the error (it would need more
refactoring).
Test: ✅ Pragmatic
The test exercises the normal SQLAllocHandle(SQL_HANDLE_STMT) path that triggers ARD_AllocBookmark.
It can't deterministically trigger OOM in a portable way, so it validates the happy path. The PR
description documents manual fault-injection testing with LD_PRELOAD that confirmed the crash
before and the clean error after. This is a reasonable approach — the code change is obviously
correct from inspection, and the fault injection provides the empirical evidence.
Issues
1. Minor: DESC_NO_MEMORY_ERROR SQLSTATE mapping
Looking at the descriptor error table, DESC_NO_MEMORY_ERROR maps to SQLSTATE HY001 (memory
allocation error). This is the correct SQLSTATE for an OOM condition per the ODBC spec. Good.
2. The ARDFields_copy silent failure is a latent issue (not introduced by this PR)
If ARD_AllocBookmark returns NULL during PGAPI_CopyDesc, the bookmark is silently lost. This is
pre-existing behavior (the code already checked for NULL) and not made worse by this PR. A
follow-up could propagate the error, but it's out of scope here.
3. Test name ard-bookmark-oom is slightly misleading
The committed test doesn't actually test OOM — it tests the normal allocation path. The name
suggests it's an OOM test. Something like ard-bookmark-alloc would be more accurate. But this is
cosmetic and the test file comments explain the situation clearly.
4. Test placement in test/tests
The test is inserted after exe/bookmark-test in the test list, which is a logical grouping. Good.
view thread (2+ messages)
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: github://postgresql-interfaces/psqlodbc
Cc: [email protected], [email protected]
Subject: Re: [postgresql-interfaces/psqlodbc] PR #179: Handle ARD bookmark allocation failure
In-Reply-To: <<[email protected]>>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox