postgresql-interfaces/psqlodbc GitHub issues and pull requests (mirror)  
help / color / mirror / Atom feed
From: markmaker (@markmaker) <[email protected]>
To: postgresql-interfaces/psqlodbc <[email protected]>
Subject: [postgresql-interfaces/psqlodbc] PR #145: SQL_C_BINARY data buffer uses NULL terminator, but realloc() may be missed
Date: Fri, 21 Nov 2025 15:05:52 +0000
Message-ID: <[email protected]> (raw)

# Problem

We get spurious heap corruption.

# Diagnosis

After a steep learning curve in such matters, we finally found a way to pinpoint it using `valgrind` (the key was using the redzone, so it would not immediately corrupt everything): 

```bash
valgrind --tool=memcheck --leak-check=summary --redzone-size=8 <executable>
```
It outputs these sections (snippets).
**EDIT:** installed Debug symbol, now we can even better pinpoint it:

```
==2666205== Invalid write of size 1
==2666205==    at 0x154AEDA7: UnknownInlinedFun (convert.c:6414)
==2666205==    by 0x154AEDA7: convert_from_pgbinary.isra.0 (convert.c:6235)
==2666205==    by 0x154ABE8E: UnknownInlinedFun (convert.c:1115)
==2666205==    by 0x154ABE8E: UnknownInlinedFun (convert.c:1189)
==2666205==    by 0x154ABE8E: copy_and_convert_field.isra.0 (convert.c:1726)
==2666205==    by 0x154754FA: UnknownInlinedFun (convert.c:810)
==2666205==    by 0x154754FA: SC_fetch (statement.c:1839)
==2666205==    by 0x15469B14: PGAPI_ExtendedFetch (results.c:1902)
==2666205==    by 0x15485922: SQLFetchScroll (odbcapi30.c:245)
==2666205==    by 0x556BF4D: SQLFetchScroll (in /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0)
...

==2666205==  Address 0x180015b8 is 0 bytes after a block of size 3,576 alloc'd
==2666205==    at 0x4851E10: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2666205==    by 0x154ACDDB: UnknownInlinedFun (convert.c:1071)
==2666205==    by 0x154ACDDB: UnknownInlinedFun (convert.c:1189)
==2666205==    by 0x154ACDDB: copy_and_convert_field.isra.0 (convert.c:1726)
==2666205==    by 0x154754FA: UnknownInlinedFun (convert.c:810)
==2666205==    by 0x154754FA: SC_fetch (statement.c:1839)
==2666205==    by 0x15469B14: PGAPI_ExtendedFetch (results.c:1902)
==2666205==    by 0x15485922: SQLFetchScroll (odbcapi30.c:245)
==2666205==    by 0x556BF4D: SQLFetchScroll (in /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0)
...
```

Due to the sequence of ODBC calls, and the exact size of the buffer (3576), we knew it was the BYTEA column in our row:

```psql
v_base_pg=# select length(prstntpacked) from v.gusrstns where usrstgusr_userv = 46035;
 length 
--------
   3576
(1 row)
```

Because we use bound buffers that are smaller than that, and we haven't yet come to the point of calling `SQLGetData()`, we know this must be an internal buffer that already knows the size of the BYTEA data. Therefore it couldn't be one of _our_ buffers being too small.

It follows that this looks like the extra NULL terminator byte that so plagues the C world. And sure, the code says:

https://github.com/postgresql-interfaces/psqlodbc/blob/6e99e750163d8cf572d71ea958acc7ef3b561ce5/conv...

# Proposed fix

It seems that immediately after this, the `len_for_wcs_term` is not included in the comparison to assess the need of `realloc()`. If by chance the buffer was already exactly `needbuflen` bytes large, it would not be realloc'd.


https://github.com/postgresql-interfaces/psqlodbc/blob/6e99e750163d8cf572d71ea958acc7ef3b561ce5/conv...

Therefore this PR intends to fix that.

~~We were unable to test this due to time constraints (this is currently impeding our rollout, we have our hands full 🤕!)~~

Help in setting up a psqlodbc compilation and local installation and deployment is welcome.


view thread (8+ messages)  latest in thread

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 #145: SQL_C_BINARY data buffer uses NULL terminator, but realloc() may be missed
  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