diff options
author | josh.macdonald <jmacd@users.noreply.github.com> | 2007-12-28 06:09:23 +0000 |
---|---|---|
committer | josh.macdonald <jmacd@users.noreply.github.com> | 2007-12-28 06:09:23 +0000 |
commit | e7b61e1ec3b00947fc8052bccb2906e8d000eff5 (patch) | |
tree | 47a7237ab3794671320269394304822b09eae140 /xdelta3 | |
parent | 2e0d675bf995f9f6e893bd41cb4b14304c6c88ab (diff) |
Fixes issue 58. Incorrect looping condition in xd3_smatch() caused
checking for matches with incorrect checksums, detected by debug builds.
This also improves speed slightly and potentially degrades compression
where the sprevsz array had spurious matches beyond its actual coverage.
Diffstat (limited to 'xdelta3')
-rw-r--r-- | xdelta3/xdelta3.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c index ad8fdb7..b047a3c 100644 --- a/xdelta3/xdelta3.c +++ b/xdelta3/xdelta3.c | |||
@@ -4701,12 +4701,12 @@ xd3_smatch (xd3_stream *stream, | |||
4701 | usize_t scksum, | 4701 | usize_t scksum, |
4702 | usize_t *match_offset) | 4702 | usize_t *match_offset) |
4703 | { | 4703 | { |
4704 | usize_t cmp_len; | 4704 | usize_t cmp_len; |
4705 | usize_t match_length = 0; | 4705 | usize_t match_length = 0; |
4706 | usize_t chain = (stream->min_match == MIN_MATCH ? | 4706 | usize_t chain = (stream->min_match == MIN_MATCH ? |
4707 | stream->smatcher.small_chain : | 4707 | stream->smatcher.small_chain : |
4708 | stream->smatcher.small_lchain); | 4708 | stream->smatcher.small_lchain); |
4709 | const uint8_t *inp_max = stream->next_in + stream->avail_in; | 4709 | const uint8_t *inp_max = stream->next_in + stream->avail_in; |
4710 | const uint8_t *inp; | 4710 | const uint8_t *inp; |
4711 | const uint8_t *ref; | 4711 | const uint8_t *ref; |
4712 | 4712 | ||
@@ -4718,6 +4718,9 @@ xd3_smatch (xd3_stream *stream, | |||
4718 | 4718 | ||
4719 | again: | 4719 | again: |
4720 | 4720 | ||
4721 | IF_DEBUG1 (DP(RINT "smatch at base=%u inp=%u cksum=%u\n", base, | ||
4722 | stream->input_position, scksum)); | ||
4723 | |||
4721 | /* For small matches, we can always go to the end-of-input because | 4724 | /* For small matches, we can always go to the end-of-input because |
4722 | * the matching position must be less than the input position. */ | 4725 | * the matching position must be less than the input position. */ |
4723 | XD3_ASSERT (base < stream->input_position); | 4726 | XD3_ASSERT (base < stream->input_position); |
@@ -4759,24 +4762,34 @@ xd3_smatch (xd3_stream *stream, | |||
4759 | while (--chain != 0) | 4762 | while (--chain != 0) |
4760 | { | 4763 | { |
4761 | /* Calculate the previous offset. */ | 4764 | /* Calculate the previous offset. */ |
4762 | usize_t last_pos = stream->small_prev[base & stream->sprevmask].last_pos; | 4765 | usize_t prev_pos = stream->small_prev[base & stream->sprevmask].last_pos; |
4766 | usize_t diff_pos; | ||
4763 | 4767 | ||
4764 | if (last_pos == 0) | 4768 | if (prev_pos == 0) |
4765 | { | 4769 | { |
4766 | break; | 4770 | break; |
4767 | } | 4771 | } |
4768 | 4772 | ||
4769 | last_pos -= HASH_CKOFFSET; | 4773 | prev_pos -= HASH_CKOFFSET; |
4770 | base = last_pos; | ||
4771 | 4774 | ||
4772 | /* Stop if the position is wrong (because the lists are not | 4775 | if (prev_pos > base) |
4773 | * re-initialized across input windows). */ | 4776 | { |
4774 | if (base < stream->input_position) | 4777 | break; |
4775 | { | 4778 | } |
4776 | goto again; | ||
4777 | } | ||
4778 | 4779 | ||
4779 | break; | 4780 | base = prev_pos; |
4781 | |||
4782 | XD3_ASSERT (stream->input_position > base); | ||
4783 | diff_pos = stream->input_position - base; | ||
4784 | |||
4785 | /* Stop searching if we go beyond sprevsz, since those entries | ||
4786 | * are for unrelated checksum entries. */ | ||
4787 | if (diff_pos & ~stream->sprevmask) | ||
4788 | { | ||
4789 | break; | ||
4790 | } | ||
4791 | |||
4792 | goto again; | ||
4780 | } | 4793 | } |
4781 | 4794 | ||
4782 | done: | 4795 | done: |