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