Merge branch 'PHP-7.2' into PHP-7.3

This commit is contained in:
Jakub Zelenka 2019-01-25 14:16:08 +00:00
commit 0da13086bd
4 changed files with 187 additions and 48 deletions

4
NEWS
View File

@ -16,6 +16,10 @@ PHP NEWS
. Fixed bug #77287 (Opcache literal compaction is incompatible with EXT
opcodes). (Nikita)
- OpenSSL:
. Fixed bug #77390 (feof might hang on TLS streams in case of fragmented TLS
records). (Abyl Valg, Jakub Zelenka)
07 Feb 2019, PHP 7.3.2
- Core:

View File

@ -2,14 +2,16 @@
const WORKER_ARGV_VALUE = 'RUN_WORKER';
function phpt_notify()
const WORKER_DEFAULT_NAME = 'server';
function phpt_notify($worker = WORKER_DEFAULT_NAME)
{
ServerClientTestCase::getInstance()->notify();
ServerClientTestCase::getInstance()->notify($worker);
}
function phpt_wait()
function phpt_wait($worker = WORKER_DEFAULT_NAME)
{
ServerClientTestCase::getInstance()->wait();
ServerClientTestCase::getInstance()->wait($worker);
}
/**
@ -20,11 +22,11 @@ class ServerClientTestCase
{
private $isWorker = false;
private $workerHandle;
private $workerHandle = [];
private $workerStdIn;
private $workerStdIn = [];
private $workerStdOut;
private $workerStdOut = [];
private static $instance;
@ -46,26 +48,41 @@ class ServerClientTestCase
$this->isWorker = $isWorker;
}
private function spawnWorkerProcess($code)
private function spawnWorkerProcess($worker, $code)
{
if (defined("PHP_WINDOWS_VERSION_MAJOR")) {
$ini = php_ini_loaded_file();
$cmd = sprintf('%s %s "%s" %s', PHP_BINARY, $ini ? "-n -c $ini" : "", __FILE__, WORKER_ARGV_VALUE);
$ini = php_ini_loaded_file();
$cmd = sprintf(
'%s %s "%s" %s',
PHP_BINARY, $ini ? "-n -c $ini" : "",
__FILE__,
WORKER_ARGV_VALUE
);
} else {
$cmd = sprintf('%s "%s" %s', PHP_BINARY, __FILE__, WORKER_ARGV_VALUE);
$cmd = sprintf(
'%s "%s" %s %s',
PHP_BINARY,
__FILE__,
WORKER_ARGV_VALUE,
$worker
);
}
$this->workerHandle = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], STDERR], $pipes);
$this->workerStdIn = $pipes[0];
$this->workerStdOut = $pipes[1];
$this->workerHandle[$worker] = proc_open(
$cmd,
[['pipe', 'r'], ['pipe', 'w'], STDERR],
$pipes
);
$this->workerStdIn[$worker] = $pipes[0];
$this->workerStdOut[$worker] = $pipes[1];
fwrite($this->workerStdIn, $code . "\n---\n");
fwrite($this->workerStdIn[$worker], $code . "\n---\n");
}
private function cleanupWorkerProcess()
private function cleanupWorkerProcess($worker)
{
fclose($this->workerStdIn);
fclose($this->workerStdOut);
proc_close($this->workerHandle);
fclose($this->workerStdIn[$worker]);
fclose($this->workerStdOut[$worker]);
proc_close($this->workerHandle[$worker]);
}
private function stripPhpTagsFromCode($code)
@ -90,21 +107,28 @@ class ServerClientTestCase
eval($code);
}
public function run($proc1Code, $proc2Code)
public function run($masterCode, $workerCode)
{
$this->spawnWorkerProcess($this->stripPhpTagsFromCode($proc2Code));
eval($this->stripPhpTagsFromCode($proc1Code));
$this->cleanupWorkerProcess();
if (!is_array($workerCode)) {
$workerCode = [WORKER_DEFAULT_NAME => $workerCode];
}
foreach ($workerCode as $worker => $code) {
$this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
}
eval($this->stripPhpTagsFromCode($masterCode));
foreach ($workerCode as $worker => $code) {
$this->cleanupWorkerProcess($worker);
}
}
public function wait()
public function wait($worker)
{
fgets($this->isWorker ? STDIN : $this->workerStdOut);
fgets($this->isWorker ? STDIN : $this->workerStdOut[$worker]);
}
public function notify()
public function notify($worker)
{
fwrite($this->isWorker ? STDOUT : $this->workerStdIn, "\n");
fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n");
}
}

View File

@ -0,0 +1,119 @@
--TEST--
Bug #76705: feof might hang on TLS streams in case of fragmented TLS records
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip openssl not loaded");
if (!function_exists("proc_open")) die("skip no proc_open");
?>
--FILE--
<?php
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug77390.pem.tmp';
$cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug77390-ca.pem.tmp';
$peerName = 'bug77390';
$clientCode = <<<'CODE'
$context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => '%s']]);
phpt_wait('server');
phpt_notify('proxy');
phpt_wait('proxy');
$fp = stream_socket_client("ssl://127.0.0.1:10012", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context);
stream_set_blocking($fp, false);
$read = [$fp];
$buf = '';
$printed = false;
while (stream_select($read, $write, $except, 1000)) {
$chunk = stream_get_contents($fp, 4096);
if ($chunk !== "") {
var_dump($chunk);
$buf .= $chunk;
} elseif (!$printed) {
$printed = true;
var_dump($chunk);
}
if ($buf === 'hello, world') {
break;
}
}
phpt_notify('server');
phpt_notify('proxy');
CODE;
$clientCode = sprintf($clientCode, $peerName);
$serverCode = <<<'CODE'
$context = stream_context_create(['ssl' => ['local_cert' => '%s']]);
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
$fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context);
phpt_notify();
$conn = stream_socket_accept($fp);
fwrite($conn, 'hello, world');
phpt_wait();
fclose($conn);
CODE;
$serverCode = sprintf($serverCode, $certFile);
$proxyCode = <<<'CODE'
phpt_wait();
$upstream = stream_socket_client("tcp://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT);
stream_set_blocking($upstream, false);
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
$server = stream_socket_server("tcp://127.0.0.1:10012", $errornum, $errorstr, $flags);
phpt_notify();
$conn = stream_socket_accept($server);
stream_set_blocking($conn, false);
$read = [$upstream, $conn];
while (stream_select($read, $write, $except, 1)) {
foreach ($read as $fp) {
$data = stream_get_contents($fp);
if ($fp === $conn) {
fwrite($upstream, $data);
} else {
if ($data !== '' && $data[0] === chr(23)) {
$parts = str_split($data, (int) ceil(strlen($data) / 3));
foreach ($parts as $part) {
fwrite($conn, $part);
usleep(1000);
}
} else {
fwrite($conn, $data);
}
}
}
if (feof($upstream)) {
break;
}
$read = [$upstream, $conn];
}
phpt_wait();
CODE;
include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$certificateGenerator->saveCaCert($cacertFile);
$certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile);
include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, [
'server' => $serverCode,
'proxy' => $proxyCode,
]);
?>
--CLEAN--
<?php
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug77390.pem.tmp');
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug77390-ca.pem.tmp');
?>
--EXPECT--
string(0) ""
string(12) "hello, world"

View File

@ -2453,30 +2453,22 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
alive = 0;
} else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
if (sslsock->ssl_active) {
int n;
do {
n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
if (n <= 0) {
int err = SSL_get_error(sslsock->ssl_handle, n);
if (err == SSL_ERROR_SYSCALL) {
int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
if (n <= 0) {
int err = SSL_get_error(sslsock->ssl_handle, n);
switch (err) {
case SSL_ERROR_SYSCALL:
alive = php_socket_errno() == EAGAIN;
break;
}
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
/* re-negotiate */
continue;
}
/* any other problem is a fatal error */
alive = 0;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
alive = 1;
break;
default:
/* any other problem is a fatal error */
alive = 0;
}
/* either peek succeeded or there was an error; we
* have set the alive flag appropriately */
break;
} while (1);
}
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
alive = 0;
}