cmp: fix -s bug when comparing /proc files

* NEWS: Mention this.
* src/cmp.c (main, cmp): Do not trust st_size == 0, as it may
be a /proc file.
* tests/brief-vs-stat-zero-kernel-lies: Also test cmp -s.
This commit is contained in:
Paul Eggert 2023-06-21 11:19:13 -07:00
parent 77722b5c59
commit ff1096a0c2
3 changed files with 16 additions and 4 deletions

6
NEWS
View File

@ -10,6 +10,12 @@ GNU diffutils NEWS -*- outline -*-
cmp/diff can again work with file dates past Y2K38
[bug introduced in 3.9]
cmp -s no longer mishandles /proc files, for which the Linux kernel
reports a zero size even when nonempty. For example, the following
shell command now outputs nothing, as it should:
cp /proc/cmdline t; cmp -s /proc/cmdline t || echo files differ
[bug present since "the beginning"]
diff -D no longer fails to output #ifndef lines.
[bug#61193 introduced in 3.9]

View File

@ -338,13 +338,14 @@ main (int argc, char **argv)
}
/* If only a return code is needed,
and if both input descriptors are associated with plain files,
and both input descriptors are associated with plain files,
and the file sizes are nonzero so they are not Linux /proc files,
conclude that the files differ if they have different sizes
and if more bytes will be compared than are in the smaller file. */
if (comparison_type == type_status
&& 0 <= stat_buf[0].st_size && S_ISREG (stat_buf[0].st_mode)
&& 0 <= stat_buf[1].st_size && S_ISREG (stat_buf[1].st_mode))
&& 0 < stat_buf[0].st_size && S_ISREG (stat_buf[0].st_mode)
&& 0 < stat_buf[1].st_size && S_ISREG (stat_buf[1].st_mode))
{
off_t s0 = stat_buf[0].st_size - file_position (0);
off_t s1 = stat_buf[1].st_size - file_position (1);
@ -401,7 +402,7 @@ cmp (void)
? bytes : TYPE_MAXIMUM (off_t));
for (int f = 0; f < 2; f++)
if (0 <= stat_buf[f].st_size && S_ISREG (stat_buf[f].st_mode))
if (0 < stat_buf[f].st_size && S_ISREG (stat_buf[f].st_mode))
{
off_t file_bytes = stat_buf[f].st_size - file_position (f);
if (file_bytes < byte_number_max)

View File

@ -35,4 +35,9 @@ printf 'diff\0--brief\0/proc/self/cmdline\0bin\0' > bin || framework_failure_
diff --brief /proc/self/cmdline bin > out 2>&1 || fail=1
compare /dev/null out || fail=1
# Similarly for cmp -s.
printf 'cmp\0-s\0/proc/self/cmdline\0bin\0' > bin || framework_failure_
cmp -s /proc/self/cmdline bin > out 2>&1 || fail=1
compare /dev/null out || fail=1
Exit $fail