bug-grep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug #34917] grep refuses to run when input file is also the output,


From: Jim Meyering
Subject: Re: [bug #34917] grep refuses to run when input file is also the output, even when the -q option is used
Date: Sun, 11 Dec 2011 20:45:15 +0100

Jim Meyering wrote:
> Nicolas Vigier wrote:
>> Follow-up Comment #1, bug #34917 (project grep):
>>
>> Oops, I misunderstood the issue reported on Mageia bugzilla.
>>
>> The issue is a little different :
>> When the -q option is used, there should not be any error output. grep 
>> version
>> 2.10 outputs errors about "input file `./file' is also the output" even when
>> the -q options is used.
>>
>> But not rejecting the command when the -q option is used should also fix 
>> this.
>
> Thanks for forwarding that and for the patch.
> I've added a comment and a proper commit log to your patch, but
> that means you'll have to sign off on the grammar/etc. before I push.
> Please reply here, and not on the savannah tracker.
>
> I'll update NEWS and add a test separately.

I wrote the NEWS entry and tests after realizing that the
new test should be skipped also for other options:

>From c6c22c0bcb2d97e4d6ce39483de568d51dbe4642 Mon Sep 17 00:00:00 2001
From: Nicolas Vigier <address@hidden>
Date: Mon, 28 Nov 2011 15:45:19 +0100
Subject: [PATCH 1/2] do not reject "grep -qr . > out"

The recent fix to avoid an infinite disk-filling loop, commit 5e20a38a,
introduced a minor regression.  If you use grep with -q and -r, and
redirect output to a file that will be traversed, then grep would
reject the command, even though it will generate no output.
In that case, there is no risk of an infinite loop.
* src/main.c (grepfile): Do not reject input == output when
using --quiet/--silent (-q).
Reported by J H Wilson in http://bugs.mageia.org/show_bug.cgi?id=3501
forwarded by Nicolas Vigier to https://savannah.gnu.org/bugs/?34917
---
 src/main.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/main.c b/src/main.c
index c70156f..c81342f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1225,8 +1225,10 @@ grepfile (char const *file, struct stats *stats)
          disk before we open this file, we can end up reading and matching
          those lines and appending them to the file from which we're reading.
          Then we'd have what appears to be an infinite loop that'd terminate
-         only upon filling the output file system or reaching a quota.  */
-      if (S_ISREG (stats->stat.st_mode) && out_stat.st_ino
+         only upon filling the output file system or reaching a quota.
+         However, there is no risk of an infinite loop when we know that
+         grep will generate no output (-q).  */
+      if (!out_quiet && S_ISREG (stats->stat.st_mode) && out_stat.st_ino
           && SAME_REGULAR_FILE (stats->stat, out_stat))
         {
           error (0, 0, _("input file %s is also the output"), quote (file));
--
1.7.8.163.g9859a


>From 2627f049ee29d10a2d145688ce418889ae8b47ed Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Sun, 11 Dec 2011 19:26:38 +0100
Subject: [PATCH 2/2] do not reject input==output also for some other options

* src/main.c (grepfile): Do not reject input == output also
when using a few other options.
* tests/in-eq-out-infloop: Test these new cases.
* NEWS (Bug fixes): Mention it
---
 NEWS                    |   12 ++++++++++++
 src/main.c              |   18 ++++++++++++++----
 tests/in-eq-out-infloop |    9 +++++++++
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/NEWS b/NEWS
index 6bdeb22..5e187f8 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,18 @@ GNU grep NEWS                                    -*- outline 
-*-

 * Noteworthy changes in release ?.? (????-??-??) [?]

+** Bug fixes
+
+  grep no longer rejects "grep -qr . > out", i.e., when run with -q
+  and an input file is the same as the output file, since with -q
+  grep generates no output, so there is no risk of infinite loop or
+  of an output-affecting race condition.  Thus, the use of the following
+  options also disables the input-equals-output failure:
+    --max-count=N (-m) (for N >= 2)
+    --files-with-matches (-l)
+    --files-without-match (-L)
+  [bug introduced in grep-2.10]
+

 * Noteworthy changes in release 2.10 (2011-11-16) [stable]

diff --git a/src/main.c b/src/main.c
index c81342f..afd77c5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1219,16 +1219,26 @@ grepfile (char const *file, struct stats *stats)
                                       || S_ISFIFO (stats->stat.st_mode)))
         return 1;

-      /* If there's a regular file on stdout and the current file refers
+      /* If there is a regular file on stdout and the current file refers
          to the same i-node, we have to report the problem and skip it.
          Otherwise when matching lines from some other input reach the
          disk before we open this file, we can end up reading and matching
          those lines and appending them to the file from which we're reading.
          Then we'd have what appears to be an infinite loop that'd terminate
          only upon filling the output file system or reaching a quota.
-         However, there is no risk of an infinite loop when we know that
-         grep will generate no output (-q).  */
-      if (!out_quiet && S_ISREG (stats->stat.st_mode) && out_stat.st_ino
+         However, there is no risk of an infinite loop if grep is generating
+         no output, i.e., with --silent, --quiet, -q.
+         Similarly, with any of these:
+           --max-count=N (-m) (for N >= 2)
+           --files-with-matches (-l)
+           --files-without-match (-L)
+         there is no risk of trouble.
+         For --max-count=1, grep stops after printing the first match,
+         so there is no risk of malfunction.  But even --max-count=2, with
+         input==output, while there is no risk of infloop, there is a race
+         condition that could result in "alternate" output.  */
+      if (!out_quiet && list_files == 0 && 1 < max_count
+          && S_ISREG (stats->stat.st_mode) && out_stat.st_ino
           && SAME_REGULAR_FILE (stats->stat, out_stat))
         {
           error (0, 0, _("input file %s is also the output"), quote (file));
diff --git a/tests/in-eq-out-infloop b/tests/in-eq-out-infloop
index 726accb..dcb7ac0 100755
--- a/tests/in-eq-out-infloop
+++ b/tests/in-eq-out-infloop
@@ -23,4 +23,13 @@ test $st = 2 || fail=1

 compare err.exp err || fail=1

+# But with each of the following options it must not exit-2.
+for i in -q -m1 -l -L; do
+  timeout 10 grep $i 0 out >> out 2> err; st=$?
+  test $st = 2 && fail=1
+done
+
+timeout 10 grep -2 0 out >> out 2> err; st=$?
+test $st = 2 || fail=1
+
 Exit $fail
--
1.7.8.163.g9859a



reply via email to

[Prev in Thread] Current Thread [Next in Thread]