Skip to content

Commit bcecbb5

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

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

ext/zend_test/test.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,38 @@ static ZEND_FUNCTION(zend_test_set_fmode)
774774
}
775775
#endif
776776

777+
static ZEND_FUNCTION(zend_test_cast_fread)
778+
{
779+
zval *stream_zv;
780+
php_stream *stream;
781+
FILE *fp;
782+
783+
ZEND_PARSE_PARAMETERS_START(1, 1)
784+
Z_PARAM_RESOURCE(stream_zv);
785+
ZEND_PARSE_PARAMETERS_END();
786+
787+
php_stream_from_zval(stream, stream_zv);
788+
789+
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS) == FAILURE) {
790+
return;
791+
}
792+
793+
size_t size = 10240; /* Must be large enough to trigger the issue */
794+
char *buf = malloc(size);
795+
bool bail = false;
796+
zend_try {
797+
(void) !fread(buf, 1, size, fp);
798+
} zend_catch {
799+
bail = true;
800+
} zend_end_try();
801+
802+
free(buf);
803+
804+
if (bail) {
805+
zend_bailout();
806+
}
807+
}
808+
777809
static zend_object *zend_test_class_new(zend_class_entry *class_type)
778810
{
779811
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
@@ -281,6 +281,9 @@ function zend_test_is_pcre_bundled(): bool {}
281281
#if defined(PHP_WIN32)
282282
function zend_test_set_fmode(bool $binary): void {}
283283
#endif
284+
285+
/** @param resource $stream */
286+
function zend_test_cast_fread($stream): void {}
284287
}
285288

286289
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)