[PATCH 3 of 3 STABLE] patch: fix fuzzing of hunks without previous lines (issue3264)

Patrick Mezard patrick at mezard.eu
Mon Feb 13 10:02:09 CST 2012


# HG changeset patch
# User Patrick Mezard <patrick at mezard.eu>
# Date 1329148051 -3600
# Branch stable
# Node ID 3a4855a08072bd2ca2b3ed8a60fad0c21488f1f7
# Parent  8711986a875ff4b529073090f81c60d6e868154a
patch: fix fuzzing of hunks without previous lines (issue3264)

When applying hunks such as:

  @@ -2,1 +2,2 @@
   context
  +change

fuzzing would empty the "old" block and make patchfile.apply() traceback.
Instead, we apply the new block at specified location without testing.

The "bottom hunk" test was removed as patch(1) has no problem applying hunk
with no context in the middle of a file.

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -742,20 +742,21 @@
         self.hash = {}
         for x, s in enumerate(self.lines):
             self.hash.setdefault(s, []).append(x)
-        if h.hunk[-1][0] != ' ':
-            # if the hunk tried to put something at the bottom of the file
-            # override the start line and use eof here
-            search_start = len(self.lines)
-        else:
-            search_start = orig_start + self.skew
 
         for fuzzlen in xrange(3):
             for toponly in [True, False]:
                 old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly)
+                oldstart = oldstart + self.offset + self.skew
+                oldstart = min(oldstart, len(self.lines))
+                if old:
+                    cand = self.findlines(old[0][1:], oldstart)
+                else:
+                    # Only adding lines with no or fuzzed context, just
+                    # take the skew in account
+                    cand = [oldstart]
 
-                cand = self.findlines(old[0][1:], search_start)
                 for l in cand:
-                    if diffhelpers.testhunk(old, self.lines, l) == 0:
+                    if not old or diffhelpers.testhunk(old, self.lines, l) == 0:
                         self.lines[l : l + len(old)] = new
                         self.offset += len(new) - len(old)
                         self.skew = l - orig_start
diff --git a/tests/test-import.t b/tests/test-import.t
--- a/tests/test-import.t
+++ b/tests/test-import.t
@@ -998,3 +998,79 @@
   c2
   c3
   c4
+
+Test corner case involving fuzz and skew
+
+  $ hg init morecornercases
+  $ cd morecornercases
+
+  $ cat > 01-no-context-beginning-of-file.diff <<EOF
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,0 +1,1 @@
+  > +line
+  > EOF
+
+  $ cat > 02-no-context-middle-of-file.diff <<EOF
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,1 @@
+  > -2
+  > +add some skew
+  > @@ -2,0 +2,1 @@
+  > +line
+  > EOF
+
+  $ cat > 03-no-context-end-of-file.diff <<EOF
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -10,0 +10,1 @@
+  > +line
+  > EOF
+
+  $ cat > a <<EOF
+  > 1
+  > 2
+  > 3
+  > 4
+  > EOF
+  $ hg ci -Am adda a
+  $ for p in *.diff; do
+  >   hg import -v --no-commit $p
+  >   cat a
+  >   hg revert -aqC a
+  >   # patch -p1 < $p
+  >   # cat a
+  >   # hg revert -aC a
+  > done
+  applying 01-no-context-beginning-of-file.diff
+  patching file a
+  applied to working directory
+  1
+  line
+  2
+  3
+  4
+  applying 02-no-context-middle-of-file.diff
+  patching file a
+  Hunk #1 succeeded at 2 (offset 1 lines).
+  Hunk #2 succeeded at 4 (offset 1 lines).
+  applied to working directory
+  1
+  add some skew
+  3
+  line
+  4
+  applying 03-no-context-end-of-file.diff
+  patching file a
+  Hunk #1 succeeded at 5 (offset -6 lines).
+  applied to working directory
+  1
+  2
+  3
+  4
+  line
+


More information about the Mercurial-devel mailing list