On Wed, Mar 27, 2013 at 3:10 PM, <phi...@apache.org> wrote: > Author: philip > Date: Wed Mar 27 14:10:54 2013 > New Revision: 1461590 > > URL: http://svn.apache.org/r1461590 > Log: > Fix issue 4339, diff suffix scanning invalid read at last chunk boundary. > > * subversion/libsvn_diff/diff_file.c > (find_identical_suffix): Handle last chunk. > > * subversion/tests/libsvn_diff/diff-diff3-test.c > (test_token_compare): Add comments, tweak allocation to match use (which > doesn't change the underlying allocation due to alignment rounding). > > Modified: > subversion/trunk/subversion/libsvn_diff/diff_file.c > subversion/trunk/subversion/tests/libsvn_diff/diff-diff3-test.c > > Modified: subversion/trunk/subversion/libsvn_diff/diff_file.c > URL: > http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/diff_file.c?rev=1461590&r1=1461589&r2=1461590&view=diff > ============================================================================== > --- subversion/trunk/subversion/libsvn_diff/diff_file.c (original) > +++ subversion/trunk/subversion/libsvn_diff/diff_file.c Wed Mar 27 14:10:54 > 2013 > @@ -549,6 +549,14 @@ find_identical_suffix(apr_off_t *suffix_ > /* Prefix ended in last chunk, so we can reuse the prefix buffer */ > file_for_suffix[i].buffer = file[i].buffer; > } > + else if (!length[i] && file_for_suffix[i].chunk == file[i].chunk + 1) > + { > + /* Prefix ended at end of last chunk, so we can reuse the > + prefix buffer */ > + file_for_suffix[i].chunk = file[i].chunk; > + file_for_suffix[i].buffer = file[i].buffer; > + length[i] = CHUNK_SIZE; > + } > else > { > /* There is at least more than 1 chunk,
Hi Philip, Thanks for finding and fixing this. However, I think you only fixed it for one particular case of "empty-last-chunkness": where find_identical_prefix ended in last_chunk - 1. I think the problem is still there if for instance one of the files is exactly 262144 bytes (2 * CHUNK_SIZE), and there is no or very little identical prefix (so prefix scanning stops in the first chunk (chunk number 0). Suffix scanning will (as always) start at last_chunk == offset_to_chunk(262144) == 2, which is an empty chunk, but this is not file[i].chunk + 1. I think if we'd write a test for that case, you'll see your valgrind warning again. I can spend more time on this in a week or two, but if you want to dig into it sooner, I think a better fix would be something like this (untested / uncompiled): [[[ Index: diff_file.c =================================================================== --- diff_file.c (revision 1461996) +++ diff_file.c (working copy) @@ -544,19 +544,18 @@ find_identical_suffix(apr_off_t *suffix_lines, str file_for_suffix[i].chunk = (int) offset_to_chunk(file_for_suffix[i].size); /* last chunk */ length[i] = offset_in_chunk(file_for_suffix[i].size); + if (length[i] == 0) + { + /* last chunk is an empty chunk -> start at next-to-last chunk */ + file_for_suffix[i].chunk = file_for_suffix[i].chunk - 1; + length[i] = CHUNK_SIZE; + } + if (file_for_suffix[i].chunk == file[i].chunk) { /* Prefix ended in last chunk, so we can reuse the prefix buffer */ file_for_suffix[i].buffer = file[i].buffer; } - else if (!length[i] && file_for_suffix[i].chunk == file[i].chunk + 1) - { - /* Prefix ended at end of last chunk, so we can reuse the - prefix buffer */ - file_for_suffix[i].chunk = file[i].chunk; - file_for_suffix[i].buffer = file[i].buffer; - length[i] = CHUNK_SIZE; - } else { /* There is at least more than 1 chunk, ]]] This will probably go wrong if the file is completely empty (then file_for_suffix[i].chunk will be set to -1), but I think in that case this code shouldn't be hit anyway (early exit in datasources_open if one of the files is empty). -- Johan > > Modified: subversion/trunk/subversion/tests/libsvn_diff/diff-diff3-test.c > URL: > http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1461590&r1=1461589&r2=1461590&view=diff > ============================================================================== > --- subversion/trunk/subversion/tests/libsvn_diff/diff-diff3-test.c (original) > +++ subversion/trunk/subversion/tests/libsvn_diff/diff-diff3-test.c Wed Mar > 27 14:10:54 2013 > @@ -2571,6 +2571,7 @@ test_token_compare(apr_pool_t *pool) > > diff_opts->ignore_space = svn_diff_file_ignore_space_all; > > + /* CHUNK_SIZE bytes */ > original = svn_stringbuf_create_ensure(chunk_size, pool); > while (original->len < chunk_size - 8) > { > @@ -2578,7 +2579,8 @@ test_token_compare(apr_pool_t *pool) > } > svn_stringbuf_appendcstr(original, " @@@\n"); > > - modified = svn_stringbuf_create_ensure(chunk_size, pool); > + /* CHUNK_SIZE+1 bytes, one ' ' more than original */ > + modified = svn_stringbuf_create_ensure(chunk_size + 1, pool); > while (modified->len < chunk_size - 8) > { > svn_stringbuf_appendcstr(modified, pattern); > >