Bug #71417 [Opn]: fread() does not detect decoding errors from filter zlib.inflate

From: Date: Wed, 20 Jan 2016 11:06:42 +0000
Subject: Bug #71417 [Opn]: fread() does not detect decoding errors from filter zlib.inflate
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-198790@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71417&edit=1

 ID:                 71417
 User updated by:    salsi at icosaedro dot it
 Reported by:        salsi at icosaedro dot it
 Summary:            fread() does not detect decoding errors from filter
                     zlib.inflate
 Status:             Open
 Type:               Bug
 Package:            Streams related
 Operating System:   Slackware 14.1
 PHP Version:        master-Git-2016-01-20 (Git)
 Block user comment: N
 Private report:     N

 New Comment:

...and in general errors that are certainly generated internally to the zlib library are not
reported to the user's application, resulting in missing or no data read at all.

This happens, for example, when an highly compressible stream (say, a source program at least 40 KB
long) that was compressed with a large window (window=15+16), is then decompressed with a smaller
window (window=9+16). In this case fread() simply returns the empty string before the feof() (source
code available).

At this point these issues seem more related to the general implementation of the stream filters
that to a specific filter, but I don't know enough of the internals stuff to tell for sure.

FIX: in the test script above any reference to "bzip2" in the comments should be read
"zlib" :->


Previous Comments:
------------------------------------------------------------------------
[2016-01-20 02:57:42] salsi at icosaedro dot it

Description:
------------
When the zlib.inflate filter is applied to a gzip stream, the fread() function does not detect
decoding errors on a corrupted file and keeps instead returning the empty string or garbage. The
following script illustrates 3 distinct cases:

1. data corrupted
2. file truncated (commented away)
3. invalid CRC    (commented away)
4. invalid length (commented away)

For comparison, the comments in the script also report what the 'gzip' command tells about
these corrupted files.
Also the gzdecode() function works properly and always triggers error "data error".

In all the 4 cases above, no errors nor exceptions are generated, although the data read are either
corrupted or truncated.

Unsure if this bug is in some way related to bug #71263 (same issues with the bzip2.decompress
filter).


Test script:
---------------
<?php
// Bug report: zlib.inflate fails to detect corrupted data.

// Set a safe environment:
error_reporting(-1);

// Maps errors to ErrorException.
function my_error_handler($errno, $message)
{ throw new ErrorException($message); }

set_error_handler("my_error_handler");


/**
 * Testing reading corrupted BZIP2 file using bzip2.decompress filter.
 * @throws ErrorException
 */
function main()
{
	$plain = "The quick brown fox jumps over the lazy dog.";
	$fn = "test-zlib-inflate.gz";
	$compressed = (string) gzencode($plain);
	
	// 0. No corruption.
	// $ php test-zlib-inflate.php
	// --> read: string(44) "The quick brown fox jumps over the lazy dog."
	// $ gzip test-zlib-inflate.gz
	// (generates the file test-zlib-inflate with correct content)
	
	// 1. Set a random byte in the middle of the compressed data.
	// $ php test-zlib-inflate.php
	// --> read: string(0) ""
	// --> read: string(44) "The quick brown fox jumps over the lazx8dog."
	// $ gzip test-zlib-inflate.gz
	// gzip: test-zlib-inflate.gz: invalid compressed data--crc error
//	$compressed[strlen($compressed) - 15] = 'X';
	
	// 2. Truncate the compressed data.
	// $ php test-zlib-inflate.php
	// --> read: string(32) "The quick brown fox jumps over t"
	// $ gzip test-zlib-inflate.gz
	// gzip: test-zlib-inflate.gz: unexpected end of file
//	$compressed = substr($compressed, 0, strlen($compressed) - 20);
	
	// 3. Corrupted final CRC.
	// $ php test-zlib-inflate.php
	// --> read: string(0) ""
	// --> read: string(44) "The quick brown fox jumps over the lazy dog."
	// $ gzip test-zlib-inflate.gz
	// gzip: test-zlib-inflate.gz: invalid compressed data--crc error
//	$compressed[strlen($compressed)-5] = 'X';
	
	// 4. Corrupted final length.
	// $ php test-zlib-inflate.phpread: string(0) ""
	// read: string(44) "The quick brown fox jumps over the lazy dog."
	// $ gunzip test-zlib-inflate.gz 
	// gzip: test-zlib-inflate.gz: invalid compressed data--length error
	$compressed[strlen($compressed)-2] = 'X';
	
	// The gzdecode() function applied to the corrupted compressed data always
	// detects the error:
	// --> gzdecode(): PHP Fatal error:  Uncaught ErrorException: gzdecode(): data error in ...
//	echo "gzdecode(): ", rawurldecode(gzdecode($compressed)), "\n";

	file_put_contents($fn, $compressed);
	
	$r = fopen($fn, "r");
	stream_filter_append($r, 'zlib.inflate', STREAM_FILTER_READ, array('window'
=> 15+16));
	while( ! feof($r) ){
		$s = fread($r, 100);
		echo "read: "; var_dump($s);
	}
	fclose($r);
//	unlink($fn);
}

main();
?>

Expected result:
----------------
Fatal error: Uncaught ErrorException: fread() I/O error in ...

(or possibly a more descriptive error message similar to one of those returned by the gzip command)


Actual result:
--------------
read: string(0) ""
read: string(44) "The quick brown fox jumps over the lazx8dog."



------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=71417&edit=1


Thread (6 messages)

« previous php.bugs (#198790) next »