Skip to content

Commit ccdd1c4

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix GH-11078: PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors
2 parents 159f14c + bc558bf commit ccdd1c4

File tree

6 files changed

+88
-2
lines changed

6 files changed

+88
-2
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ PHP NEWS
6060
. Fixed bug GH-14290 (Member access within null pointer in extension spl).
6161
(nielsdos)
6262

63+
- Streams:
64+
. Fixed bug GH-11078 (PHP Fatal error triggers pointer being freed was not
65+
allocated and malloc: double free for ptr errors). (nielsdos)
66+
6367
06 Jun 2024, PHP 8.3.8
6468

6569
- CGI:

ext/zend_test/test.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,38 @@ static ZEND_FUNCTION(zend_test_set_fmode)
750750
}
751751
#endif
752752

753+
static ZEND_FUNCTION(zend_test_cast_fread)
754+
{
755+
zval *stream_zv;
756+
php_stream *stream;
757+
FILE *fp;
758+
759+
ZEND_PARSE_PARAMETERS_START(1, 1)
760+
Z_PARAM_RESOURCE(stream_zv);
761+
ZEND_PARSE_PARAMETERS_END();
762+
763+
php_stream_from_zval(stream, stream_zv);
764+
765+
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS) == FAILURE) {
766+
return;
767+
}
768+
769+
size_t size = 10240; /* Must be large enough to trigger the issue */
770+
char *buf = malloc(size);
771+
bool bail = false;
772+
zend_try {
773+
(void) !fread(buf, 1, size, fp);
774+
} zend_catch {
775+
bail = true;
776+
} zend_end_try();
777+
778+
free(buf);
779+
780+
if (bail) {
781+
zend_bailout();
782+
}
783+
}
784+
753785
static zend_object *zend_test_class_new(zend_class_entry *class_type)
754786
{
755787
zend_object *obj = zend_objects_new(class_type);

ext/zend_test/test.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ function zend_test_is_pcre_bundled(): bool {}
250250
#if defined(PHP_WIN32)
251251
function zend_test_set_fmode(bool $binary): void {}
252252
#endif
253+
254+
/** @param resource $stream */
255+
function zend_test_cast_fread($stream): void {}
253256
}
254257

255258
namespace ZendTestNS {

ext/zend_test/test_arginfo.h

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/zend_test/tests/gh11078.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
GH-11078 (PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors)
3+
--EXTENSIONS--
4+
zend_test
5+
--SKIPIF--
6+
<?php
7+
if (getenv('USE_ZEND_ALLOC') === '0') die('skip Zend MM disabled');
8+
if (PHP_OS_FAMILY === 'Windows') die('skip Windows does not support generic stream casting');
9+
?>
10+
--FILE--
11+
<?php
12+
13+
const MEM = 32 * 1024 * 1024;
14+
ini_set('memory_limit', MEM);
15+
16+
class CrashingFifo {
17+
public $context;
18+
19+
function stream_open($path, $mode, $options, &$opened_path): bool {
20+
return true;
21+
}
22+
23+
function stream_read(int $count): false|string|null {
24+
return str_repeat('x', MEM);
25+
}
26+
}
27+
28+
stream_register_wrapper('fifo', CrashingFifo::class);
29+
$readStream = fopen('fifo://1', 'r');
30+
zend_test_cast_fread($readStream);
31+
32+
?>
33+
--EXPECTF--
34+
Fatal error: Allowed memory size of %d bytes exhausted %s

main/streams/cast.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,14 @@ typedef struct {
4646

4747
FILE *fopencookie(void *cookie, const char *mode, COOKIE_IO_FUNCTIONS_T *funcs)
4848
{
49-
return funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer);
49+
FILE *file = funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer);
50+
if (file) {
51+
/* Buffering of FILE handles is stateful.
52+
* A bailout during these can corrupt the state of the FILE handle
53+
* and cause memory corruption errors. See GH-11078. */
54+
setvbuf(file, NULL, _IONBF, 0);
55+
}
56+
return file;
5057
}
5158
# define HAVE_FOPENCOOKIE 1
5259
# define PHP_EMULATE_FOPENCOOKIE 1

0 commit comments

Comments
 (0)