ID: 28673
Updated by: [EMAIL PROTECTED]
Reported By: valyala at tut dot by
-Status: Feedback
+Status: No Feedback
Bug Type: Output Control
Operating System: any with MMAP support
PHP Version: 4.3.7
New Comment:
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
Previous Comments:
------------------------------------------------------------------------
[2004-12-13 01:30:41] [EMAIL PROTECTED]
Is this still a problem in the most recent PHP versions? (PHP 4.3.9 for
example) If it is, please provide an unified diff of your changes (diff
-u) and place the patch somewhere in the web and paste an url here.
------------------------------------------------------------------------
[2004-06-07 15:46:39] valyala at tut dot by
Description:
------------
When I try to print huge files (greater than 500Mb) using readfile()
function, my computer crashes.
I found in the PHP 4.3.7 sources the file /main/strems.c and function
_php_stream_passthru() in it.
The readfile() uses this function to print content of the file.
Below you can see source of the function with my comments:
===================================================================
PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC
TSRMLS_DC)
{
size_t bcount = 0;
int ready = 0;
char buf[8192];
#ifdef HAVE_MMAP
int fd;
#endif
#ifdef HAVE_MMAP
if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)
&& stream->filterhead == NULL
&& php_stream_tell(stream) == 0
&& SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD,
(void*)&fd, 0))
{
struct stat sbuf;
off_t off; /* !!! offset == 0 (see above condition
[php_stream_tell(stream) == 0] ) */
void *p;
size_t len;
fstat(fd, &sbuf); /* !!! missing error check after this line
*/
if (sbuf.st_size > sizeof(buf)) {
off = php_stream_tell(stream); /* !!! offset == 0 (see
above) */
len = sbuf.st_size - off;
/* suppose len > 1 Gb, machine has 128Mb RAM and 128Mb
swap. What happens after the next
line? */
p = mmap(0, len, PROT_READ, MAP_SHARED, fd, off); /* !!!
why MAP_SHARED, not MAP_PRIVATE ?
First parameter of the mmap is (void *)
type, not (int) */
if (p != (void *) MAP_FAILED) {
BG(mmap_file) = p; /* !!! what sense of this and next
string? Thread safety?
I don't understand how it works here */
BG(mmap_len) = len;
PHPWRITE(p, len);
BG(mmap_file) = NULL; /* !!! thread safety? ok. why
there is not BG(mmap_len) = 0 on
the next line ? */
munmap(p, len); /* !!! missing error check after munmap
*/
bcount += len;
ready = 1;
}
}
}
#endif
if(!ready) {
int b;
while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) {
PHPWRITE(buf, b);
bcount += b;
}
}
return bcount;
}
===================================================================
And here you can see my version of the function:
===================================================================
PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC
TSRMLS_DC)
{
size_t bcount = 0; /* counter of printed out bytes */
int is_mapped = 0;
char buf[8192];
size_t buf_len = sizeof(buf);
#ifdef HAVE_MMAP
int fd;
if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)
&& stream->filterhead == NULL
&& php_stream_tell(stream) == 0
&& SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD,
(void*)&fd, 0))
{
is_mapped = 1;
buf_len = 1024 * 1024; /* default length of the mapped memory
*/
struct stat sbuf;
void *p; /* pinter to the mapped part of file */
size_t len;
/* get the length of local file connected to descriptor fd */
fstat(fd, &sbuf);
if (errno) {
/* cannot get length of file */
php_error_docref(NULL TSRMLS_CC, E_ERROR, "cannot get
length of the file");
return bcount;
}
len = (size_t) sbuf.st_size;
/* print to the output buffer file contents */
while (bcount < len) {
if (len - bcount < buf_len) buf_len = len - bcount;
p = mmap(NULL, buf_len, PROT_READ, MAP_PRIVATE, fd, (off_t)
bcount); /* try to map part of
the file to memory */
if (p == (void *) MAP_FAILED) {
/* error when mapping part of the file to memory */
php_error_docref(NULL TSRMLS_CC, E_ERROR, "mmap error:
cannot map part of the file to
memory");
break;
}
PHPWRITE(p, buf_len);
munmap(p, buf_len); /* try to unmap allocated memory */
if (errno) {
/* error when unmapping memory */
php_error_docref(NULL TSRMLS_CC, E_ERROR, "mmap error:
cannot unmap allocated memory");
break;
}
bcount += buf_len;
}
}
#endif
if (!is_mapped) {
/* print to the output buffer stream contents */
while ((buf_len = php_stream_read(stream, buf, sizeof(buf))) >
0) {
PHPWRITE(buf, buf_len);
bcount += buf_len;
}
}
return bcount;
}
Reproduce code:
---------------
<?php
readfile('very_big_file');
?>
Expected result:
----------------
contents of the very_big_file
Actual result:
--------------
PHP crash
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=28673&edit=1