summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml3
-rw-r--r--NEWS10
-rw-r--r--Zend/tests/bug73753.phpt29
-rw-r--r--Zend/tests/bug73792.phpt20
-rw-r--r--Zend/tests/concat_003.phpt6
-rw-r--r--Zend/zend_hash.c7
-rw-r--r--Zend/zend_vm_def.h6
-rw-r--r--Zend/zend_vm_execute.h24
-rw-r--r--ext/curl/interface.c19
-rw-r--r--ext/curl/tests/bug48203_multi-win32.phpt89
-rw-r--r--ext/curl/tests/bug48203_multi.phpt36
-rw-r--r--ext/curl/tests/server.inc86
-rw-r--r--ext/opcache/ZendAccelerator.c4
-rw-r--r--ext/openssl/xp_ssl.c17
-rw-r--r--ext/pdo_firebird/firebird_driver.c12
-rw-r--r--ext/zlib/tests/deflate_add_buffer_full.phpt53
-rw-r--r--ext/zlib/zlib.c19
-rw-r--r--sapi/cli/tests/bug67429.phpt7
-rw-r--r--sapi/cli/tests/php_cli_server.inc67
-rw-r--r--sapi/phpdbg/phpdbg.c2
-rw-r--r--sapi/phpdbg/phpdbg_list.c12
-rw-r--r--sapi/phpdbg/phpdbg_list.h1
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c35
-rw-r--r--sapi/phpdbg/tests/bug73704.phpt27
24 files changed, 386 insertions, 205 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 9a05c6a65c..ba0d1c132d 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -29,9 +29,6 @@ environment:
- THREAD_SAFE: 1
OPCACHE: 1
-matrix:
- fast_finish: true
-
services:
# the setup scripts have to be touched, once some other db version is used
- mysql
diff --git a/NEWS b/NEWS
index b79be92f36..d22471418e 100644
--- a/NEWS
+++ b/NEWS
@@ -3,10 +3,12 @@ PHP NEWS
?? ??? 2016 PHP 7.0.15
- Core:
+ . Fixed bug #73792 (invalid foreach loop hangs script). (Dmitry)
. Fixed bug #73663 ("Invalid opcode 65/16/8" occurs with a variable created
with list()). (Laruence)
. Fixed bug #73585 (Logging of "Internal Zend error - Missing class
information" missing class name). (Laruence)
+ . Fixed bug #73753 (unserialized array pointer not advancing). (David Walker)
- COM:
. Fixed bug #73679 (DOTNET read access violation using invalid codepage).
@@ -31,9 +33,7 @@ PHP NEWS
. Fixed bug #73615 (phpdbg without option never load .phpdbginit at startup).
(Bob)
. Fixed issue getting executable lines from custom wrappers. (Bob)
-
-- Apache2handler:
- . Fixed bug #61471 (POST request timeout did not handle correctly). (Zheng SHAO)
+ . Fixed bug #73704 (phpdbg shows the wrong line in files with shebang). (Bob)
- Reflection:
. Fixed bug #46103 (ReflectionObject memory leak). (Nikita)
@@ -42,6 +42,10 @@ PHP NEWS
. Fixed bug #73594 (dns_get_record does not populate $additional out parameter).
(Bruce Weirdan)
+- Zlib:
+ . Fixed bug #73373 (deflate_add does not verify that output was not truncated).
+ (Matt Bonneau)
+
08 Dec 2016 PHP 7.0.14
- Core:
diff --git a/Zend/tests/bug73753.phpt b/Zend/tests/bug73753.phpt
new file mode 100644
index 0000000000..9a77f62f56
--- /dev/null
+++ b/Zend/tests/bug73753.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #73753 Non packed arrays and duplication
+--FILE--
+<?php
+function iterate($current, $a, $result = null) {
+ if (!$current) {
+ return $result;
+ }
+
+ return iterate(getNext($a), $a, $current);
+}
+
+function getNext(&$a) {
+ return next($a);
+}
+
+function getCurrent($a) {
+ return current($a);
+}
+
+function traverse($a) {
+ return iterate(getCurrent($a), $a);
+}
+
+$arr = array(1 => 'foo', 'b' => 'bar', 'baz');
+var_dump(traverse($arr));
+?>
+--EXPECTF--
+string(3) "baz"
diff --git a/Zend/tests/bug73792.phpt b/Zend/tests/bug73792.phpt
new file mode 100644
index 0000000000..ac4f265aaf
--- /dev/null
+++ b/Zend/tests/bug73792.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #73792 (invalid foreach loop hangs script)
+--FILE--
+<?php
+$a = 'aaa';
+
+foreach ($a['bbb'] as &$value) {
+ echo 'loop';
+}
+
+unset($value);
+echo 'done';
+?>
+--EXPECTF--
+Warning: Illegal string offset 'bbb' in %sbug73792.php on line 4
+
+Fatal error: Uncaught Error: Cannot iterate on string offsets by reference in %sbug73792.php:4
+Stack trace:
+#0 {main}
+ thrown in %sbug73792.php on line 4
diff --git a/Zend/tests/concat_003.phpt b/Zend/tests/concat_003.phpt
index 07fabd1113..53d8d2f9a4 100644
--- a/Zend/tests/concat_003.phpt
+++ b/Zend/tests/concat_003.phpt
@@ -13,8 +13,8 @@ memory_limit=256m
$time = microtime(TRUE);
/* This might vary on Linux/Windows, so the worst case and also count in slow machines. */
-$t0_max = 0.1;
-$t1_max = 0.4;
+$t0_max = 0.3;
+$t1_max = 1.0;
$datas = [];
for ($i = 0; $i < 220000; $i++)
@@ -34,7 +34,7 @@ for ($i = 0; $i < 220000; $i++)
$t0 = microtime(TRUE) - $time;
var_dump($t0 < $t0_max);
-
+$time = microtime(TRUE);
$texts = '';
foreach ($datas AS $data)
{
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
index aecdac6379..322422da15 100644
--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@ -1757,7 +1757,7 @@ static zend_always_inline void zend_array_dup_packed_elements(HashTable *source,
static zend_always_inline uint32_t zend_array_dup_elements(HashTable *source, HashTable *target, int static_keys, int with_holes)
{
- uint32_t idx = 0;
+ uint32_t idx = 0;
Bucket *p = source->arData;
Bucket *q = target->arData;
Bucket *end = p + source->nNumUsed;
@@ -1785,7 +1785,7 @@ static zend_always_inline uint32_t zend_array_dup_elements(HashTable *source, Ha
ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
{
- uint32_t idx;
+ uint32_t idx;
HashTable *target;
IS_CONSISTENT(source);
@@ -1849,7 +1849,8 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
target->u.flags = (source->u.flags & ~(HASH_FLAG_PERSISTENT|ZEND_HASH_APPLY_COUNT_MASK)) | HASH_FLAG_APPLY_PROTECTION;
target->nTableMask = source->nTableMask;
target->nNextFreeElement = source->nNextFreeElement;
- target->nInternalPointer = HT_INVALID_IDX;
+ target->nInternalPointer = source->nInternalPointer;
+
HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
HT_HASH_RESET(target);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 3fe2f1dc5a..89725bd02d 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5878,6 +5878,12 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
array_ref = array_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
+ if (OP1_TYPE == IS_VAR && UNEXPECTED(array_ref == NULL)) {
+ zend_throw_error(NULL, "Cannot iterate on string offsets by reference");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ HANDLE_EXCEPTION();
+ }
if (Z_ISREF_P(array_ref)) {
array_ptr = Z_REFVAL_P(array_ref);
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 3e38c71436..5784ead38d 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3836,6 +3836,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER
if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
array_ref = array_ptr = NULL;
+ if (IS_CONST == IS_VAR && UNEXPECTED(array_ref == NULL)) {
+ zend_throw_error(NULL, "Cannot iterate on string offsets by reference");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ HANDLE_EXCEPTION();
+ }
if (Z_ISREF_P(array_ref)) {
array_ptr = Z_REFVAL_P(array_ref);
}
@@ -12331,6 +12337,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z
if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
array_ref = array_ptr = NULL;
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(array_ref == NULL)) {
+ zend_throw_error(NULL, "Cannot iterate on string offsets by reference");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ HANDLE_EXCEPTION();
+ }
if (Z_ISREF_P(array_ref)) {
array_ptr = Z_REFVAL_P(array_ref);
}
@@ -15799,6 +15811,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z
if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
array_ref = array_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1);
+ if (IS_VAR == IS_VAR && UNEXPECTED(array_ref == NULL)) {
+ zend_throw_error(NULL, "Cannot iterate on string offsets by reference");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ HANDLE_EXCEPTION();
+ }
if (Z_ISREF_P(array_ref)) {
array_ptr = Z_REFVAL_P(array_ref);
}
@@ -29641,6 +29659,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE
if (IS_CV == IS_VAR || IS_CV == IS_CV) {
array_ref = array_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ if (IS_CV == IS_VAR && UNEXPECTED(array_ref == NULL)) {
+ zend_throw_error(NULL, "Cannot iterate on string offsets by reference");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ HANDLE_EXCEPTION();
+ }
if (Z_ISREF_P(array_ref)) {
array_ptr = Z_REFVAL_P(array_ref);
}
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 65539d1acc..8a354a371f 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -2302,8 +2302,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
error = curl_easy_setopt(ch->cp, option, lval);
break;
case CURLOPT_SAFE_UPLOAD:
- lval = zval_get_long(zvalue);
- if (lval == 0) {
+ if (!zend_is_true(zvalue)) {
php_error_docref(NULL, E_WARNING, "Disabling safe uploads is no longer supported");
return FAILURE;
}
@@ -2639,13 +2638,11 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
break;
case CURLOPT_FOLLOWLOCATION:
- lval = zval_get_long(zvalue);
+ lval = zend_is_true(zvalue);
#if LIBCURL_VERSION_NUM < 0x071304
- if (PG(open_basedir) && *PG(open_basedir)) {
- if (lval != 0) {
- php_error_docref(NULL, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set");
- return FAILURE;
- }
+ if (lval && PG(open_basedir) && *PG(open_basedir)) {
+ php_error_docref(NULL, E_WARNING, "CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set");
+ return FAILURE;
}
#endif
error = curl_easy_setopt(ch->cp, option, lval);
@@ -2801,8 +2798,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
break;
case CURLOPT_RETURNTRANSFER:
- lval = zval_get_long(zvalue);
- if (lval) {
+ if (zend_is_true(zvalue)) {
ch->handlers->write->method = PHP_CURL_RETURN;
} else {
ch->handlers->write->method = PHP_CURL_STDOUT;
@@ -2878,8 +2874,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
}
case CURLINFO_HEADER_OUT:
- lval = zval_get_long(zvalue);
- if (lval == 1) {
+ if (zend_is_true(zvalue)) {
curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug);
curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch);
curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1);
diff --git a/ext/curl/tests/bug48203_multi-win32.phpt b/ext/curl/tests/bug48203_multi-win32.phpt
deleted file mode 100644
index 9016725080..0000000000
--- a/ext/curl/tests/bug48203_multi-win32.phpt
+++ /dev/null
@@ -1,89 +0,0 @@
---TEST--
-Variation of bug #48203 with curl_multi_exec (Crash when file pointers passed to curl are closed before calling curl_multi_exec)
---SKIPIF--
-<?php
-include 'skipif.inc';
-if(substr(PHP_OS, 0, 3) != 'WIN' ) {
- die('skip Windows only test');
-}
-?>
---FILE--
-<?php
-include 'server.inc';
-function checkForClosedFilePointer($curl_option, $description) {
- $fp = fopen(dirname(__FILE__) . '/bug48203.tmp', 'w');
-
- $ch1 = curl_init();
- $ch2 = curl_init();
-
- $options = array(
- CURLOPT_RETURNTRANSFER => 1,
- $curl_option => $fp,
- CURLOPT_URL => curl_cli_server_start()
- );
-
- // we also need to set CURLOPT_VERBOSE to test CURLOPT_STDERR properly
- if (CURLOPT_STDERR == $curl_option) {
- $options[CURLOPT_VERBOSE] = 1;
- }
-
- if (CURLOPT_INFILE == $curl_option) {
- $options[CURLOPT_UPLOAD] = 1;
- }
-
- curl_setopt_array($ch1, $options);
- curl_setopt_array($ch2, $options);
-
- fclose($fp); // <-- premature close of $fp caused a crash!
-
- $mh = curl_multi_init();
-
- curl_multi_add_handle($mh, $ch1);
- curl_multi_add_handle($mh, $ch2);
-
- $active = 0;
- do {
- curl_multi_exec($mh, $active);
- } while ($active > 0);
-
- curl_multi_remove_handle($mh, $ch1);
- curl_multi_remove_handle($mh, $ch2);
- curl_multi_close($mh);
-
- echo "Ok for $description\n";
-}
-
-$options_to_check = array(
- "CURLOPT_STDERR", "CURLOPT_WRITEHEADER", "CURLOPT_FILE", "CURLOPT_INFILE"
-);
-
-foreach($options_to_check as $option) {
- checkForClosedFilePointer(constant($option), $option);
-}
-
-?>
---CLEAN--
-<?php @unlink(dirname(__FILE__) . '/bug48203.tmp'); ?>
---EXPECTF--
-Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
-
-Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
-Ok for CURLOPT_STDERR
-%A
-
-Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %s on line %d
-
-Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %s on line %d
-Ok for CURLOPT_WRITEHEADER
-
-Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %s on line %d
-
-Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %s on line %d
-Hello World!
-Hello World!Hello World!
-Hello World!Ok for CURLOPT_FILE
-
-Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %s on line %d
-
-Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %s on line %d
-Ok for CURLOPT_INFILE
diff --git a/ext/curl/tests/bug48203_multi.phpt b/ext/curl/tests/bug48203_multi.phpt
index b582e78627..5f9e2ba6b2 100644
--- a/ext/curl/tests/bug48203_multi.phpt
+++ b/ext/curl/tests/bug48203_multi.phpt
@@ -3,14 +3,11 @@ Variation of bug #48203 with curl_multi_exec (Crash when file pointers passed to
--SKIPIF--
<?php
include 'skipif.inc';
-if(substr(PHP_OS, 0, 3) == 'WIN' ) {
- die('skip not for Windows');
-}
?>
--FILE--
<?php
include 'server.inc';
-function checkForClosedFilePointer($curl_option, $description) {
+function checkForClosedFilePointer($target_url, $curl_option, $description) {
$fp = fopen(dirname(__FILE__) . '/bug48203.tmp', 'w');
$ch1 = curl_init();
@@ -19,7 +16,7 @@ function checkForClosedFilePointer($curl_option, $description) {
$options = array(
CURLOPT_RETURNTRANSFER => 1,
$curl_option => $fp,
- CURLOPT_URL => curl_cli_server_start()
+ CURLOPT_URL => $target_url,
);
// we also need to set CURLOPT_VERBOSE to test CURLOPT_STDERR properly
@@ -50,6 +47,10 @@ function checkForClosedFilePointer($curl_option, $description) {
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
+ // Force curl to output results
+ fflush(STDERR);
+ fflush(STDOUT);
+
echo "Ok for $description\n";
}
@@ -57,31 +58,34 @@ $options_to_check = array(
"CURLOPT_STDERR", "CURLOPT_WRITEHEADER", "CURLOPT_FILE", "CURLOPT_INFILE"
);
+$target_url = curl_cli_server_start();
foreach($options_to_check as $option) {
- checkForClosedFilePointer(constant($option), $option);
+ checkForClosedFilePointer($target_url, constant($option), $option);
}
?>
--CLEAN--
<?php @unlink(dirname(__FILE__) . '/bug48203.tmp'); ?>
--EXPECTF--
-Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
-Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
%A
Ok for CURLOPT_STDERR
-%A
-Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %sbug48203_multi.php on line 36
-Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %s on line %d
+
+Warning: curl_multi_exec(): CURLOPT_WRITEHEADER resource has gone away, resetting to default in %s on line %d
Ok for CURLOPT_WRITEHEADER
-Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %s on line %d
-Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %sbug48203_multi.php on line 36
-%AOk for CURLOPT_FILE
+Warning: curl_multi_exec(): CURLOPT_FILE resource has gone away, resetting to default in %s on line %d
+Hello World!
+Hello World!Hello World!
+Hello World!Ok for CURLOPT_FILE
-Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %s on line %d
-Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %sbug48203_multi.php on line 36
+Warning: curl_multi_exec(): CURLOPT_INFILE resource has gone away, resetting to default in %s on line %d
Ok for CURLOPT_INFILE
diff --git a/ext/curl/tests/server.inc b/ext/curl/tests/server.inc
index 6d96a9850c..315fd68cc4 100644
--- a/ext/curl/tests/server.inc
+++ b/ext/curl/tests/server.inc
@@ -9,48 +9,64 @@ function curl_cli_server_start() {
return getenv('PHP_CURL_HTTP_REMOTE_SERVER');
}
- $php_executable = getenv('TEST_PHP_EXECUTABLE');
- $doc_root = __DIR__;
- $router = "responder/get.php";
-
- $descriptorspec = array(
- 0 => STDIN,
- 1 => STDOUT,
- 2 => STDERR,
- );
-
- if (substr(PHP_OS, 0, 3) == 'WIN') {
- $cmd = "{$php_executable} -t {$doc_root} -n -S " . PHP_CURL_SERVER_ADDRESS;
+ $php_executable = getenv('TEST_PHP_EXECUTABLE');
+ $doc_root = __DIR__;
+ $router = "responder/get.php";
+
+ $descriptorspec = array(
+ 0 => STDIN,
+ 1 => STDOUT,
+ 2 => STDERR,
+ );
+
+ if (substr(PHP_OS, 0, 3) == 'WIN') {
+ $cmd = "{$php_executable} -t {$doc_root} -n -S " . PHP_CURL_SERVER_ADDRESS;
+ $cmd .= " {$router}";
+ $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, $doc_root, NULL, array("bypass_shell" => true, "suppress_errors" => true));
+ } else {
+ $cmd = "exec {$php_executable} -t {$doc_root} -n -S " . PHP_CURL_SERVER_ADDRESS;
$cmd .= " {$router}";
- $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, $doc_root, NULL, array("bypass_shell" => true, "suppress_errors" => true));
- } else {
- $cmd = "exec {$php_executable} -t {$doc_root} -n -S " . PHP_CURL_SERVER_ADDRESS;
- $cmd .= " {$router}";
- $cmd .= " 2>/dev/null";
-
- $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root);
- }
+ $cmd .= " 2>/dev/null";
+
+ $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root);
+ }
- // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
- // it might not be listening yet...need to wait until fsockopen() call returns
- $i = 0;
- while (($i++ < 30) && !($fp = @fsockopen(PHP_CURL_SERVER_HOSTNAME, PHP_CURL_SERVER_PORT))) {
- usleep(10000);
+ // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
+ // it might not be listening yet...need to wait until fsockopen() call returns
+ $error = "Unable to connect to servers\n";
+ for ($i=0; $i < 60; $i++) {
+ usleep(25000); // 25ms per try
+ $status = proc_get_status($handle);
+ $fp = @fsockopen(PHP_CURL_SERVER_HOSTNAME, PHP_CURL_SERVER_PORT);
+ // Failure, the server is no longer running
+ if (!($status && $status['running'])) {
+ $error = "Server is not running\n";
+ break;
+ }
+ // Success, Connected to servers
+ if ($fp) {
+ $error = '';
+ break;
+ }
}
if ($fp) {
fclose($fp);
}
- register_shutdown_function(
- function($handle) use($router) {
- proc_terminate($handle);
- },
- $handle
- );
- // don't bother sleeping, server is already up
- // server can take a variable amount of time to be up, so just sleeping a guessed amount of time
- // does not work. this is why tests sometimes pass and sometimes fail. to get a reliable pass
- // sleeping doesn't work.
+ if ($error) {
+ echo $error;
+ proc_terminate($handle);
+ exit(1);
+ }
+
+ register_shutdown_function(
+ function($handle) use($router) {
+ proc_terminate($handle);
+ },
+ $handle
+ );
+
return PHP_CURL_SERVER_ADDRESS;
}
+
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 8844da6d59..676e3939a8 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -582,7 +582,7 @@ static void accel_use_shm_interned_strings(void)
for (j = 0; j < ce->constants_table.nNumUsed; j++) {
q = ce->constants_table.arData + j;
- if (!Z_TYPE(q->val) == IS_UNDEF) continue;
+ if (Z_TYPE(q->val) == IS_UNDEF) continue;
if (q->key) {
q->key = accel_new_interned_string(q->key);
}
@@ -592,7 +592,7 @@ static void accel_use_shm_interned_strings(void)
/* constant hash keys */
for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) {
p = EG(zend_constants)->arData + idx;
- if (!Z_TYPE(p->val) == IS_UNDEF) continue;
+ if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) {
p->key = accel_new_interned_string(p->key);
}
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index 208aafcd7b..f9697d0483 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -1599,8 +1599,8 @@ int php_openssl_setup_crypto(php_stream *stream,
if (sslsock->is_client) {
SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len);
} else {
- sslsock->alpn_ctx = (php_openssl_alpn_ctx *) emalloc(sizeof(php_openssl_alpn_ctx));
- sslsock->alpn_ctx->data = (unsigned char*)estrndup((const char*)alpn, alpn_len);
+ sslsock->alpn_ctx = (php_openssl_alpn_ctx *) pemalloc(sizeof(php_openssl_alpn_ctx), php_stream_is_persistent(stream));
+ sslsock->alpn_ctx->data = (unsigned char *) pestrndup((const char*)alpn, alpn_len, php_stream_is_persistent(stream));
sslsock->alpn_ctx->len = alpn_len;
SSL_CTX_set_alpn_select_cb(sslsock->ctx, server_alpn_callback, sslsock);
}
@@ -1632,6 +1632,13 @@ int php_openssl_setup_crypto(php_stream *stream,
php_error_docref(NULL, E_WARNING, "SSL handle creation failure");
SSL_CTX_free(sslsock->ctx);
sslsock->ctx = NULL;
+#ifdef HAVE_TLS_ALPN
+ if (sslsock->alpn_ctx) {
+ pefree(sslsock->alpn_ctx->data, php_stream_is_persistent(stream));
+ pefree(sslsock->alpn_ctx, php_stream_is_persistent(stream));
+ sslsock->alpn_ctx = NULL;
+ }
+#endif
return FAILURE;
} else {
SSL_set_ex_data(sslsock->ssl_handle, php_openssl_get_ssl_stream_data_index(), stream);
@@ -2137,6 +2144,12 @@ static int php_openssl_sockop_close(php_stream *stream, int close_handle) /* {{{
SSL_CTX_free(sslsock->ctx);
sslsock->ctx = NULL;
}
+#ifdef HAVE_TLS_ALPN
+ if (sslsock->alpn_ctx) {
+ pefree(sslsock->alpn_ctx->data, php_stream_is_persistent(stream));
+ pefree(sslsock->alpn_ctx, php_stream_is_persistent(stream));
+ }
+#endif
#ifdef PHP_WIN32
if (sslsock->s.socket == -1)
sslsock->s.socket = SOCK_ERR;
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
index b26939ccd2..91cd3593ea 100644
--- a/ext/pdo_firebird/firebird_driver.c
+++ b/ext/pdo_firebird/firebird_driver.c
@@ -238,14 +238,16 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sq
/* execute the statement */
if (isc_dsql_execute2(H->isc_status, &H->tr, &stmt, PDO_FB_SQLDA_VERSION, &in_sqlda, &out_sqlda)) {
RECORD_ERROR(dbh);
- return -1;
+ ret = -1;
+ goto free_statement;
}
/* find out how many rows were affected */
if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), const_cast(info_count),
sizeof(result), result)) {
RECORD_ERROR(dbh);
- return -1;
+ ret = -1;
+ goto free_statement;
}
if (result[0] == isc_info_sql_records) {
@@ -265,6 +267,12 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sq
RECORD_ERROR(dbh);
}
+free_statement:
+
+ if (isc_dsql_free_statement(H->isc_status, &stmt, DSQL_drop)) {
+ RECORD_ERROR(dbh);
+ }
+
return ret;
}
/* }}} */
diff --git a/ext/zlib/tests/deflate_add_buffer_full.phpt b/ext/zlib/tests/deflate_add_buffer_full.phpt
new file mode 100644
index 0000000000..a2b3fc4ab0
--- /dev/null
+++ b/ext/zlib/tests/deflate_add_buffer_full.phpt
@@ -0,0 +1,53 @@
+--TEST--
+Test deflate_add() buffer issue with data that fills deflate buffer while using ZLIB_SYNC_FLUSH on ZLIB_ENCODING_RAW.
+--SKIPIF--
+<?php
+if (!extension_loaded("zlib")) {
+ print "skip - ZLIB extension not loaded";
+}
+?>
+--FILE--
+<?php
+
+/*
+ * When using ZLIB_ENCODING_RAW, the deflated buffer should always end in 00 00 ff ff
+ * Many streaming deflate users rely on this behaviour.
+ * example: websocket permessage-deflate extension
+ * (https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#section-7.2.1)
+ *
+ * Prior to fixing, the output buffer size was not being checked. According to the zlib
+ * manual, deflate must be called again with more buffer space.
+ */
+
+$deflateContext = deflate_init(ZLIB_ENCODING_RAW);
+
+$deflated = deflate_add(
+ $deflateContext,
+ hex2bin("255044462d312e320a25c7ec8fa20a362030206f626a0a3c3c2f4c656e6774682037203020522f46696c746572202f466c6174654465636f64653e3e0a737472"),
+ ZLIB_SYNC_FLUSH
+);
+
+echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
+
+$deflated = deflate_add(
+ $deflateContext,
+ hex2bin("65616d0a789c7d53c16ed43010bde7c037f85824766a7bc6767c2ca8a00a016a1b2edcb2dbecaed1266937d98afe3d6327363794439437e3f17b6f5e242821e3"),
+ ZLIB_SYNC_FLUSH
+);
+
+echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
+
+$deflated = deflate_add(
+ $deflateContext,
+ hex2bin("b3be777df5525d3f90384cd58b50a9945fbb5e7c6cb8c89fca8156c688665f2de794504a81f75658a7c1d54a347d7575fb6e17ba617edffcae9c84da3aee6c9e"),
+ ZLIB_SYNC_FLUSH
+);
+
+echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
+?>
+===DONE===
+--EXPECTF--
+0000ffff
+0000ffff
+0000ffff
+===DONE===
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index d9d6be1638..bbe1334ca9 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -1115,7 +1115,7 @@ PHP_FUNCTION(deflate_add)
{
zend_string *out;
char *in_buf;
- size_t in_len, out_size;
+ size_t in_len, out_size, buffer_used;
zval *res;
z_stream *ctx;
zend_long flush_type = Z_SYNC_FLUSH;
@@ -1157,6 +1157,7 @@ PHP_FUNCTION(deflate_add)
out_size = PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in + in_len);
out_size = (ctx->total_out >= out_size) ? 16 : (out_size - ctx->total_out);
out_size = (out_size < 16) ? 16 : out_size;
+ out_size += 64;
out = zend_string_alloc(out_size, 0);
ctx->next_in = (Bytef *) in_buf;
@@ -1164,7 +1165,21 @@ PHP_FUNCTION(deflate_add)
ctx->avail_in = in_len;
ctx->avail_out = ZSTR_LEN(out);
- status = deflate(ctx, flush_type);
+ buffer_used = 0;
+
+ do {
+ if (ctx->avail_out == 0) {
+ /* more output buffer space needed; realloc and try again */
+ /* adding 64 more bytes solved every issue I have seen */
+ /* the + 1 is for the string terminator added below */
+ out = zend_string_realloc(out, ZSTR_LEN(out) + 64 + 1, 0);
+ ctx->avail_out = 64;
+ ctx->next_out = (Bytef *) ZSTR_VAL(out) + buffer_used;
+ }
+ status = deflate(ctx, flush_type);
+ buffer_used = ZSTR_LEN(out) - ctx->avail_out;
+ } while (status == Z_OK && ctx->avail_out == 0);
+
switch (status) {
case Z_OK:
ZSTR_LEN(out) = (char *) ctx->next_out - ZSTR_VAL(out);
diff --git a/sapi/cli/tests/bug67429.phpt b/sapi/cli/tests/bug67429.phpt
index 856946b29d..1c861be899 100644
--- a/sapi/cli/tests/bug67429.phpt
+++ b/sapi/cli/tests/bug67429.phpt
@@ -8,8 +8,9 @@ include "skipif.inc";
<?php
include "php_cli_server.inc";
+// This creates a new server for each response code
foreach ([308, 426] as $code) {
- php_cli_server_start(<<<PHP
+ $proc_handle = php_cli_server_start(<<<PHP
http_response_code($code);
PHP
);
@@ -34,6 +35,10 @@ HEADER
}
fclose($fp);
+ // Shutdown the servers or another server may not be able to start
+ // because of the this server still being bound to the port
+
+ php_cli_server_stop($proc_handle);
}
?>
--EXPECTF--
diff --git a/sapi/cli/tests/php_cli_server.inc b/sapi/cli/tests/php_cli_server.inc
index 6b1e90c4dc..6e7b70cb60 100644
--- a/sapi/cli/tests/php_cli_server.inc
+++ b/sapi/cli/tests/php_cli_server.inc
@@ -33,29 +33,62 @@ function php_cli_server_start($code = 'echo "Hello world";', $router = 'index.ph
$handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root);
}
-
- // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
- // it might not be listening yet...need to wait until fsockopen() call returns
- $i = 0;
- while (($i++ < 30) && !($fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT))) {
- usleep(10000);
+
+ // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
+ // it might not be listening yet...need to wait until fsockopen() call returns
+ $error = "Unable to connect to servers\n";
+ for ($i=0; $i < 60; $i++) {
+ usleep(25000); // 25ms per try
+ $status = proc_get_status($handle);
+ $fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT);
+ // Failure, the server is no longer running
+ if (!($status && $status['running'])) {
+ $error = "Server is not running\n";
+ break;
+ }
+ // Success, Connected to servers
+ if ($fp) {
+ $error = '';
+ break;
+ }
}
if ($fp) {
fclose($fp);
}
- register_shutdown_function(
- function($handle) use($router) {
- proc_terminate($handle);
- @unlink(__DIR__ . "/{$router}");
- },
- $handle
- );
- // don't bother sleeping, server is already up
- // server can take a variable amount of time to be up, so just sleeping a guessed amount of time
- // does not work. this is why tests sometimes pass and sometimes fail. to get a reliable pass
- // sleeping doesn't work.
+ if ($error) {
+ echo $error;
+ proc_terminate($handle);
+ exit(1);
+ }
+
+ register_shutdown_function(
+ function($handle) use($router) {
+ proc_terminate($handle);
+ @unlink(__DIR__ . "/{$router}");
+ },
+ $handle
+ );
+
+ return $handle;
+}
+
+function php_cli_server_stop($handle) {
+ $success = FALSE;
+ if ($handle) {
+ proc_terminate($handle);
+ /* Wait for server to shutdown */
+ for ($i = 0; $i < 60; $i++) {
+ $status = proc_get_status($handle);
+ if (!($status && $status['running'])) {
+ $success = TRUE;
+ break;
+ }
+ usleep(25000);
+ }
+ }
+ return $success;
}
?>
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index 9cc60286c5..8153772368 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -1576,7 +1576,7 @@ phpdbg_main:
quit_immediately = phpdbg_startup_run > 1;
/* set exec if present on command line */
- if (!read_from_stdin && argc > php_optind && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
+ if (!read_from_stdin && argc > php_optind) {
if (!exec && strlen(argv[php_optind])) {
exec = strdup(argv[php_optind]);
}
diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c
index 1b70039fda..34e9187f52 100644
--- a/sapi/phpdbg/phpdbg_list.c
+++ b/sapi/phpdbg/phpdbg_list.c
@@ -250,7 +250,6 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) {
memcpy(data.buf, bufptr, data.len);
}
memset(data.buf + data.len, 0, ZEND_MMAP_AHEAD + 1);
- data.filename = filename;
data.line[0] = 0;
memset(&fake, 0, sizeof(fake));
@@ -283,10 +282,9 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) {
return NULL;
}
- dataptr->filename = estrdup(dataptr->filename);
dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
- zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr);
- phpdbg_resolve_pending_file_break(filename);
+ zend_hash_add_ptr(&PHPDBG_G(file_sources), ret->filename, dataptr);
+ phpdbg_resolve_pending_file_break(ZSTR_VAL(ret->filename));
fake.opened_path = NULL;
zend_file_handle_dtor(&fake);
@@ -321,9 +319,7 @@ zend_op_array *phpdbg_init_compile_file(zend_file_handle *file, int type) {
return NULL;
}
- filename = (char *)(file->opened_path ? ZSTR_VAL(file->opened_path) : file->filename);
-
- dataptr = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), filename, strlen(filename));
+ dataptr = zend_hash_find_ptr(&PHPDBG_G(file_sources), op_array->filename);
ZEND_ASSERT(dataptr != NULL);
dataptr->op_array = *op_array;
@@ -370,7 +366,6 @@ zend_op_array *phpdbg_compile_string(zval *source_string, char *filename) {
dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
zend_hash_add_ptr(&PHPDBG_G(file_sources), fake_name, dataptr);
- dataptr->filename = estrndup(ZSTR_VAL(fake_name), ZSTR_LEN(fake_name));
zend_string_release(fake_name);
dataptr->op_array = *op_array;
@@ -387,7 +382,6 @@ void phpdbg_free_file_source(zval *zv) {
if (data->buf) {
efree(data->buf);
}
- efree(data->filename);
destroy_op_array(&data->op_array);
diff --git a/sapi/phpdbg/phpdbg_list.h b/sapi/phpdbg/phpdbg_list.h
index c011b9598a..62ded66cf0 100644
--- a/sapi/phpdbg/phpdbg_list.h
+++ b/sapi/phpdbg/phpdbg_list.h
@@ -42,7 +42,6 @@ void phpdbg_init_list(void);
void phpdbg_list_update(void);
typedef struct {
- char *filename;
char *buf;
size_t len;
#if HAVE_MMAP
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 4ee27d1beb..450e57d02e 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -544,6 +544,7 @@ int phpdbg_compile_stdin(zend_string *code) {
PHPDBG_G(exec_len) = 1;
{ /* remove leading ?> from source */
int i;
+ /* remove trailing data after zero byte, used for avoiding conflicts in eval()'ed code snippets */
zend_string *source_path = strpprintf(0, "-%c%p", 0, PHPDBG_G(ops)->opcodes);
phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), source_path);
dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
@@ -553,9 +554,6 @@ int phpdbg_compile_stdin(zend_string *code) {
zend_hash_str_update_ptr(&PHPDBG_G(file_sources), "-", 1, data);
zend_string_release(source_path);
- efree(data->filename);
- data->filename = estrdup("-");
-
for (i = 1; i <= data->lines; i++) {
data->line[i] -= 2;
}
@@ -572,7 +570,10 @@ int phpdbg_compile(void) /* {{{ */
{
zend_file_handle fh;
char *buf;
+ char *start_line = NULL;
size_t len;
+ size_t start_line_len;
+ int i;
if (!PHPDBG_G(exec)) {
phpdbg_error("inactive", "type=\"nocontext\"", "No execution context");
@@ -591,7 +592,10 @@ int phpdbg_compile(void) /* {{{ */
}
case '\n':
CG(start_lineno) = 2;
- fh.handle.stream.mmap.len -= fh.handle.stream.mmap.buf - buf;
+ start_line_len = fh.handle.stream.mmap.buf - buf;
+ start_line = emalloc(start_line_len);
+ memcpy(start_line, buf, start_line_len);
+ fh.handle.stream.mmap.len -= start_line_len;
end = fh.handle.stream.mmap.buf;
}
} while (fh.handle.stream.mmap.buf + 1 < end);
@@ -599,6 +603,29 @@ int phpdbg_compile(void) /* {{{ */
PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE);
+ /* prepend shebang line to file_source */
+ if (start_line) {
+ phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename);
+
+ dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
+ PHPDBG_G(file_sources).pDestructor = NULL;
+ zend_hash_del(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename);
+ PHPDBG_G(file_sources).pDestructor = dtor;
+
+ data = erealloc(data, sizeof(phpdbg_file_source) + sizeof(uint) * ++data->lines);
+ memmove(data->line + 1, data->line, sizeof(uint) * data->lines);
+ data->line[0] = 0;
+ data->buf = erealloc(data->buf, data->len + start_line_len);
+ memmove(data->buf + start_line_len, data->buf, data->len * sizeof(uint));
+ memcpy(data->buf, start_line, start_line_len);
+ efree(start_line);
+ data->len += start_line_len;
+ for (i = 1; i <= data->lines; i++) {
+ data->line[i] += start_line_len;
+ }
+ zend_hash_update_ptr(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename, data);
+ }
+
fh.handle.stream.mmap.buf = buf;
fh.handle.stream.mmap.len = len;
zend_destroy_file_handle(&fh);
diff --git a/sapi/phpdbg/tests/bug73704.phpt b/sapi/phpdbg/tests/bug73704.phpt
new file mode 100644
index 0000000000..a3ee92b126
--- /dev/null
+++ b/sapi/phpdbg/tests/bug73704.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #73704 (phpdbg shows the wrong line in files with shebang)
+--PHPDBG--
+list 6
+b 4
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> 00001: #!/usr/bin/env php
+ 00002: <?php
+ 00003:
+ 00004: echo 1;
+ 00005:
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 1;
+ 00005:
+prompt> 1
+[Script ended normally]
+prompt>
+--FILE--
+#!/usr/bin/env php
+<?php
+
+echo 1;