diff options
| -rw-r--r-- | .appveyor.yml | 3 | ||||
| -rw-r--r-- | NEWS | 10 | ||||
| -rw-r--r-- | Zend/tests/bug73753.phpt | 29 | ||||
| -rw-r--r-- | Zend/tests/bug73792.phpt | 20 | ||||
| -rw-r--r-- | Zend/tests/concat_003.phpt | 6 | ||||
| -rw-r--r-- | Zend/zend_hash.c | 7 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 6 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 24 | ||||
| -rw-r--r-- | ext/curl/interface.c | 19 | ||||
| -rw-r--r-- | ext/curl/tests/bug48203_multi-win32.phpt | 89 | ||||
| -rw-r--r-- | ext/curl/tests/bug48203_multi.phpt | 36 | ||||
| -rw-r--r-- | ext/curl/tests/server.inc | 86 | ||||
| -rw-r--r-- | ext/opcache/ZendAccelerator.c | 4 | ||||
| -rw-r--r-- | ext/openssl/xp_ssl.c | 17 | ||||
| -rw-r--r-- | ext/pdo_firebird/firebird_driver.c | 12 | ||||
| -rw-r--r-- | ext/zlib/tests/deflate_add_buffer_full.phpt | 53 | ||||
| -rw-r--r-- | ext/zlib/zlib.c | 19 | ||||
| -rw-r--r-- | sapi/cli/tests/bug67429.phpt | 7 | ||||
| -rw-r--r-- | sapi/cli/tests/php_cli_server.inc | 67 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg.c | 2 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg_list.c | 12 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg_list.h | 1 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg_prompt.c | 35 | ||||
| -rw-r--r-- | sapi/phpdbg/tests/bug73704.phpt | 27 |
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 @@ -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; |
