php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #37158 if userspace stream is present, fread() reads in 8192 max, otherwise it works
Submitted: 2006-04-21 22:11 UTC Modified: 2006-04-22 17:18 UTC
From: cellog@php.net Assigned: wez
Status: Closed Package: Streams related
PHP Version: 5CVS-2006-04-21 (CVS) OS: n/a
Private report: No CVE-ID:
 [2006-04-21 22:11 UTC] cellog@php.net
Description:
------------
fread($fp, 20000); will read in 20000 bytes from a local file, but is a userspace stream is defined anywhere, it will only read in 8192 bytes, without any warning or error.

This is actually similar to Bug #30936, but as I say the problem here is that the presence of a userspace stream handler changes the behavior of fread() - any indeterminate behavior is bad.

I wonder if the fix from #32810 could be helpful for this problem as well?

Reproduce code:
---------------
<?php
// paste in the stream code from the example in the manual
// be sure to include stream_wrapper_register
error_reporting(E_ALL | E_STRICT);
$file = dirname(__FILE__) . '/footest.txt';
$x = str_repeat('1', 8192);
$fp = fopen($file, 'w');
for ($i = 0; $i < 5; $i++) {
    fwrite($fp, $x);
}
fclose($fp);

$fp = fopen($file, 'r');
$outsidecontents = fread($fp, 20000);
fclose($fp);
var_dump('size of contents 1 = ' . strlen($outsidecontents));
$outsidecontents = file_get_contents($file);
var_dump('size of contents 2 = ' . strlen($outsidecontents));
?>

Expected result:
----------------
string(26) "size of contents 1 = 20000"
string(26) "size of contents 2 = 40960"


Actual result:
--------------
string(25) "size of contents 1 = 8192"
string(26) "size of contents 2 = 40960"


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-04-21 22:15 UTC] cellog@php.net
P.S.  The documentation still sucks for fread() on the need to read in chunks.

I ran into this bug because I had an fread() from a local file handle within a streams handler (pear.php.net/PHP_Archive) that had never been more than 8192 before.

I would recommend fixing this by adding an E_STRICT warning if a value larger than 8192 is passed into fread()
 [2006-04-21 22:40 UTC] pajoye@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

"...or (after opening userspace stream) when 8192 bytes have been read whichever comes first."

I think it is clear. What do you suggest to make it more clear? Reopen and change it to "documentation" bug if you have a better text.

It is not a bug.
 [2006-04-22 04:25 UTC] cellog@php.net
"...or (after opening userspace stream) when 8192 bytes have been read
whichever comes first."

Pierre, I never opened a userspace stream.  A user stream was registered with stream_wrapper_register(), and never used.  Read the example code.  The only thing opened was a local file, which is very much a built-in stream.

This would be equivalent to mysql_query() failing because the code initialized a pdo object.  The two should not affect each other.
 [2006-04-22 14:52 UTC] pajoye@php.net
Your example is incomplete, but there was a comment to help to complete it, next time, please provide a complete script :)

However, I found the problem, please try:
http://pear.php.net/~pierre/check_stream_plainfile_wops.txt


 [2006-04-22 15:36 UTC] wez@php.net
A change was made to wrapper resolution that mean that the plain file wrapper is effectively aliased at alternate locations in memory.  This fundamentally breaks the wrapper implementation macros (PHP_STREAM_IS(...)) which absolutely rely on the wrapper structures living at the definitive original address in memory.  Other streams core code also relies on this being the case.

The fix is to change the wrapper hash tables to store pointers to the wrapper structures instead of having them clone the wrapper structures.

The reason this problem only triggered when calling stream_wrapper_register() is that it clones the hash on the first call.  This coupled with a change that allows scripts to override file:// causes regular plain file access (even without file://) to lookup the cloned plain file wrapper from the cloned hash. 
 [2006-04-22 16:02 UTC] wez@php.net
The following patch corrects the issue:
http://y1.php.net/~wez/streams-37158.diff
 [2006-04-22 17:18 UTC] wez@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sun Apr 20 10:02:06 2014 UTC