<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>Bug with Allegro packfile compression</title>
		<link>http://www.allegro.cc/forums/view/587170</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Mon, 04 Sep 2006 03:38:38 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I&#39;m not entirely sure if it&#39;s the compression itself or the getc/putc functions, but using a packfile to store and read data can occasionally cause our data to become corrupt. What happens is that the unpacked data gets written to a packed packfile. However, when the packfile is read via Allegro&#39;s built-in functions, the output ends up being one byte short of the original&#39;s length, which screws up our loading functions. Note that this only occurs extremely rarely.</p><p>Packed into the file below is a test program I wrote to demonstrate this problem. It contains the program, the source, the dll, and the uncompressed data from our program that&#39;s exhibiting this problem. Any help would e greatly appreciated.</p><p><a href="http://www.cgi101.com/~jman2050/pack_test.zip">http://www.cgi101.com/~jman2050/pack_test.zip</a></p><p>EDIT - forgot to mention that the program takes tst.tst, packs it via pack_putc, then unpacks itvia pack_getc, and puts the result into output.tst
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (jman2050)</author>
		<pubDate>Tue, 22 Aug 2006 19:15:05 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I can confirm the bug.  I&#39;d thought there was a bug remaining in the packfile code. Thanks for the test case.</p><p>In case anyone wants to have a go at this, I&#39;ve found that: </p><p>(1) the bug doesn&#39;t show up with a random file of the same length as test.tst;</p><p>(2) appending a single byte to test.tst causes the bug not to show;</p><p>(3) removing the last byte of test.tst causes the bug not to show;</p><p>(4) removing the first byte of test.tst causes the bug not to show.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Peter Wang)</author>
		<pubDate>Wed, 23 Aug 2006 03:36:52 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>The bug also shows if you &quot;double&quot; test.tst by:<br />$ cat test.tst test.tst &gt;tmp.tst; mv tmp.tst test.tst<br />Then output.tst lacks two bytes.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Milan Mimica)</author>
		<pubDate>Wed, 30 Aug 2006 19:34:13 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Going to sleep now.  I&#39;m pretty certain the compressed file is okay.  I checked the length using the following program.  It seems the bug is an off by one error in the read buffering.</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="p">#include &lt;assert.h&gt;</span></td></tr><tr><td class="number">2</td><td><span class="p">#include &lt;stdio.h&gt;</span></td></tr><tr><td class="number">3</td><td><span class="p">#include &lt;stdlib.h&gt;</span></td></tr><tr><td class="number">4</td><td>&#160;</td></tr><tr><td class="number">5</td><td><span class="k1">int</span> main<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span></td></tr><tr><td class="number">6</td><td><span class="k2">{</span></td></tr><tr><td class="number">7</td><td>    FILE <span class="k3">*</span>fp<span class="k2">;</span></td></tr><tr><td class="number">8</td><td>    <span class="k1">int</span> length<span class="k2">;</span></td></tr><tr><td class="number">9</td><td>&#160;</td></tr><tr><td class="number">10</td><td>    fp <span class="k3">=</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_337.html" target="_blank">fopen</a><span class="k2">(</span><span class="s">"tmp.tmp"</span>, <span class="s">"rb"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">11</td><td>    <span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span>fp<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">12</td><td>        <a href="http://www.delorie.com/djgpp/doc/libc/libc_298.html" target="_blank">exit</a><span class="k2">(</span>EXIT_FAILURE<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">14</td><td>&#160;</td></tr><tr><td class="number">15</td><td>    <span class="c">/* skip signature */</span></td></tr><tr><td class="number">16</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">17</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">19</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">20</td><td>&#160;</td></tr><tr><td class="number">21</td><td>    length <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">22</td><td>    <span class="k1">while</span> <span class="k2">(</span><span class="n">1</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">23</td><td>        <span class="k1">int</span> flags<span class="k2">;</span></td></tr><tr><td class="number">24</td><td>        <span class="k1">int</span> bit<span class="k2">;</span></td></tr><tr><td class="number">25</td><td>&#160;</td></tr><tr><td class="number">26</td><td>        flags <span class="k3">=</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">27</td><td>        <span class="k1">if</span> <span class="k2">(</span>flags <span class="k3">=</span><span class="k3">=</span> EOF<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">28</td><td>            <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"Reached EOF\n"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">29</td><td>            <span class="k1">break</span><span class="k2">;</span></td></tr><tr><td class="number">30</td><td>        <span class="k2">}</span></td></tr><tr><td class="number">31</td><td>&#160;</td></tr><tr><td class="number">32</td><td>        <span class="k1">for</span> <span class="k2">(</span>bit <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span> bit <span class="k3">&lt;</span> <span class="n">8</span><span class="k2">;</span> bit<span class="k3">+</span><span class="k3">+</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">33</td><td>            <span class="k1">if</span> <span class="k2">(</span>flags <span class="k3">&amp;</span> <span class="k2">(</span><span class="n">1</span> <span class="k3">&lt;</span><span class="k3">&lt;</span> bit<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">34</td><td>                <span class="k1">if</span> <span class="k2">(</span><a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> EOF<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">35</td><td>                    <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"Reached EOF while reading raw byte\n"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">36</td><td>                    <span class="k1">goto</span> Exit<span class="k2">;</span></td></tr><tr><td class="number">37</td><td>                <span class="k2">}</span></td></tr><tr><td class="number">38</td><td>                length<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span></td></tr><tr><td class="number">39</td><td>            <span class="k2">}</span></td></tr><tr><td class="number">40</td><td>            <span class="k1">else</span> <span class="k2">{</span></td></tr><tr><td class="number">41</td><td>                <span class="k1">int</span> byte1<span class="k2">;</span></td></tr><tr><td class="number">42</td><td>                <span class="k1">int</span> byte2<span class="k2">;</span></td></tr><tr><td class="number">43</td><td>                <span class="k1">int</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_470.html" target="_blank">index</a><span class="k2">;</span></td></tr><tr><td class="number">44</td><td>                <span class="k1">int</span> len<span class="k2">;</span></td></tr><tr><td class="number">45</td><td>&#160;</td></tr><tr><td class="number">46</td><td>                byte1 <span class="k3">=</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">47</td><td>                <span class="k1">if</span> <span class="k2">(</span>byte1 <span class="k3">=</span><span class="k3">=</span> EOF<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">48</td><td>                    <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"Reached EOF while reading byte1\n"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">49</td><td>                    <span class="k1">goto</span> Exit<span class="k2">;</span></td></tr><tr><td class="number">50</td><td>                <span class="k2">}</span></td></tr><tr><td class="number">51</td><td>&#160;</td></tr><tr><td class="number">52</td><td>                byte2 <span class="k3">=</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_317.html" target="_blank">fgetc</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">53</td><td>                <span class="k1">if</span> <span class="k2">(</span>byte2 <span class="k3">=</span><span class="k3">=</span> EOF<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">54</td><td>                    <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"Reached EOF while reading byte2\n"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">55</td><td>                    <span class="k1">goto</span> Exit<span class="k2">;</span></td></tr><tr><td class="number">56</td><td>                <span class="k2">}</span></td></tr><tr><td class="number">57</td><td>&#160;</td></tr><tr><td class="number">58</td><td>                <a href="http://www.delorie.com/djgpp/doc/libc/libc_470.html" target="_blank">index</a> <span class="k3">=</span> byte1 <span class="k3">|</span> <span class="k2">(</span><span class="k2">(</span>byte2 <span class="k3">&amp;</span> <span class="n">0xF0</span><span class="k2">)</span> <span class="k3">&lt;</span><span class="k3">&lt;</span> <span class="n">4</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">59</td><td>                len <span class="k3">=</span> <span class="k2">(</span>byte2 <span class="k3">&amp;</span> <span class="n">0x0F</span><span class="k2">)</span> <span class="k3">+</span> <span class="n">3</span><span class="k2">;</span></td></tr><tr><td class="number">60</td><td>&#160;</td></tr><tr><td class="number">61</td><td>                <a href="http://www.delorie.com/djgpp/doc/libc/libc_48.html" target="_blank">assert</a><span class="k2">(</span><a href="http://www.delorie.com/djgpp/doc/libc/libc_470.html" target="_blank">index</a> <span class="k3">&gt;</span><span class="k3">=</span> <span class="n">0</span> <span class="k3">&amp;</span><span class="k3">&amp;</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_470.html" target="_blank">index</a> <span class="k3">&lt;</span> <span class="n">4096</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">62</td><td>                length <span class="k3">+</span><span class="k3">=</span> len<span class="k2">;</span></td></tr><tr><td class="number">63</td><td>            <span class="k2">}</span></td></tr><tr><td class="number">64</td><td>        <span class="k2">}</span></td></tr><tr><td class="number">65</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">66</td><td>&#160;</td></tr><tr><td class="number">67</td><td> Exit:</td></tr><tr><td class="number">68</td><td>&#160;</td></tr><tr><td class="number">69</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_308.html" target="_blank">fclose</a><span class="k2">(</span>fp<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">70</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"Length = %d bytes\n"</span>, length<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">71</td><td>    <span class="k1">return</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">72</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>


EDIT: For anyone not on [AD], I posted this:</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
I think I have a fix.  I would appreciate help looking it over (see the<br />comments for detailed explanation of the problem) and stress testing it,<br />since Evert is planning to release 4.2.1 this weekend.  In addition to<br />the test case in the thread, I&#39;ve attached a shell script which produces<br />files using /dev/zero and /dev/urandom, compresses and decompresses them<br />with the `pack&#39; tool and checks they are the same.</p><p>I&#39;ve tried to minimise the number of changes and maintaining PACKFILE<br />semantics, in particular that pack_feof() returns TRUE immediately after<br />the last byte has been read (unlike feof() which returns true once you<br />try to read <u>past</u> the last byte).
</p></div></div><p>

The patch and shell script are attached.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Peter Wang)</author>
		<pubDate>Wed, 30 Aug 2006 19:52:01 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>The fix seems to have done the trick. I&#39;ll report if anything else goes wrong. Thanks a lot Peter <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (jman2050)</author>
		<pubDate>Mon, 04 Sep 2006 03:38:38 +0000</pubDate>
	</item>
</rss>
