debug: Fix read error handling in pcprofiledump

The reading loops did not check for read failures.  Addresses
a static analysis report.

Manually tested by compiling a program with the GCC's
-finstrument-functions option, running it with
“LD_PRELOAD=debug/libpcprofile.so PCPROFILE_OUTPUT=output-file”,
and reviewing the output of “debug/pcprofiledump output-file”.
This commit is contained in:
Florian Weimer 2024-09-10 12:40:27 +02:00
parent e82a7cb162
commit 89b088bf70

View File

@ -75,6 +75,44 @@ static struct argp argp =
options, parse_opt, args_doc, doc, NULL, more_help options, parse_opt, args_doc, doc, NULL, more_help
}; };
/* Try to read SIZE bytes from FD and store them on BUF. Terminate
the process upon read error. Also terminate the process if less
than SIZE bytes are remaining in the file. If !IN_HEADER, do not
terminate the process if the end of the file is encountered
immediately, before any bytes are read.
Returns true if SIZE bytes have been read, and false if no bytes
have been read due to an end-of-file condition. */
static bool
read_exactly (int fd, void *buffer, size_t size, bool in_header)
{
char *p = buffer;
char *end = p + size;
while (p < end)
{
ssize_t ret = TEMP_FAILURE_RETRY (read (fd, p, end - p));
if (ret < 0)
{
if (in_header)
error (EXIT_FAILURE, errno, _("cannot read header"));
else
error (EXIT_FAILURE, errno, _("cannot read pointer pair"));
}
if (ret == 0)
{
if (p == buffer && !in_header)
/* Nothing has been read. */
return false;
if (in_header)
error (EXIT_FAILURE, 0, _("unexpected end of file in header"));
else
error (EXIT_FAILURE, 0,
_("unexpected end of file in pointer pair"));
}
p += ret;
}
return true;
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
@ -110,8 +148,7 @@ main (int argc, char *argv[])
/* Read the first 4-byte word. It contains the information about /* Read the first 4-byte word. It contains the information about
the word size and the endianness. */ the word size and the endianness. */
uint32_t word; uint32_t word;
if (TEMP_FAILURE_RETRY (read (fd, &word, 4)) != 4) read_exactly (fd, &word, sizeof (word), true);
error (EXIT_FAILURE, errno, _("cannot read header"));
/* Check whether we have to swap the byte order. */ /* Check whether we have to swap the byte order. */
int must_swap = (word & 0x0fffffff) == bswap_32 (0xdeb00000); int must_swap = (word & 0x0fffffff) == bswap_32 (0xdeb00000);
@ -120,57 +157,31 @@ main (int argc, char *argv[])
/* We have two loops, one for 32 bit pointers, one for 64 bit pointers. */ /* We have two loops, one for 32 bit pointers, one for 64 bit pointers. */
if (word == 0xdeb00004) if (word == 0xdeb00004)
{
union
{ {
uint32_t ptrs[2]; uint32_t ptrs[2];
char bytes[8];
} pair;
while (1) while (1)
{ {
size_t len = sizeof (pair); if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
size_t n;
while (len > 0
&& (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
len))) != 0)
len -= n;
if (len != 0)
/* Nothing to read. */
break; break;
printf ("this = %#010" PRIx32 ", caller = %#010" PRIx32 "\n", printf ("this = %#010" PRIx32 ", caller = %#010" PRIx32 "\n",
must_swap ? bswap_32 (pair.ptrs[0]) : pair.ptrs[0], must_swap ? bswap_32 (ptrs[0]) : ptrs[0],
must_swap ? bswap_32 (pair.ptrs[1]) : pair.ptrs[1]); must_swap ? bswap_32 (ptrs[1]) : ptrs[1]);
} }
} }
else if (word == 0xdeb00008) else if (word == 0xdeb00008)
{
union
{ {
uint64_t ptrs[2]; uint64_t ptrs[2];
char bytes[16];
} pair;
while (1) while (1)
{ {
size_t len = sizeof (pair); if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
size_t n;
while (len > 0
&& (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
len))) != 0)
len -= n;
if (len != 0)
/* Nothing to read. */
break; break;
printf ("this = %#018" PRIx64 ", caller = %#018" PRIx64 "\n", printf ("this = %#018" PRIx64 ", caller = %#018" PRIx64 "\n",
must_swap ? bswap_64 (pair.ptrs[0]) : pair.ptrs[0], must_swap ? bswap_64 (ptrs[0]) : ptrs[0],
must_swap ? bswap_64 (pair.ptrs[1]) : pair.ptrs[1]); must_swap ? bswap_64 (ptrs[1]) : ptrs[1]);
} }
} }
else else