On 29/06/2026 15:04, Peter Eisentraut wrote:
Here is a patch series to clean up the use of size_t and ssize_t with
POSIX file system APIs (read, write, etc.) and the APIs that PostgreSQL
has built on top.
Most newer code already did this correctly, but some older code did not
and mostly used int or some other randomness. Which also sometimes
leads to odd back-and-forth at different API layers.
Aside from consistency and basic correctness, this also helps in other
ways.
It makes error messages more consistent. Consider the current potpourri
like
read %d of %d
read %d of %lld
read %d of %u
read %d of %zu
read %lld of %lld
read %zd of %lld
read %zd of %zu
read %zu of %zu
Once we get all of this aligned better, there might also be some
opportunities to refactor some repeated combinations like read/write +
error checking + pgstat report.
Another advantage of correctly using size_t instead of int is that you
don't have to wonder whether a negative value might be passed and what
to do with it.
Also, of course, we do want to actually support large files in some
situations. I don't think it currently matters in practice for the
places I changed here, but it might in the future, or if this code gets
expanded or copied around.
Some patches have some additional details that are noted in the commit
messages, but most of it is relatively straightforward replacement and
some cosmetic adjustments.
(Note: There are similar issues with network functions recv()/send(),
but there are weird complications related to Windows, different API
wrappers in used for frontends and backends, so I left those out for now.)
The patches related to casts of pgoff_t are included here (0002 and
0003) here because they are prerequisites, but there is a separate
thread for those at [0].
[0]: https://www.postgresql.org/message-id/20ce62fa-47fc-457b-
b504-12f3c1651726%40eisentraut.org
I skimmed through all these patches (phew!), and it all looks good to
me. Only this one little thing caught my eye:
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index b5433a75d12..85ded4c0e2b 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -317,11 +317,12 @@ readfile(const char *path, int *numlines)
int fd;
int nlines;
char **result;
+ size_t buflen;
char *buffer;
char *linebegin;
int i;
int n;
- int len;
+ ssize_t nread;
struct stat statbuf;
*numlines = 0; /* in case of failure or empty file */
@@ -367,7 +370,7 @@ readfile(const char *path, int *numlines)
* any characters after the last newline will be ignored.
*/
nlines = 0;
- for (i = 0; i < len; i++)
+ for (i = 0; i < nread; i++)
{
if (buffer[i] == '\n')
nlines++;
@@ -380,7 +383,7 @@ readfile(const char *path, int *numlines)
/* now split the buffer into lines */
linebegin = buffer;
n = 0;
- for (i = 0; i < len; i++)
+ for (i = 0; i < nread; i++)
{
if (buffer[i] == '\n')
{
Should probably change the 'i' into size_t as well, since it's compared
with 'nread'. And 'nlines' too, to be pendantic, so that it doesn't
overflow if you have a 10 GB file full of newlines..
As a sanity check though, it'd probably make sense to check that the
file is not larger than a few kB or so. This is used to read the pid
file and postmaster.opts file, neither of which is expected to be large.
- Heikki