Bug Summary

File:external/xstream/src/bz.cpp
Location:line 549, column 13
Description:Value stored to 'cret' is never read

Annotated Source Code

1#include <xstream/config.h>
2
3#if HAVE_LIBBZ21
4
5#include <stdint.h>
6#include <string.h>
7#include <algorithm>
8#include <cassert>
9
10#include <xstream/bz.h>
11#include <xstream/except/bz.h>
12
13#include <bzlib.h>
14#include <arpa/inet.h>
15
16#include "debug.h"
17
18namespace xstream {
19namespace bz {
20
21// define a set of compressed stream headers that can be used
22// to remove arbitrary bit-alignment offsets in an input stream
23
24 static const int bz_header_length[8] = {35,36,34,44,40,38,40,43};
25 static const unsigned char bz_header[8][48] = {
26 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
27 0x53, 0x59, 0x86, 0xad, 0x3f, 0xf0, 0x00, 0x00,
28 0x02, 0x48, 0x00, 0x04, 0x00, 0x20, 0x00, 0x20,
29 0x00, 0x21, 0x00, 0x82, 0x0b, 0x31, 0x41, 0x59,
30 0x26, 0x53, 0x59 },
31 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
32 0x53, 0x59, 0x7b, 0x68, 0x3e, 0x4a, 0x00, 0x00,
33 0x01, 0x88, 0x00, 0x0f, 0xc0, 0x20, 0x00, 0x21,
34 0x80, 0x0c, 0x01, 0x37, 0xa4, 0xbb, 0x98, 0xa0,
35 0xac, 0x93, 0x29, 0xac },
36 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
37 0x53, 0x59, 0x83, 0x69, 0xfc, 0x04, 0x00, 0x00,
38 0x01, 0x88, 0x00, 0x30, 0x00, 0x20, 0x00, 0x30,
39 0x80, 0x2a, 0x69, 0x11, 0xcc, 0x50, 0x56, 0x49,
40 0x94, 0xd6 },
41 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
42 0x53, 0x59, 0xd5, 0x0d, 0x1c, 0x28, 0x00, 0x00,
43 0x01, 0x51, 0x80, 0x00, 0x10, 0x01, 0x01, 0x80,
44 0x02, 0x01, 0x80, 0x20, 0x00, 0x31, 0x0c, 0x01,
45 0x06, 0x9b, 0x47, 0xe7, 0x38, 0x04, 0xa6, 0x28,
46 0x2b, 0x24, 0xca, 0x6b },
47 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
48 0x53, 0x59, 0x44, 0x1f, 0x23, 0x2f, 0x00, 0x00,
49 0x02, 0x11, 0x00, 0x00, 0x00, 0xa5, 0xa2, 0xa0,
50 0x00, 0x22, 0x06, 0x9a, 0x7a, 0x10, 0xc0, 0x8e,
51 0x10, 0xd8, 0x43, 0x14, 0x15, 0x92, 0x65, 0x35 },
52 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
53 0x53, 0x59, 0x83, 0x90, 0x27, 0xae, 0x00, 0x00,
54 0x01, 0x81, 0x80, 0x0c, 0x00, 0x14, 0x20, 0x20,
55 0x00, 0x21, 0x86, 0x81, 0x9a, 0x09, 0x4d, 0xa8,
56 0xb9, 0x8a, 0x0a, 0xc9, 0x32, 0x9a },
57 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
58 0x53, 0x59, 0x8d, 0x4f, 0x1e, 0x72, 0x00, 0x00,
59 0x04, 0x41, 0x80, 0x40, 0x00, 0x00, 0x20, 0x14,
60 0x60, 0x20, 0x00, 0x30, 0xc0, 0x08, 0x63, 0x45,
61 0x84, 0x0f, 0xb8, 0xc5, 0x05, 0x64, 0x99, 0x4d },
62 { 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
63 0x53, 0x59, 0x64, 0xf2, 0x3a, 0xdc, 0x00, 0x00,
64 0x00, 0x9e, 0x00, 0x04, 0x00, 0x30, 0x00, 0x02,
65 0x08, 0x08, 0x80, 0x20, 0x00, 0x31, 0x0c, 0x01,
66 0x06, 0x99, 0xa4, 0xe4, 0x4c, 0x0a, 0x62, 0x82,
67 0xb2, 0x4c, 0xa6 }
68 };
69
70 static const int eof = std::streambuf::traits_type::eof();
71
72 struct pimpl: public bz_stream {};
73
74 static inline int flush_macro(const flush_kind f) {
75 switch (f) {
76 case no_sync:
77 return BZ_RUN0;
78 case full_sync:
79 return BZ_FLUSH1;
80 case finish_sync:
81 return BZ_FINISH2;
82 default:
83 //should probably throw
84 return BZ_RUN0;
85 }
86 }
87
88 common::common(std::streambuf *sb)
89 : xstream::common_buffer(sb), z_strm(0), block_offset(0)
90 {
91 LOG("bz::common");
92
93 z_strm = new pimpl;
94
95 //initialize zlib structure
96 z_strm->bzalloc = NULL__null;
97 z_strm->bzfree = NULL__null;
98 z_strm->opaque = NULL__null;
99 //buffers
100 z_strm->avail_out = out.size;
101 z_strm->next_out = out.buf;
102
103 z_strm->avail_in = 0;
104 z_strm->next_in = in.buf;
105 }
106
107 unsigned long int common::input_count() const {
108// return (z_strm->total_in_hi32 * (1L << 32)) + z_strm->total_in_lo32;
109 return ((uint64_t)(z_strm->total_in_hi32)<< 32) + (uint64_t)(z_strm->total_in_lo32);
110 }
111
112 unsigned long int common::output_count() const {
113// return (z_strm->total_out_hi32 * (1L << 32)) + z_strm->total_out_lo32;
114 return ((uint64_t)(z_strm->total_out_hi32)<< 32) + (uint64_t)(z_strm->total_out_lo32);
115 }
116
117 common::~common() {
118 LOG("bz::~common");
119 delete z_strm;
120 }
121
122
123 //default compression 9
124 ostreambuf::ostreambuf(std::streambuf * sb)
125 : common(sb), level(9) {
126 LOG("bz::ostreambuf without compression level");
127 init ();
128 }
129
130 ostreambuf::ostreambuf (std::streambuf * sb, int l)
131 : common(sb), level(l) {
132 LOG("bz::ostreambuf with compression level " << l);
133 init ();
134 }
135
136 const char* error_str(int err) {
137 switch(err) {
138 case BZ_MEM_ERROR(-3):
139 return "out of memory";
140 case BZ_CONFIG_ERROR(-9):
141 return "bzlib badly configured (bad sizes of int32 (4), int16 (2) or char (1), check and recompile)";
142 case BZ_PARAM_ERROR(-2):
143 return "invalid parameter, possibly invalid compression level";
144 case BZ_SEQUENCE_ERROR(-1):
145 return "bad sequence (this means xstream is buggy)";
146 case BZ_DATA_ERROR(-4):
147 return "invalid or incomplete data (crc failed)";
148 case BZ_DATA_ERROR_MAGIC(-5):
149 return "magic bytes not found in stream";
150 case BZ_IO_ERROR(-6):
151 return "io error";
152 case BZ_UNEXPECTED_EOF(-7):
153 return "premature end of data";
154 case BZ_OUTBUFF_FULL(-8):
155 return "output buffer full";
156 }
157
158 return "unknown error";
159 }
160
161 void ostreambuf::raise_error(int err) {
162 std::string what = error_str(err);
163
164 LOG("bz::ostreambuf::raise_error (" << err << ") = " << what);
165
166 if (what.size() > 0) {
167 throw compress_error(this,what);
168 } else {
169 throw compress_error(this);
170 }
171 }
172
173
174 void ostreambuf::init() {
175 LOG("bz::ostreambuf::init");
176 int cret =::BZ2_bzCompressInit(
177 z_strm,
178 level,
179 0, //verbosity
180 30 //workFactor (default value) controls when to switch to the fallback algorithm
181 );
182
183 if (BZ_OK0 != cret) {
184 LOG("bz::ostreambuf::init: error creating zstream " << cret);
185 raise_error(cret);
186 }
187 //initialize streambuf interface functions
188 setp(in.buf, in.buf + in.size);
189 }
190
191 ostreambuf::~ostreambuf() {
192 LOG("bz::ostreambuf::~ostreambuf");
193 //fullsync (write remaining data)
194 flush(finish_sync);
195
196 //sync underlying streambuf
197 _sb->pubsync();
198
199 if (0 != z_strm) {
200 //XXX should I throw an exception in case of error?
201 //remember this is a destructor
202 int cret = ::BZ2_bzCompressEnd(z_strm);
203 if (BZ_OK0 != cret) {
204 LOG("\tERROR: BZ2_bzCompressEnd returned " << cret);
205 }
206 }
207 }
208
209 int ostreambuf::sync () {
210 LOG("bz::ostreambuf::sync");
211 int ret = flush(full_sync);
212 _sb->pubsync();
213 return ret;
214 }
215
216
217 int ostreambuf::overflow (int c) {
218 LOG("bz::ostreambuf::overflow(" << c << ")\t available=" << (available ()) << "\tEOF=" << eof);
219 if (eof == c) {
220 LOG("\tEOF");
221 flush(no_sync);
222 return eof;
223 } else {
224 if (0 == available()) {
225 LOG("\t have to flush :[]");
226 flush(no_sync);
227 }
228 *pptr() = static_cast < char >(c);
229 pbump(1);
230 }
231 return c;
232 }
233
234 std::streamsize ostreambuf::xsputn(const char *buffer, std::streamsize n) {
235 LOG("bz::ostreambuf::xsputn(" << buffer << "," << n << ")");
236
237 return flush(no_sync, buffer, n);
238 }
239
240 int ostreambuf::flush(flush_kind f, const char *appendbuf, int appendsize) {
241 LOG("bz::ostreambuf::flush(" << f << ")");
242 std::streamsize in_s = taken();
243 LOG("\tinput_size=" << in_s);
244
245 //set up compression engine input feed
246 int written;
247 if (in_s > 0) {
248 z_strm->next_in = pbase();
249 z_strm->avail_in = in_s;
250 written = in_s;
251 } else if (appendsize > 0) {
252 z_strm->next_in = (char*)appendbuf;
253 z_strm->avail_in = appendsize;
254 written = appendsize;
255 appendsize = 0;
256 } else {
257 z_strm->next_in = pbase();
258 z_strm->avail_in = 0;
259 written = 0;
260 }
261 block_offset += written;
262 if (block_offset > (std::streamoff)level * 100000) {
263 f = full_sync;
264 }
265
266 bool redo = false;
267
268 do {
269 int cret;
270 redo = false;
271 bool error = false;
272
273 cret = ::BZ2_bzCompress(z_strm, flush_macro(f));
274
275 //error handling
276 if (finish_sync == f) {
277 if (BZ_STREAM_END4 == cret) {
278 redo = false;
279 }
280 else if (BZ_FINISH_OK3 == cret) {
281 redo = true;
282 } else {
283 //serious error, throw exception
284 LOG("\terror in finish:" << cret);
285 error = true;
286 }
287 } else if (full_sync == f) {
288 if (BZ_FLUSH_OK2 == cret) {
289 LOG("\tanother go at sync");
290 redo = true;
291 } else if (BZ_RUN_OK1 == cret) {
292 LOG("\tsync ok");
293 redo = false;
294 } else {
295 LOG("\terror in sync: " << cret);
296 error = true;
297 }
298 } else if (no_sync == f) {
299 if (BZ_RUN_OK1 != cret) {
300 LOG("\terror compressing " << cret);
301 error = true;
302 }
303 } else {
304 LOG("\tERROR: unknown flush mode " << flush_macro(f));
305 throw general_error();
306 error = true;
307 }
308
309 if (error) {
310 raise_error(cret);
311 }
312
313 if (f != no_sync) {
314 std::streamsize count = out.size - z_strm->avail_out;
315 LOG("\twriting " << count << " bytes");
316 int size = htonl(count)(__extension__ ({ register unsigned int __v, __x = (count); if
(__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000
) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x
) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) <<
24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v
; }))
;
317 const std::streamsize wrote = _sb->sputn((char*)&size, 4) +
318 _sb->sputn(out.buf, count);
319 if (wrote != count + 4) {
320 LOG("\terror writting, only wrote " << wrote
321 << " but asked for " << count);
322 raise_error(BZ_IO_ERROR(-6));
323 }
324
325 //reset output
326 z_strm->next_out = out.buf;
327 z_strm->avail_out = out.size;
328 block_offset = 0;
329 }
330
331 if ((0 == z_strm->avail_out) && (0 != z_strm->avail_in)) {
332 LOG("\tavail_out=0 => redo");
333 redo = true;
334 }
335
336 if (!redo && appendbuf && appendsize > 0) {
337 z_strm->next_in = (char*)appendbuf;
338 z_strm->avail_in = appendsize;
339 written += appendsize;
340 appendsize = 0;
341 redo = true;
342 }
343 } while (redo);
344 assert (0 == z_strm->avail_in)((0 == z_strm->avail_in) ? static_cast<void> (0) : __assert_fail
("0 == z_strm->avail_in", "external/xstream/src/bz.cpp", 344
, __PRETTY_FUNCTION__))
;
345
346 //reset buffer
347 setp(in.buf, in.buf + in.size);
348 return written;
349 }
350
351 /////////////////////
352 // istream follows //
353 /////////////////////
354
355 istreambuf::istreambuf(std::streambuf * sb)
356 : common(sb), end(false), block_size(0), block_pending(0) {
357 LOG("bz::istreambuf");
358
359 int cret =::BZ2_bzDecompressInit(z_strm,
360 0, //verbosity
361 0 //no small memory
362 );
363
364 if (BZ_OK0 != cret) {
365 LOG("\terror creating zstream " << cret);
366 raise_error(cret);
367 }
368 //initialize streambuf interface functions
369 //first call will call uflow and this will set the buffer accordingly
370 //no buffering
371 setg(out.buf, out.buf, out.buf);
372 }
373
374 void istreambuf::raise_error(int err){
375 std::string what = error_str(err);
376
377 LOG("bz::istreambuf::raise_error (" << err << ") = " << what);
378
379 if (what.size() > 0) {
380 throw decompress_error(this, what);
381 } else {
382 throw decompress_error(this);
383 }
384 }
385
386 int istreambuf::underflow() {
387 LOG("z:istreambuf::underflow");
388
389 if (end) {
390 LOG("\tend of stream (EOF)");
391 //signal the stream has reached it's end
392 return eof;
393 }
394
395 z_strm->avail_out = out.size;
396 z_strm->next_out = out.buf;
397 if (0 < z_strm->avail_in) {
398 LOG("\tdata in queue, inflating");
399 decompress();
400 }
401 while (!end && z_strm->avail_out > 0) {
402 read_decompress();
403 }
404
405 //set streambuf pointers
406 setg(out.buf, out.buf, z_strm->next_out);
407
408 return int(out.buf[0]);
409 }
410
411 //read to buffer in place (apart from data already buffered)
412 std::streamsize istreambuf::xsgetn(char *buffer, std::streamsize n) {
413 LOG("bz::istreambuf::xsgetn (" << n << ")");
414
415 //try to satisfy request from buffered input
416 std::streamsize available = egptr() - gptr();
417 int read = (available >= n)? n : available;
418 if (read) {
419 std::copy(gptr(), gptr() + read, buffer);
420 gbump(read);
421 block_offset += read;
422 }
423
424 //inflate the rest directly into the user's buffer
425 if (read < n) {
426 if (end) {
427 LOG("\tend of stream (EOF)");
428 //signal the stream has reached it's end
429 return eof;
430 }
431
432 z_strm->next_out = buffer + read;
433 z_strm->avail_out = n - read;
434
435 if (0 < z_strm->avail_in) {
436 decompress();
437 }
438 while (!end && z_strm->avail_out > 0) {
439 read_decompress();
440 }
441 block_offset += n - read;
442 }
443 return n;
444 }
445
446 void istreambuf::read_decompress() {
447 LOG("bz::istreambuf::read_decompress ");
448 int read;
449 if (block_size < 0) { // stream has no blocksize markers
450 read = _sb->sgetn(in.buf, in.size);
451 }
452 else { // look for prefixed blocksize: leading byte = 0
453 block_size = block_pending;
454 read = _sb->sgetn(in.buf, 4);
455 if (in.buf[0] == 0) { // bz2 blocks have prefixed blocksize
456 int *size = (int*)in.buf;
457 block_pending = ntohl(*size)(__extension__ ({ register unsigned int __v, __x = (*size); if
(__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000
) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x
) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) <<
24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v
; }))
;
458 read = _sb->sgetn(in.buf, block_pending);
459 }
460 else { // bz2 blocks are jammed together, no blocksize available
461 read += _sb->sgetn(in.buf + 4, in.size - 4);
462 block_size = -1;
463 }
464 }
465 LOG("\tread " << read << " bytes");
466 block_offset = 0;
467
468 if (0 == read) {
469 LOG("\tpremature end of stream");
470 raise_error(BZ_UNEXPECTED_EOF(-7));
471 }
472
473 // We want to be able to start decompression at an arbitrary position
474 // in the input stream. This is possible with bzip2 streams, but there
475 // is a problem that the compressed blocks are arbitrary numbers of
476 // bits long and they are catenated one after another in a bit stream
477 // without any reference to byte boundaries. This makes it difficult
478 // to jump into the middle of a stream and start the decompressor
479 // since it expects a stream header followed by the first block that
480 // happens to start on a byte boundary. To make this work, I splice
481 // an artificial stream header followed by a dummy compressed block
482 // onto the beginning of the input stream, where the length of the
483 // dummy block in bits is chosen so that it abutts without padding
484 // the next block in the input stream. I have prepared 8 dummy blocks
485 // so there should be one to match the alignment of any input block.
486 // To match them, I look for the first place in the input stream
487 // with a byte string that matches the last 5 bytes in one of my
488 // dummy headers, and then I inject the dummy header into the
489 // decompressor ahead of the actual data. The dummy blocks are all
490 // contrived to decompress to an 8-byte string, so throwing away the
491 // first 8 bytes out of the decompressor, it is primed to decompress
492 // the remaining stream without any need for bit-shifting the input.
493
494 const char* head = (const char*)bz_header[0];
495 if (block_size == 0 && strncmp(head, in.buf, 4) != 0) {
496 int hdr;
497 int splice;
498 int match = 10;
499 for (hdr = 0; hdr < 8; ++hdr) {
500 splice = bz_header_length[hdr] - 5;
501 const char* shead = (const char*)bz_header[hdr];
502 for (match = 1; match < 10; ++match) {
503 if (strncmp(&in.buf[match], &shead[splice], 5) == 0)
504 break;
505 }
506 if (match < 10)
507 break;
508 }
509 if (hdr > 7) {
510 LOG("\tbz2 stream format error on input");
511 raise_error(BZ_DATA_ERROR_MAGIC(-5));
512 }
513 int saved_buflen = z_strm->avail_out;
514 char *saved_buffer = z_strm->next_out;
515 char dummy_buffer[8];
516 z_strm->avail_out = 8;
517 z_strm->next_out = dummy_buffer;
518 while (match > 0)
519 in.buf[--match] = (const char)bz_header[hdr][--splice];
520 z_strm->avail_in = splice;
521 z_strm->next_in = (char*)bz_header[hdr];
522 decompress(); // waste the first 8 bytes
523 z_strm->next_in = in.buf;
524 z_strm->avail_in = read;
525 decompress();
526 z_strm->avail_out = saved_buflen;
527 z_strm->next_out = saved_buffer;
528 decompress();
529 }
530 else {
531 z_strm->next_in = in.buf;
532 z_strm->avail_in = read;
533 decompress();
534 }
535 }
536
537 void istreambuf::decompress() {
538 LOG("bz::istreambuf::decompress ");
539
540 int cret = ::BZ2_bzDecompress(z_strm);
541
542 if (BZ_STREAM_END4 == cret) {
543 end = true;
544 }
545 else if (cret == BZ_DATA_ERROR(-4) && z_strm->avail_in == 0) {
546 // Ignore CRC errors at the end of stream because we may not have
547 // started decompressing at the beginning. We can rely on the CRC
548 // checks that are present within each compressed block anyway.
549 cret = BZ_OK0;
Value stored to 'cret' is never read
550 end = true;
551 }
552 else if (BZ_OK0 != cret) {
553 LOG("\terror decompressing: " << cret);
554 raise_error(cret);
555 }
556 }
557
558 istreambuf::~istreambuf() {
559 LOG("bz::~istreambuf");
560 if (0 != z_strm) {
561 int cret = ::BZ2_bzDecompressEnd(z_strm);
562 if (BZ_OK0 != cret) {
563 LOG("\tERROR: BZ2_bzDecompressEnd returned " << cret);
564 }
565 }
566 }
567
568}//namespace bz
569}//namespace xstream
570
571#endif //bzlib