Skip to content

Commit

Permalink
Merge branch 'PHP-8.3'
Browse files Browse the repository at this point in the history
* PHP-8.3:
  Fix GH-11078: PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors
  • Loading branch information
nielsdos committed Jun 10, 2024
2 parents 62bfb01 + ccdd1c4 commit bcecbb5
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
32 changes: 32 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,38 @@ static ZEND_FUNCTION(zend_test_set_fmode)
}
#endif

static ZEND_FUNCTION(zend_test_cast_fread)
{
zval *stream_zv;
php_stream *stream;
FILE *fp;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_RESOURCE(stream_zv);
ZEND_PARSE_PARAMETERS_END();

php_stream_from_zval(stream, stream_zv);

if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS) == FAILURE) {
return;
}

size_t size = 10240; /* Must be large enough to trigger the issue */
char *buf = malloc(size);
bool bail = false;
zend_try {
(void) !fread(buf, 1, size, fp);
} zend_catch {
bail = true;
} zend_end_try();

free(buf);

if (bail) {
zend_bailout();
}
}

static zend_object *zend_test_class_new(zend_class_entry *class_type)
{
zend_object *obj = zend_objects_new(class_type);
Expand Down
3 changes: 3 additions & 0 deletions ext/zend_test/test.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ function zend_test_is_pcre_bundled(): bool {}
#if defined(PHP_WIN32)
function zend_test_set_fmode(bool $binary): void {}
#endif

/** @param resource $stream */
function zend_test_cast_fread($stream): void {}
}

namespace ZendTestNS {
Expand Down
8 changes: 7 additions & 1 deletion ext/zend_test/test_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions ext/zend_test/tests/gh11078.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
GH-11078 (PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors)
--EXTENSIONS--
zend_test
--SKIPIF--
<?php
if (getenv('USE_ZEND_ALLOC') === '0') die('skip Zend MM disabled');
if (PHP_OS_FAMILY === 'Windows') die('skip Windows does not support generic stream casting');
?>
--FILE--
<?php

const MEM = 32 * 1024 * 1024;
ini_set('memory_limit', MEM);

class CrashingFifo {
public $context;

function stream_open($path, $mode, $options, &$opened_path): bool {
return true;
}

function stream_read(int $count): false|string|null {
return str_repeat('x', MEM);
}
}

stream_register_wrapper('fifo', CrashingFifo::class);
$readStream = fopen('fifo://1', 'r');
zend_test_cast_fread($readStream);

?>
--EXPECTF--
Fatal error: Allowed memory size of %d bytes exhausted %s
9 changes: 8 additions & 1 deletion main/streams/cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ typedef struct {

FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t *funcs)
{
return funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer);
FILE *file = funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer);
if (file) {
/* Buffering of FILE handles is stateful.
* A bailout during these can corrupt the state of the FILE handle
* and cause memory corruption errors. See GH-11078. */
setvbuf(file, NULL, _IONBF, 0);
}
return file;
}
# define HAVE_FOPENCOOKIE 1
# define PHP_EMULATE_FOPENCOOKIE 1
Expand Down

0 comments on commit bcecbb5

Please sign in to comment.