Message-ID: From: "markmaker (@markmaker)" To: "postgresql-interfaces/psqlodbc" Date: Wed, 01 Apr 2026 19:52:01 +0000 Subject: Re: [postgresql-interfaces/psqlodbc] PR #145: SQL_C_BINARY data buffer uses NULL terminator, but realloc() may be missed In-Reply-To: References: List-Id: X-GitHub-Author-Login: markmaker X-GitHub-Comment-Id: 4172597997 X-GitHub-Comment-Type: issue_comment X-GitHub-Issue: 145 X-GitHub-Repo: postgresql-interfaces/psqlodbc X-GitHub-Type: comment X-GitHub-Url: https://github.com/postgresql-interfaces/psqlodbc/pull/145#issuecomment-4172597997 Content-Type: text/plain; charset=utf-8 @jarvis24young, you need to provoke a case, where the previously used `pgdc->ttlbuf` is exactly one byte too small (for the null terminator byte), or in other words, the largest previously buffered blob needs to have a length that is one less. I guess it would suffice to create a table with blobs that grow in size row-by-row by one byte. Then using a fresh ODBC connection, fetch those rows ordered by length, ascending. For `valgrind` it might trigger the error for every length, but for a real memory corruption, you would also need to hit a certain length that exactly fills up the internal `malloc()` block allocation (which is typically rounded up to some granularity), so that the buffer overrun null terminator byte corrupts the neighboring block. I don't hand-write SQL very often so I used AI to help generate this script. It seems to work, creating such rows. But I haven't tested reproducing the bug with the old faulty ODBC driver. ```sql -- Drop table if it already exists DROP TABLE IF EXISTS bytea_test; -- Create table with sequential primary key and bytea column CREATE TABLE bytea_test ( id BIGSERIAL PRIMARY KEY, data BYTEA NOT NULL ); -- Insert rows with increasing bytea length INSERT INTO bytea_test (data) SELECT repeat('D', n)::bytea FROM generate_series(1000, 1100) AS n; -- Verify lengths SELECT id, octet_length(data) AS byte_length FROM bytea_test ORDER BY id; ```