Open ecm-pushbx opened 4 years ago
This patch seems to fix it, but I'm not sure whether it is correct. It just fixes the infinite looping by checking that it won't loop with the same pos value.
$ git diff
diff --git a/heatshrink_encoder.c b/heatshrink_encoder.c
index edf4abe..be216ee 100644
--- a/heatshrink_encoder.c
+++ b/heatshrink_encoder.c
@@ -471,8 +471,10 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start,
* This is redundant with the index if match_maxlen is 0, but the
* added branch overhead to check if it == 0 seems to be worse. */
if (pospoint[match_maxlen] != needlepoint[match_maxlen]) {
- pos = hsi->index[pos];
- continue;
+ if (pos != hsi->index[pos]) {
+ pos = hsi->index[pos];
+ continue;
+ }
}
for (len = 1; len < maxlen; len++) {
@@ -484,6 +486,9 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start,
match_index = pos;
if (len == maxlen) { break; } /* won't find better */
}
+ if (pos == hsi->index[pos]) {
+ break;
+ }
pos = hsi->index[pos];
}
#else
Curiously, -w 15 almost always ends up with negative compression for me (ie, expanding the output file to be larger than the input file). So for now I just exclude -w 15 from my scripts that determine the best compression parameters.
Thanks for your detailed bug report! This will be fixed in the next release.
I wouldn't expect -w 15
to compress effectively, except in very contrived circumstances.
Do you still intend to create a new revision of the library? I ask because I just recommended it to someone else on the freedos-devel mailing list and I stumbled across the allowed parameter ranges being larger than my script used to try. (And a -w
parameter below 10 often wins out for the lDebug online help pages, as these are all below 3 KiB each.) That led me to rediscovering the -w 15
bug on large files.
Yes. It will probably be a few weeks before I get to it because I'm currently busy with moving, but I currently plan to tie up some loose ends and post another release by the end of the year.
This is with revision v0.4.1-1-g7d419e1.
Using -w 14 or lower, or building with HEATSHRINK_USE_INDEX set to zero, works around this bug.
It seems to be that in the function find_longest_match the while loop loops forever, because pos = 0, match_maxlen = 0, pospoint[match_maxlen] = pospoint[0] = 0, needlepoint[match_maxlen] = needlepoint[0] = 0x90 (presumably a byte (first one?) from the input file), hsi->index[pos] = hsi->index[0] = 0. So the first if in that while always is evaluated as true, pos gets reset to hsi->index[pos] (both are zero), and the loop continues looping.
Here's a gdb session showing the behaviour: