From d2d684901b10686c5cc4b98219fdd2300683a689 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Mon, 16 Jun 2025 17:28:35 +0200 Subject: [PATCH] pg_dump: Handle errors in reading ZStd streams The read_func API is defined to always return true with errors during reading generating a pg_fatal. The ZStd code was however not checking if 0 returned from fread was due to error or an EOF, which would mask errors as EOF. Also fix all internal callers to correctly use the API and not check the returnvalue. Reported-by: Evgeniy Gorbanev Discussion: https://postgr.es/m/6b9817a8-88ec-4efd-b441-9e2a0439c6b8@basealt.ru --- src/bin/pg_dump/compress_zstd.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/bin/pg_dump/compress_zstd.c b/src/bin/pg_dump/compress_zstd.c index cb595b10c2d..9e79619c955 100644 --- a/src/bin/pg_dump/compress_zstd.c +++ b/src/bin/pg_dump/compress_zstd.c @@ -272,6 +272,13 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH) output->dst = ptr; output->pos = 0; + /* + * Clear the error/eof flag before calling fread so that we can inspect + * for errors after reading. This also protects reading against fread + * implementations which won't read when set. + */ + clearerr(zstdcs->fp); + for (;;) { Assert(input->pos <= input->size); @@ -296,9 +303,15 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH) Assert(cnt <= input_allocated_size); - /* If we have no more input to consume, we're done */ + /* check if the returned zero is due to EOF or an error */ if (cnt == 0) + { + if (ferror(zstdcs->fp)) + pg_fatal("could not read from input file: %m"); + + /* If we have no more input to consume, we're done */ break; + } } while (input->pos < input->size) @@ -366,8 +379,15 @@ Zstd_getc(CompressFileHandle *CFH) { ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data; int ret; + size_t readsz; - if (CFH->read_func(&ret, 1, NULL, CFH) != 1) + CFH->read_func(&ret, 1, &readsz, CFH); + + /* + * read_func will throw an error on ferror but not feof, but getc_func is + * defined to throw an error on EOF so we need to test that here. + */ + if (readsz == 0) { if (feof(zstdcs->fp)) pg_fatal("could not read from input file: end of file"); @@ -392,8 +412,8 @@ Zstd_gets(char *buf, int len, CompressFileHandle *CFH) { size_t readsz; - if (!CFH->read_func(&buf[i], 1, &readsz, CFH)) - break; + CFH->read_func(&buf[i], 1, &readsz, CFH); + if (readsz != 1) break; if (buf[i] == '\n') -- 2.39.3 (Apple Git-146)