From: William Baker via GitGitGadget <hidden> Date: 2019-10-03 19:49:58
This patch series fixes a segfault that I encountered while testing
fsmonitor. Under some circumstances, the fsmonitor extension was being
written with too many bits, and subsequent git commands would segfault when
trying to apply the bits to the index.
As part of these changes I've added some BUG checks that would have helped
catch this problem sooner. Special thanks to Dscho for pointing me in the
right direction and suggesting a test that can reproduce the issue.
Thanks, William
William Baker (1):
fsmonitor: don't fill bitmap with entries to be removed
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 12 ++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 60 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
base-commit: 5fa0f5238b0cd46cfe7f6fa76c3f526ea98148d9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-372%2Fwilbaker%2Ffix_git_fsmonitor_crash-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-372/wilbaker/fix_git_fsmonitor_crash-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/372
--
gitgitgadget
From: William Baker via GitGitGadget <hidden> Date: 2019-10-03 19:50:02
From: William Baker <redacted>
While doing some testing with fsmonitor enabled I found
that git commands would segfault after staging and
unstaging an untracked file. Looking at the crash it
appeared that fsmonitor_ewah_callback was attempting to
adjust bits beyond the bounds of the index cache.
Digging into how this could happen it became clear that
the fsmonitor extension must have been written with
more bits than there were entries in the index. The
root cause ended up being that fill_fsmonitor_bitmap was
populating fsmonitor_dirty with bits for all entries in
the index, even those that had been marked for removal.
To solve this problem fill_fsmonitor_bitmap has been
updated to skip entries with the the CE_REMOVE flag set.
With this change the bits written for the fsmonitor
extension will be consistent with the index entries
written by do_write_index. Additionally, BUG checks
have been added to detect if the number of bits in
fsmonitor_dirty should ever exceed the number of
entries in the index again.
Another option that was considered was moving the call
to fill_fsmonitor_bitmap closer to where the index is
written (and where the fsmonitor extension itself is
written). However, that did not work as the
fsmonitor_dirty bitmap must be filled before the index
is split during writing.
Signed-off-by: William Baker <redacted>
---
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 12 ++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 60 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
@@ -14,8 +14,13 @@ struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);staticvoidfsmonitor_ewah_callback(size_tpos,void*is){structindex_state*istate=(structindex_state*)is;-structcache_entry*ce=istate->cache[pos];+structcache_entry*ce;++if(pos>=istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %"PRIuMAX")",+(uintmax_t)pos,(uintmax_t)istate->cache_nr);+ce=istate->cache[pos];ce->ce_flags&=~CE_FSMONITOR_VALID;}
@@ -50,17 +55,24 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,}istate->fsmonitor_dirty=fsmonitor_dirty;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",+(uintmax_t)istate->fsmonitor_dirty->bit_size,(uintmax_t)istate->cache_nr);+trace_printf_key(&trace_fsmonitor,"read fsmonitor extension successful");return0;}voidfill_fsmonitor_bitmap(structindex_state*istate){-unsignedinti;+unsignedinti,skipped=0;istate->fsmonitor_dirty=ewah_new();-for(i=0;i<istate->cache_nr;i++)-if(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))-ewah_set(istate->fsmonitor_dirty,i);+for(i=0;i<istate->cache_nr;i++){+if(istate->cache[i]->ce_flags&CE_REMOVE)+skipped++;+elseif(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))+ewah_set(istate->fsmonitor_dirty,i-skipped);+}}voidwrite_fsmonitor_extension(structstrbuf*sb,structindex_state*istate)
@@ -71,6 +83,10 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)uint32_tewah_size=0;intfixup=0;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",+(uintmax_t)istate->fsmonitor_dirty->bit_size,(uintmax_t)istate->cache_nr);+put_be32(&hdr_version,INDEX_EXTENSION_VERSION);strbuf_add(sb,&hdr_version,sizeof(uint32_t));
@@ -236,6 +252,9 @@ void tweak_fsmonitor(struct index_state *istate)}/* Mark all previously saved entries as dirty */+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",+(uintmax_t)istate->fsmonitor_dirty->bit_size,(uintmax_t)istate->cache_nr);ewah_each_bit(istate->fsmonitor_dirty,fsmonitor_ewah_callback,istate);/* Now mark the untracked cache for fsmonitor usage */
@@ -354,4 +354,16 @@ test_expect_success 'discard_index() also discards fsmonitor info' 'test_cmpexpectactual'+# Use test files that start with 'z' so that the entries being added+# and removed appear at the end of the index.+test_expect_success'status succeeds after staging/unstaging ''+test_commitinitial&&+removed=$(test_seq1100|sed"s/^/z/")&&+touch$removed&&+gitadd$removed&&+test_configcore.fsmonitor"$TEST_DIRECTORY/t7519/fsmonitor-env"&&+FSMONITOR_LIST="$removed"gitrestore-S$removed&&+FSMONITOR_LIST="$removed"gitstatus+'+ test_done
@@ -0,0 +1,24 @@+#!/bin/sh+#+# An test hook script to integrate with git to test fsmonitor.+#+# The hook is passed a version (currently 1) and a time in nanoseconds+# formatted as a string and outputs to stdout all files that have been+# modified since the given time. Paths must be relative to the root of+# the working tree and separated by a single NUL.+#+#echo "$0 $*" >&2++if test "$#" -ne 2+then+ echo "$0: exactly 2 arguments expected" >&2+ exit 2+fi++if test "$1" != 1+then+ echo "Unsupported core.fsmonitor hook version." >&2+ exit 1+fi++printf '%s\n' $FSMONITOR_LIST
From: Johannes Schindelin <hidden> Date: 2019-10-03 21:08:48
Hi all,
On Thu, 3 Oct 2019, William Baker via GitGitGadget wrote:
This patch series fixes a segfault that I encountered while testing
fsmonitor. Under some circumstances, the fsmonitor extension was being
written with too many bits, and subsequent git commands would segfault when
trying to apply the bits to the index.
As part of these changes I've added some BUG checks that would have helped
catch this problem sooner. Special thanks to Dscho for pointing me in the
right direction and suggesting a test that can reproduce the issue.
Thanks, William
Please note that I was involved with the development of this patch,
reviewed a couple of iterations internally and am implictly okay with
this first public iteration.
Ciao,
Dscho
From: William Baker via GitGitGadget <hidden> Date: 2019-10-09 21:00:18
From: William Baker <redacted>
While doing some testing with fsmonitor enabled I found
that git commands would segfault after staging and
unstaging an untracked file. Looking at the crash it
appeared that fsmonitor_ewah_callback was attempting to
adjust bits beyond the bounds of the index cache.
Digging into how this could happen it became clear that
the fsmonitor extension must have been written with
more bits than there were entries in the index. The
root cause ended up being that fill_fsmonitor_bitmap was
populating fsmonitor_dirty with bits for all entries in
the index, even those that had been marked for removal.
To solve this problem fill_fsmonitor_bitmap has been
updated to skip entries with the the CE_REMOVE flag set.
With this change the bits written for the fsmonitor
extension will be consistent with the index entries
written by do_write_index. Additionally, BUG checks
have been added to detect if the number of bits in
fsmonitor_dirty should ever exceed the number of
entries in the index again.
Another option that was considered was moving the call
to fill_fsmonitor_bitmap closer to where the index is
written (and where the fsmonitor extension itself is
written). However, that did not work as the
fsmonitor_dirty bitmap must be filled before the index
is split during writing.
Signed-off-by: William Baker <redacted>
---
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 13 +++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 61 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
@@ -14,8 +14,13 @@ struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);staticvoidfsmonitor_ewah_callback(size_tpos,void*is){structindex_state*istate=(structindex_state*)is;-structcache_entry*ce=istate->cache[pos];+structcache_entry*ce;++if(pos>=istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)",+(uintmax_t)pos,istate->cache_nr);+ce=istate->cache[pos];ce->ce_flags&=~CE_FSMONITOR_VALID;}
@@ -50,17 +55,24 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,}istate->fsmonitor_dirty=fsmonitor_dirty;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);+trace_printf_key(&trace_fsmonitor,"read fsmonitor extension successful");return0;}voidfill_fsmonitor_bitmap(structindex_state*istate){-unsignedinti;+unsignedinti,skipped=0;istate->fsmonitor_dirty=ewah_new();-for(i=0;i<istate->cache_nr;i++)-if(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))-ewah_set(istate->fsmonitor_dirty,i);+for(i=0;i<istate->cache_nr;i++){+if(istate->cache[i]->ce_flags&CE_REMOVE)+skipped++;+elseif(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))+ewah_set(istate->fsmonitor_dirty,i-skipped);+}}voidwrite_fsmonitor_extension(structstrbuf*sb,structindex_state*istate)
@@ -71,6 +83,10 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)uint32_tewah_size=0;intfixup=0;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);+put_be32(&hdr_version,INDEX_EXTENSION_VERSION);strbuf_add(sb,&hdr_version,sizeof(uint32_t));
@@ -236,6 +252,9 @@ void tweak_fsmonitor(struct index_state *istate)}/* Mark all previously saved entries as dirty */+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);ewah_each_bit(istate->fsmonitor_dirty,fsmonitor_ewah_callback,istate);/* Now mark the untracked cache for fsmonitor usage */
@@ -354,4 +354,17 @@ test_expect_success 'discard_index() also discards fsmonitor info' 'test_cmpexpectactual'+# This test covers staging/unstaging files that appear at the end of the index.+# Test files with names beginning with 'z' are used under the assumption that+# earlier tests do not add/leave index entries that sort below them. +test_expect_success'status succeeds after staging/unstaging ''+test_commitinitial&&+removed=$(test_seq1100|sed"s/^/z/")&&+touch$removed&&+gitadd$removed&&+test_configcore.fsmonitor"$TEST_DIRECTORY/t7519/fsmonitor-env"&&+FSMONITOR_LIST="$removed"gitrestore-S$removed&&+FSMONITOR_LIST="$removed"gitstatus+'+ test_done
@@ -0,0 +1,24 @@+#!/bin/sh+#+# An test hook script to integrate with git to test fsmonitor.+#+# The hook is passed a version (currently 1) and a time in nanoseconds+# formatted as a string and outputs to stdout all files that have been+# modified since the given time. Paths must be relative to the root of+# the working tree and separated by a single NUL.+#+#echo "$0 $*" >&2++if test "$#" -ne 2+then+ echo "$0: exactly 2 arguments expected" >&2+ exit 2+fi++if test "$1" != 1+then+ echo "Unsupported core.fsmonitor hook version." >&2+ exit 1+fi++printf '%s\n' $FSMONITOR_LIST
From: William Baker via GitGitGadget <hidden> Date: 2019-10-09 21:00:19
This is the second iteration of changes to fix the segfault that I
encountered while testing fsmonitor. This iteration includes the following
updates for feedback I received on v1:
* Use %u instead of %"PRIuMAX" for unsigned ints in BUG format strings
* Updated the new test's comment to be more descriptive
Thanks,
William
William Baker (1):
fsmonitor: don't fill bitmap with entries to be removed
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 13 +++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 61 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
base-commit: 5fa0f5238b0cd46cfe7f6fa76c3f526ea98148d9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-372%2Fwilbaker%2Ffix_git_fsmonitor_crash-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-372/wilbaker/fix_git_fsmonitor_crash-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/372
Range-diff vs v1:
1: ce9bf4237e ! 1: 08741d986c fsmonitor: don't fill bitmap with entries to be removed
@@ -44,8 +44,8 @@
+ struct cache_entry *ce;
+
+ if (pos >= istate->cache_nr)
-+ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %"PRIuMAX")",
-+ (uintmax_t)pos, (uintmax_t)istate->cache_nr);
++ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)",
++ (uintmax_t)pos, istate->cache_nr);
+ ce = istate->cache[pos];
ce->ce_flags &= ~CE_FSMONITOR_VALID;
@@ -56,8 +56,8 @@
istate->fsmonitor_dirty = fsmonitor_dirty;
+ if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
-+ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",
-+ (uintmax_t)istate->fsmonitor_dirty->bit_size, (uintmax_t)istate->cache_nr);
++ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
++ (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
+
trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
return 0;
@@ -85,8 +85,8 @@
int fixup = 0;
+ if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
-+ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",
-+ (uintmax_t)istate->fsmonitor_dirty->bit_size, (uintmax_t)istate->cache_nr);
++ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
++ (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
+
put_be32(&hdr_version, INDEX_EXTENSION_VERSION);
strbuf_add(sb, &hdr_version, sizeof(uint32_t));
@@ -96,8 +96,8 @@
/* Mark all previously saved entries as dirty */
+ if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
-+ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %"PRIuMAX")",
-+ (uintmax_t)istate->fsmonitor_dirty->bit_size, (uintmax_t)istate->cache_nr);
++ BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
++ (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
/* Now mark the untracked cache for fsmonitor usage */
@@ -109,8 +109,9 @@
test_cmp expect actual
'
-+# Use test files that start with 'z' so that the entries being added
-+# and removed appear at the end of the index.
++# This test covers staging/unstaging files that appear at the end of the index.
++# Test files with names beginning with 'z' are used under the assumption that
++# earlier tests do not add/leave index entries that sort below them.
+test_expect_success 'status succeeds after staging/unstaging ' '
+ test_commit initial &&
+ removed=$(test_seq 1 100 | sed "s/^/z/") &&
--
gitgitgadget
@@ -354,4 +354,17 @@ test_expect_success 'discard_index() also discards fsmonitor info' 'test_cmpexpectactual'+# This test covers staging/unstaging files that appear at the end of the index.+# Test files with names beginning with 'z' are used under the assumption that+# earlier tests do not add/leave index entries that sort below them. +test_expect_success'status succeeds after staging/unstaging ''+test_commitinitial&&
This is confusing: this is the 29th test case in this script and it
creates an "initial" commit?!
The first "setup" test case has already created an initial commit, so
this should rather be called "second".
OTOH, none of the later commands in this test case seem to have
anything to do with this second commit, and indeed the test case works
even without it (i.e. 'git status' still segfaults without the fix and
then succeeds with the fix applied), so instead of updating its
message perhaps it could simply be removed.
@@ -354,4 +354,17 @@ test_expect_success 'discard_index() also discards fsmonitor info' 'test_cmpexpectactual'+# This test covers staging/unstaging files that appear at the end of the index.+# Test files with names beginning with 'z' are used under the assumption that+# earlier tests do not add/leave index entries that sort below them.
I just read through Junio's comments on the first version of this
patch, in particular his remarks about this comment.
If this new test case below were run in a dedicated repository, then
this comment wouldn't be necessary, and all my comments below about
that not-really-initial commit would be moot, too.
This is confusing: this is the 29th test case in this script and it
creates an "initial" commit?!
The first "setup" test case has already created an initial commit, so
this should rather be called "second".
OTOH, none of the later commands in this test case seem to have
anything to do with this second commit, and indeed the test case works
even without it (i.e. 'git status' still segfaults without the fix and
then succeeds with the fix applied), so instead of updating its
message perhaps it could simply be removed.
From: William Baker <hidden> Date: 2019-10-11 16:38:47
On 10/10/19 4:22 AM, SZEDER Gábor wrote:
quoted
quoted
+# This test covers staging/unstaging files that appear at the end of the index.
+# Test files with names beginning with 'z' are used under the assumption that
+# earlier tests do not add/leave index entries that sort below them.
I just read through Junio's comments on the first version of this
patch, in particular his remarks about this comment.
If this new test case below were run in a dedicated repository, then
this comment wouldn't be necessary, and all my comments below about
that not-really-initial commit would be moot, too.
Thanks for this suggestion! I will submit a v3 version of the patch
with an update to the test script.
- William
From: William Baker via GitGitGadget <hidden> Date: 2019-10-11 20:11:29
From: William Baker <redacted>
While doing some testing with fsmonitor enabled I found
that git commands would segfault after staging and
unstaging an untracked file. Looking at the crash it
appeared that fsmonitor_ewah_callback was attempting to
adjust bits beyond the bounds of the index cache.
Digging into how this could happen it became clear that
the fsmonitor extension must have been written with
more bits than there were entries in the index. The
root cause ended up being that fill_fsmonitor_bitmap was
populating fsmonitor_dirty with bits for all entries in
the index, even those that had been marked for removal.
To solve this problem fill_fsmonitor_bitmap has been
updated to skip entries with the the CE_REMOVE flag set.
With this change the bits written for the fsmonitor
extension will be consistent with the index entries
written by do_write_index. Additionally, BUG checks
have been added to detect if the number of bits in
fsmonitor_dirty should ever exceed the number of
entries in the index again.
Another option that was considered was moving the call
to fill_fsmonitor_bitmap closer to where the index is
written (and where the fsmonitor extension itself is
written). However, that did not work as the
fsmonitor_dirty bitmap must be filled before the index
is split during writing.
Signed-off-by: William Baker <redacted>
---
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 17 +++++++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 65 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
@@ -14,8 +14,13 @@ struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);staticvoidfsmonitor_ewah_callback(size_tpos,void*is){structindex_state*istate=(structindex_state*)is;-structcache_entry*ce=istate->cache[pos];+structcache_entry*ce;++if(pos>=istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)",+(uintmax_t)pos,istate->cache_nr);+ce=istate->cache[pos];ce->ce_flags&=~CE_FSMONITOR_VALID;}
@@ -50,17 +55,24 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,}istate->fsmonitor_dirty=fsmonitor_dirty;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);+trace_printf_key(&trace_fsmonitor,"read fsmonitor extension successful");return0;}voidfill_fsmonitor_bitmap(structindex_state*istate){-unsignedinti;+unsignedinti,skipped=0;istate->fsmonitor_dirty=ewah_new();-for(i=0;i<istate->cache_nr;i++)-if(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))-ewah_set(istate->fsmonitor_dirty,i);+for(i=0;i<istate->cache_nr;i++){+if(istate->cache[i]->ce_flags&CE_REMOVE)+skipped++;+elseif(!(istate->cache[i]->ce_flags&CE_FSMONITOR_VALID))+ewah_set(istate->fsmonitor_dirty,i-skipped);+}}voidwrite_fsmonitor_extension(structstrbuf*sb,structindex_state*istate)
@@ -71,6 +83,10 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)uint32_tewah_size=0;intfixup=0;+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);+put_be32(&hdr_version,INDEX_EXTENSION_VERSION);strbuf_add(sb,&hdr_version,sizeof(uint32_t));
@@ -236,6 +252,9 @@ void tweak_fsmonitor(struct index_state *istate)}/* Mark all previously saved entries as dirty */+if(istate->fsmonitor_dirty->bit_size>istate->cache_nr)+BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",+(uintmax_t)istate->fsmonitor_dirty->bit_size,istate->cache_nr);ewah_each_bit(istate->fsmonitor_dirty,fsmonitor_ewah_callback,istate);/* Now mark the untracked cache for fsmonitor usage */
@@ -354,4 +354,21 @@ test_expect_success 'discard_index() also discards fsmonitor info' 'test_cmpexpectactual'+# Test staging/unstaging files that appear at the end of the index. Test+# file names begin with 'z' so that they are sorted to the end of the index. +test_expect_success'status succeeds after staging/unstaging ''+test_create_repofsmonitor-stage-unstage&&+(+cdfsmonitor-stage-unstage&&+test_commitinitial&&+gitupdate-index--fsmonitor&&+removed=$(test_seq1100|sed"s/^/z/")&&+touch$removed&&+gitadd$removed&&+gitconfigcore.fsmonitor"$TEST_DIRECTORY/t7519/fsmonitor-env"&&+FSMONITOR_LIST="$removed"gitrestore-S$removed&&+FSMONITOR_LIST="$removed"gitstatus+)+'+ test_done
@@ -0,0 +1,24 @@+#!/bin/sh+#+# An test hook script to integrate with git to test fsmonitor.+#+# The hook is passed a version (currently 1) and a time in nanoseconds+# formatted as a string and outputs to stdout all files that have been+# modified since the given time. Paths must be relative to the root of+# the working tree and separated by a single NUL.+#+#echo "$0 $*" >&2++if test "$#" -ne 2+then+ echo "$0: exactly 2 arguments expected" >&2+ exit 2+fi++if test "$1" != 1+then+ echo "Unsupported core.fsmonitor hook version." >&2+ exit 1+fi++printf '%s\n' $FSMONITOR_LIST
From: William Baker via GitGitGadget <hidden> Date: 2019-10-11 20:11:32
This is the third iteration of changes to fix the segfault that I
encountered while testing fsmonitor. This iteration includes the following
updates for feedback I received on v2:
* Update the new test case to use its own dedicated test repository
This latest v3 series has been reviewed by Dscho.
Thanks, William
William Baker (1):
fsmonitor: don't fill bitmap with entries to be removed
fsmonitor.c | 29 ++++++++++++++++++++++++-----
t/t7519-status-fsmonitor.sh | 17 +++++++++++++++++
t/t7519/fsmonitor-env | 24 ++++++++++++++++++++++++
3 files changed, 65 insertions(+), 5 deletions(-)
create mode 100755 t/t7519/fsmonitor-env
base-commit: 5fa0f5238b0cd46cfe7f6fa76c3f526ea98148d9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-372%2Fwilbaker%2Ffix_git_fsmonitor_crash-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-372/wilbaker/fix_git_fsmonitor_crash-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/372
Range-diff vs v2:
1: 08741d986c ! 1: 840972e08b fsmonitor: don't fill bitmap with entries to be removed
@@ -109,17 +109,21 @@
test_cmp expect actual
'
-+# This test covers staging/unstaging files that appear at the end of the index.
-+# Test files with names beginning with 'z' are used under the assumption that
-+# earlier tests do not add/leave index entries that sort below them.
++# Test staging/unstaging files that appear at the end of the index. Test
++# file names begin with 'z' so that they are sorted to the end of the index.
+test_expect_success 'status succeeds after staging/unstaging ' '
-+ test_commit initial &&
-+ removed=$(test_seq 1 100 | sed "s/^/z/") &&
-+ touch $removed &&
-+ git add $removed &&
-+ test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
-+ FSMONITOR_LIST="$removed" git restore -S $removed &&
-+ FSMONITOR_LIST="$removed" git status
++ test_create_repo fsmonitor-stage-unstage &&
++ (
++ cd fsmonitor-stage-unstage &&
++ test_commit initial &&
++ git update-index --fsmonitor &&
++ removed=$(test_seq 1 100 | sed "s/^/z/") &&
++ touch $removed &&
++ git add $removed &&
++ git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
++ FSMONITOR_LIST="$removed" git restore -S $removed &&
++ FSMONITOR_LIST="$removed" git status
++ )
+'
+
test_done
--
gitgitgadget