commit ff1096a0c24c3a302a58864392270e6622e21a03 Author: Paul Eggert Date: Wed Jun 21 11:19:13 2023 -0700 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. diff --git a/NEWS b/NEWS index 0b7cf48..00ee5b6 100644 --- a/NEWS +++ b/NEWS @@ -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] diff --git a/src/cmp.c b/src/cmp.c index 4bf0a4c..936125c 100644 --- a/src/cmp.c +++ b/src/cmp.c @@ -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 (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) diff --git a/tests/brief-vs-stat-zero-kernel-lies b/tests/brief-vs-stat-zero-kernel-lies index 82b33e6..7cc2dc7 100755 --- a/tests/brief-vs-stat-zero-kernel-lies +++ b/tests/brief-vs-stat-zero-kernel-lies @@ -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