--- a/.hgsigs Thu Nov 29 09:13:13 2018 +0000
+++ b/.hgsigs Tue Dec 04 17:13:01 2018 -0500
@@ -172,3 +172,4 @@
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
--- a/.hgtags Thu Nov 29 09:13:13 2018 +0000
+++ b/.hgtags Tue Dec 04 17:13:01 2018 -0500
@@ -185,3 +185,4 @@
5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
+1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
--- a/hgext/extdiff.py Thu Nov 29 09:13:13 2018 +0000
+++ b/hgext/extdiff.py Tue Dec 04 17:13:01 2018 -0500
@@ -430,6 +430,7 @@
if args:
cmdline += ' ' + args
command(cmd, extdiffopts[:], _('hg %s [OPTION]... [FILE]...') % cmd,
+ helpcategory=command.CATEGORY_FILE_CONTENTS,
inferrepo=True)(savedcmd(path, cmdline))
# tell hggettext to extract docstrings from these functions:
--- a/hgext/rebase.py Thu Nov 29 09:13:13 2018 +0000
+++ b/hgext/rebase.py Tue Dec 04 17:13:01 2018 -0500
@@ -542,7 +542,7 @@
p1, p2, base = defineparents(repo, rev, self.destmap,
self.state, self.skipped,
self.obsoletenotrebased)
- if len(repo[None].parents()) == 2:
+ if not self.inmemory and len(repo[None].parents()) == 2:
repo.ui.debug('resuming interrupted rebase\n')
else:
overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
@@ -867,7 +867,11 @@
except error.InMemoryMergeConflictsError:
ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
' merge\n'))
- _dorebase(ui, repo, action='abort', opts={})
+ # TODO: Make in-memory merge not use the on-disk merge state, so
+ # we don't have to clean it here
+ mergemod.mergestate.clean(repo)
+ clearstatus(repo)
+ clearcollapsemsg(repo)
return _dorebase(ui, repo, action, opts, inmemory=False)
else:
return _dorebase(ui, repo, action, opts)
--- a/mercurial/cext/revlog.c Thu Nov 29 09:13:13 2018 +0000
+++ b/mercurial/cext/revlog.c Tue Dec 04 17:13:01 2018 -0500
@@ -158,6 +158,12 @@
return (const char *)(self->buf.buf) + pos * v1_hdrsize;
}
+/*
+ * Get parents of the given rev.
+ *
+ * The specified rev must be valid and must not be nullrev. A returned
+ * parent revision may be nullrev, but is guaranteed to be in valid range.
+ */
static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
int maxrev)
{
@@ -180,7 +186,7 @@
}
/* If index file is corrupted, ps[] may point to invalid revisions. So
* there is a risk of buffer overflow to trust them unconditionally. */
- if (ps[0] > maxrev || ps[1] > maxrev) {
+ if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
PyErr_SetString(PyExc_ValueError, "parent out of range");
return -1;
}
@@ -2688,6 +2694,16 @@
int rustlazyancestors_next(rustlazyancestorsObject *self);
int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
+static int index_get_parents_checked(indexObject *self, Py_ssize_t rev, int *ps,
+ int maxrev)
+{
+ if (rev < 0 || rev >= index_length(self)) {
+ PyErr_SetString(PyExc_ValueError, "rev out of range");
+ return -1;
+ }
+ return index_get_parents(self, rev, ps, maxrev);
+}
+
/* CPython instance methods */
static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
{
@@ -2729,7 +2745,8 @@
initrevs, stoprev, inclusive);
if (self->iter == NULL) {
/* if this is because of GraphError::ParentOutOfRange
- * index_get_parents() has already set the proper ValueError */
+ * index_get_parents_checked() has already set the proper
+ * ValueError */
goto bail;
}
--- a/mercurial/commandserver.py Thu Nov 29 09:13:13 2018 +0000
+++ b/mercurial/commandserver.py Tue Dec 04 17:13:01 2018 -0500
@@ -526,7 +526,15 @@
# waiting for recv() will receive ECONNRESET.
self._unlinksocket()
exiting = True
- ready = selector.select(timeout=h.pollinterval)
+ try:
+ ready = selector.select(timeout=h.pollinterval)
+ except OSError as inst:
+ # selectors2 raises ETIMEDOUT if timeout exceeded while
+ # handling signal interrupt. That's probably wrong, but
+ # we can easily get around it.
+ if inst.errno != errno.ETIMEDOUT:
+ raise
+ ready = []
if not ready:
# only exit if we completed all queued requests
if exiting:
--- a/mercurial/context.py Thu Nov 29 09:13:13 2018 +0000
+++ b/mercurial/context.py Tue Dec 04 17:13:01 2018 -0500
@@ -1843,6 +1843,11 @@
else:
return self._wrappedctx[path].flags()
+ def __contains__(self, key):
+ if key in self._cache:
+ return self._cache[key]['exists']
+ return key in self.p1()
+
def _existsinparent(self, path):
try:
# ``commitctx` raises a ``ManifestLookupError`` if a path does not
@@ -1877,19 +1882,19 @@
components = path.split('/')
for i in pycompat.xrange(len(components)):
component = "/".join(components[0:i])
- if component in self.p1() and self._cache[component]['exists']:
+ if component in self:
fail(path, component)
# Test the other direction -- that this path from p2 isn't a directory
- # in p1 (test that p1 doesn't any paths matching `path/*`).
- match = matchmod.match('/', '', [path + '/'], default=b'relpath')
+ # in p1 (test that p1 doesn't have any paths matching `path/*`).
+ match = self.match(pats=[path + '/'], default=b'path')
matches = self.p1().manifest().matches(match)
mfiles = matches.keys()
if len(mfiles) > 0:
if len(mfiles) == 1 and mfiles[0] == path:
return
# omit the files which are deleted in current IMM wctx
- mfiles = [m for m in mfiles if self._cache[m]['exists']]
+ mfiles = [m for m in mfiles if m in self]
if not mfiles:
return
raise error.Abort("error: file '%s' cannot be written because "
--- a/mercurial/thirdparty/selectors2.py Thu Nov 29 09:13:13 2018 +0000
+++ b/mercurial/thirdparty/selectors2.py Tue Dec 04 17:13:01 2018 -0500
@@ -708,7 +708,7 @@
if expires is not None:
current_time = monotonic()
if current_time > expires:
- raise OSError(errno=errno.ETIMEDOUT)
+ raise OSError(errno.ETIMEDOUT, 'Connection timed out')
if recalc_timeout:
if "timeout" in kwargs:
kwargs["timeout"] = expires - current_time
--- a/mercurial/wireprotov2peer.py Thu Nov 29 09:13:13 2018 +0000
+++ b/mercurial/wireprotov2peer.py Tue Dec 04 17:13:01 2018 -0500
@@ -377,25 +377,30 @@
# This can raise. The caller can handle it.
response._onresponsedata(meta['data'])
- # If we got a content redirect response, we want to fetch it and
- # expose the data as if we received it inline. But we also want to
- # keep our internal request accounting in order. Our strategy is to
- # basically put meaningful response handling on pause until EOS occurs
- # and the stream accounting is in a good state. At that point, we follow
- # the redirect and replace the response object with its data.
+ # We need to be careful about resolving futures prematurely. If a
+ # response is a redirect response, resolving the future before the
+ # redirect is processed would result in the consumer seeing an
+ # empty stream of objects, since they'd be consuming our
+ # response.objects() instead of the redirect's response.objects().
+ #
+ # Our strategy is to not resolve/finish the request until either
+ # EOS occurs or until the initial response object is fully received.
- redirect = response._redirect
- handlefuture = False if redirect else True
-
+ # Always react to eos.
if meta['eos']:
response._oninputcomplete()
del self._requests[frame.requestid]
- if redirect:
- self._followredirect(frame.requestid, redirect)
- return
+ # Not EOS but we haven't decoded the initial response object yet.
+ # Return and wait for more data.
+ elif not response._seeninitial:
+ return
- if not handlefuture:
+ # The specification says no objects should follow the initial/redirect
+ # object. So it should be safe to handle the redirect object if one is
+ # decoded, without having to wait for EOS.
+ if response._redirect:
+ self._followredirect(frame.requestid, response._redirect)
return
# If the command has a decoder, we wait until all input has been
@@ -458,7 +463,10 @@
self._redirects.append((requestid, res))
def _processredirect(self, rid, res):
- """Called to continue processing a response from a redirect."""
+ """Called to continue processing a response from a redirect.
+
+ Returns a bool indicating if the redirect is still serviceable.
+ """
response = self._responses[rid]
try:
@@ -470,7 +478,7 @@
response._oninputcomplete()
if rid not in self._futures:
- return
+ return bool(data)
if response.command not in COMMAND_DECODERS:
self._futures[rid].set_result(response.objects())
--- a/tests/test-fuzz-targets.t Thu Nov 29 09:13:13 2018 +0000
+++ b/tests/test-fuzz-targets.t Tue Dec 04 17:13:01 2018 -0500
@@ -2,11 +2,36 @@
$ cd $TESTDIR/../contrib/fuzz
+which(1) could exit nonzero, but that's fine because we'll still end
+up without a valid executable, so we don't need to check $? here.
+
+ $ if which gmake >/dev/null 2>&1; then
+ > MAKE=gmake
+ > else
+ > MAKE=make
+ > fi
+
+ $ havefuzz() {
+ > cat > $TESTTMP/dummy.cc <<EOF
+ > #include <stdlib.h>
+ > #include <stdint.h>
+ > int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
+ > int main(int argc, char **argv) {
+ > const char data[] = "asdf";
+ > return LLVMFuzzerTestOneInput((const uint8_t *)data, 4);
+ > }
+ > EOF
+ > $CXX $TESTTMP/dummy.cc -o $TESTTMP/dummy \
+ > -fsanitize=fuzzer-no-link,address || return 1
+ > }
+
#if clang-libfuzzer
- $ make -s clean all
+ $ CXX=clang++ havefuzz || exit 80
+ $ $MAKE -s clean all
#endif
#if no-clang-libfuzzer clang-6.0
- $ make -s clean all CC=clang-6.0 CXX=clang++-6.0
+ $ CXX=clang++-6.0 havefuzz || exit 80
+ $ $MAKE -s clean all CC=clang-6.0 CXX=clang++-6.0
#endif
#if no-clang-libfuzzer no-clang-6.0
$ exit 80
--- a/tests/test-parseindex.t Thu Nov 29 09:13:13 2018 +0000
+++ b/tests/test-parseindex.t Tue Dec 04 17:13:01 2018 -0500
@@ -133,12 +133,18 @@
$ cd invalidparent
$ hg clone --pull -q --config phases.publish=False ../a limit
+ $ hg clone --pull -q --config phases.publish=False ../a neglimit
$ hg clone --pull -q --config phases.publish=False ../a segv
- $ rm -R limit/.hg/cache segv/.hg/cache
+ $ rm -R limit/.hg/cache neglimit/.hg/cache segv/.hg/cache
$ "$PYTHON" <<EOF
> data = open("limit/.hg/store/00changelog.i", "rb").read()
- > for n, p in [(b'limit', b'\0\0\0\x02'), (b'segv', b'\0\x01\0\0')]:
+ > poisons = [
+ > (b'limit', b'\0\0\0\x02'),
+ > (b'neglimit', b'\xff\xff\xff\xfe'),
+ > (b'segv', b'\0\x01\0\0'),
+ > ]
+ > for n, p in poisons:
> # corrupt p1 at rev0 and p2 at rev1
> d = data[:24] + p + data[28:127 + 28] + p + data[127 + 32:]
> open(n + b"/.hg/store/00changelog.i", "wb").write(d)
@@ -154,6 +160,11 @@
0 1 1 -1 base 63 62 63 1.01613 63 0 0.00000
1 2 1 -1 base 66 65 66 1.01538 66 0 0.00000
+ $ hg -R neglimit debugrevlogindex -f1 -c
+ rev flag size link p1 p2 nodeid
+ 0 0000 62 0 -2 -1 7c31755bf9b5
+ 1 0000 65 1 0 -2 26333235a41c
+
$ hg -R segv debugrevlogindex -f1 -c
rev flag size link p1 p2 nodeid
0 0000 62 0 65536 -1 7c31755bf9b5
@@ -193,6 +204,12 @@
index_headrevs: parent out of range
find_gca_candidates: parent out of range
find_deepest: parent out of range
+ $ "$PYTHON" test.py neglimit/.hg/store
+ reachableroots: parent out of range
+ compute_phases_map_sets: parent out of range
+ index_headrevs: parent out of range
+ find_gca_candidates: parent out of range
+ find_deepest: parent out of range
$ "$PYTHON" test.py segv/.hg/store
reachableroots: parent out of range
compute_phases_map_sets: parent out of range
--- a/tests/test-rebase-inmemory.t Thu Nov 29 09:13:13 2018 +0000
+++ b/tests/test-rebase-inmemory.t Tue Dec 04 17:13:01 2018 -0500
@@ -1,5 +1,7 @@
#require symlink execbit
$ cat << EOF >> $HGRCPATH
+ > [phases]
+ > publish=False
> [extensions]
> amend=
> rebase=
@@ -54,6 +56,7 @@
b (no-eol)
$ hg cat -r 2 c
c (no-eol)
+ $ cd ..
Case 2:
$ hg init repo2
@@ -177,7 +180,7 @@
$ hg rebase -r . -d 2
rebasing 4:daf7dfc139cb "a/a" (tip)
- saved backup bundle to $TESTTMP/repo1/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
+ saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
$ hg tglog
@ 4: c6ad37a4f250 'a/a'
@@ -218,7 +221,7 @@
$ hg rebase -r . -d 5
rebasing 7:855e9797387e "added a back!" (tip)
- saved backup bundle to $TESTTMP/repo1/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
+ saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
$ hg tglog
@ 7: bb3f02be2688 'added a back!'
@@ -237,9 +240,48 @@
|/
o 0: b173517d0057 'a'
+ $ mkdir c
+ $ echo c > c/c
+ $ hg add c/c
+ $ hg ci -m 'c/c'
+ $ hg rebase -r . -d 3 -n
+ starting dry-run rebase; repository will not be changed
+ rebasing 8:755f0104af9b "c/c" (tip)
+ abort: error: 'c/c' conflicts with file 'c' in 3.
+ [255]
+ $ hg rebase -r 3 -d . -n
+ starting dry-run rebase; repository will not be changed
+ rebasing 3:844a7de3e617 "c"
+ abort: error: file 'c' cannot be written because 'c/' is a folder in 755f0104af9b (containing 1 entries: c/c)
+ [255]
$ cd ..
+Test path auditing (issue5818)
+
+ $ mkdir lib_
+ $ ln -s lib_ lib
+ $ hg init repo
+ $ cd repo
+ $ mkdir -p ".$TESTTMP/lib"
+ $ touch ".$TESTTMP/lib/a"
+ $ hg add ".$TESTTMP/lib/a"
+ $ hg ci -m 'a'
+
+ $ touch ".$TESTTMP/lib/b"
+ $ hg add ".$TESTTMP/lib/b"
+ $ hg ci -m 'b'
+
+ $ hg up -q '.^'
+ $ touch ".$TESTTMP/lib/c"
+ $ hg add ".$TESTTMP/lib/c"
+ $ hg ci -m 'c'
+ created new head
+ $ hg rebase -s 1 -d .
+ rebasing 1:* "b" (glob)
+ saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-rebase.hg (glob)
+ $ cd ..
+
Test dry-run rebasing
$ hg init repo3
@@ -420,7 +462,6 @@
transaction abort!
rollback completed
hit merge conflicts; re-running rebase without in-memory merge
- rebase aborted
rebasing 2:177f92b77385 "c"
rebasing 3:055a42cdd887 "d"
rebasing 4:e860deea161a "e"
@@ -428,6 +469,46 @@
warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
unresolved conflicts (see hg resolve, then hg rebase --continue)
[1]
+ $ hg rebase --abort
+ saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/c1e524d4287c-f91f82e1-backup.hg
+ rebase aborted
+
+Retrying without in-memory merge won't lose working copy changes
+ $ cd ..
+ $ hg clone repo3 repo3-dirty -q
+ $ cd repo3-dirty
+ $ echo dirty > a
+ $ hg rebase -s 2 -d 7
+ rebasing 2:177f92b77385 "c"
+ rebasing 3:055a42cdd887 "d"
+ rebasing 4:e860deea161a "e"
+ merging e
+ transaction abort!
+ rollback completed
+ hit merge conflicts; re-running rebase without in-memory merge
+ abort: uncommitted changes
+ [255]
+ $ cat a
+ dirty
+
+Retrying without in-memory merge won't lose merge state
+ $ cd ..
+ $ hg clone repo3 repo3-merge-state -q
+ $ cd repo3-merge-state
+ $ hg merge 4
+ merging e
+ warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
+ 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
+ [1]
+ $ hg resolve -l
+ U e
+ $ hg rebase -s 2 -d 7
+ rebasing 2:177f92b77385 "c"
+ abort: outstanding merge conflicts
+ [255]
+ $ hg resolve -l
+ U e
==========================
Test for --confirm option|