dunglas / frankenphp

🧟 The modern PHP app server
https://frankenphp.dev
MIT License
6.87k stars 236 forks source link

Segfault with stream_select() #614

Open flexponsive opened 8 months ago

flexponsive commented 8 months ago

What happened?

While trying to get Laravel's tinker to work with FrankenPHP, I noticed some issues relating to the stream_select function which occur when an interruption by system signals happens. With the sample script below, I am reliably able to get a segfault on FrankenPHP v1.1.0 PHP 8.3.3 Caddy v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=

<?php

// Signal handler function
function signalHandler($signo) {
    echo "Caught signal: $signo\n";
    // Handle signal, for example, set a global flag, log, cleanup, etc.
}
echo "A";
// Setup signal handling
#pcntl_signal(SIGINT, 'signalHandler'); // Handle Ctrl+C
pcntl_signal(SIGALRM, 'signalHandler'); // Handle alarm signals

echo "B";
// Simulate an external signal, such as an alarm, after a few seconds
pcntl_alarm(2);

echo "C";
$readStreams = [STDIN]; // Monitor STDIN for input
$writeStreams = null;
$exceptStreams = null;

echo "D";

while (true) {
    $modifiedStreams = $readStreams; // Make a copy since stream_select modifies it
    $numChangedStreams = stream_select($modifiedStreams, $writeStreams, $exceptStreams, 1);

    if ($numChangedStreams === false) {
        // Check for the specific error (EINTR)
        echo "stream_select error:";
        var_dump(error_get_last());
    } elseif ($numChangedStreams > 0) {
        echo "Data available, reading...\n";
        echo fgets(STDIN);
    } else {
        echo "No changes in streams. Looping...\n";
    }

    // Dispatch signals if any are pending
    pcntl_signal_dispatch();
}

Result:

$ frankenphp php-cli test2.php
ABCDNo changes in streams. Looping...
Segmentation fault (core dumped)

$ /usr/bin/php test2.php
ABCDNo changes in streams. Looping...
PHP Warning:  stream_select(): Unable to select [4]: Interrupted system call (max_fd=0) in /home/azureuser/test2.php on line 26
stream_select error:array(4) {
  ["type"]=>
  int(2)
  ["message"]=>
  string(73) "stream_select(): Unable to select [4]: Interrupted system call (max_fd=0)"
  ["file"]=>
  string(25) "/home/azureuser/test2.php"
  ["line"]=>
  int(26)
}
Caught signal: 14
No changes in streams. Looping...
No changes in streams. Looping...
No changes in streams. Looping...
^C

### Build Type

Docker (Debian Bookworm)

### Worker Mode

Yes

### Operating System

GNU/Linux

### CPU Architecture

x86_64

### PHP configuration

```shell
(too long to paste for github)

Relevant log output

No response

dunglas commented 8 months ago

This is likely because of the sigmask set by Go.

We may try to remove them before passing the hand to PHP CLI.