Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ PHP NEWS
with a given skeleton, locale, collapse type and identity fallback.
(BogdanUngureanu)

- Standard:
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)

<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
8 changes: 6 additions & 2 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -3489,6 +3489,12 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H
HT_SET_ITERATORS_COUNT(in_hash, 0);
in_hash->pDestructor = NULL;

/* Set internal pointer to 0 directly instead of calling zend_hash_internal_pointer_reset().
* This avoids the COW violation assertion and delays advancing to the first valid position
* until after we've switched to the new array structure (out_hash). The iterator will be
* advanced when actually accessed, at which point it will find valid indexes in the new array. */
in_hash->nInternalPointer = 0;

if (UNEXPECTED(GC_DELREF(in_hash) == 0)) {
/* Array was completely deallocated during the operation */
zend_array_destroy(in_hash);
Expand All @@ -3507,8 +3513,6 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H
in_hash->nNextFreeElement = out_hash.nNextFreeElement;
in_hash->arData = out_hash.arData;
in_hash->pDestructor = out_hash.pDestructor;

zend_hash_internal_pointer_reset(in_hash);
}
/* }}} */

Expand Down
20 changes: 20 additions & 0 deletions ext/standard/tests/array/gh19926.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
GH-19926 (Assertion failure zend_hash_internal_pointer_reset_ex)
--FILE--
<?php
class ThrowingDestructor {
function __destruct() {
throw new Exception();
}
}

$arr = [new ThrowingDestructor(), new ThrowingDestructor()];

try {
array_splice($arr, 0, 2);
} catch (Exception $e) {
echo "Exception caught, no assertion failure\n";
}
?>
--EXPECT--
Exception caught, no assertion failure
19 changes: 19 additions & 0 deletions ext/standard/tests/array/gh19926_pointer.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
GH-19926 (internal pointer behavior after array_splice)
--FILE--
<?php
$a = [1, 2, 3];
unset($a[0]);
next($a);

echo "Before array_splice: ";
var_dump(current($a));

array_splice($a, 0, 0, [999]);

echo "After array_splice: ";
var_dump(current($a));
?>
--EXPECT--
Before array_splice: int(3)
After array_splice: int(999)
22 changes: 22 additions & 0 deletions ext/standard/tests/streams/gh19570.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
GH-19570 (unable to fseek in /dev/zero and /dev/null)
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== "Linux") die("skip only for Linux");
?>
--FILE--
<?php
$devices = [
// Note: could test others but they're not necessarily available
"/dev/zero",
"/dev/null",
"/dev/full",
];
foreach ($devices as $device) {
var_dump(fseek(fopen($device, "rb"), 1*1024*1024, SEEK_SET));
}
?>
--EXPECT--
int(0)
int(0)
int(0)
25 changes: 25 additions & 0 deletions main/streams/plain_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
# include <limits.h>
#endif

#ifdef __linux__
# include <sys/sysmacros.h>
#endif

#define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC)
#define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC)
#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC)
Expand Down Expand Up @@ -255,7 +259,28 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC)
static void detect_is_seekable(php_stdio_stream_data *self) {
#if defined(S_ISFIFO) && defined(S_ISCHR)
if (self->fd >= 0 && do_fstat(self, 0) == 0) {
#ifdef __linux__
if (S_ISCHR(self->sb.st_mode)) {
/* Some character devices are exceptions, check their major/minor ID
* https://www.kernel.org/doc/Documentation/admin-guide/devices.txt */
if (major(self->sb.st_rdev) == 1) {
unsigned m = minor(self->sb.st_rdev);
self->is_seekable =
m == 1 || /* /dev/mem */
m == 2 || /* /dev/kmem */
m == 3 || /* /dev/null */
m == 4 || /* /dev/port (seekable, offset = I/O port) */
m == 5 || /* /dev/zero */
m == 7; /* /dev/full */
} else {
self->is_seekable = false;
}
} else {
self->is_seekable = !S_ISFIFO(self->sb.st_mode);
}
#else
self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode));
#endif
self->is_pipe = S_ISFIFO(self->sb.st_mode);
}
#elif defined(PHP_WIN32)
Expand Down
8 changes: 5 additions & 3 deletions sapi/cli/php_cli_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -2712,14 +2712,16 @@ static zend_result php_cli_server_do_event_for_each_fd_callback(void *_params, p
struct sockaddr *sa = pemalloc(server->socklen, 1);
client_sock = accept(server->server_sock, sa, &socklen);
if (!ZEND_VALID_SOCKET(client_sock)) {
int err = php_socket_errno();
if (err != SOCK_EAGAIN && php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
pefree(sa, 1);
if (php_socket_errno() == SOCK_EAGAIN) {
return SUCCESS;
}
if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
char *errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR,
"Failed to accept a client (reason: %s)", errstr);
efree(errstr);
}
pefree(sa, 1);
return FAILURE;
}
if (SUCCESS != php_set_sock_blocking(client_sock, 0)) {
Expand Down
Loading