From 0c982798e01e5a48765aa5352f96066e77e36efd Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 16:24:34 +0200 Subject: [PATCH 01/31] Fixed bug #51800 proc_open on Windows hangs forever This loop can block for some minutes, theoretically. Practially however, this is a 99% non issue for a normal use case. This is required because read() is synchronous. The PHP streams API wants to fill its internal buffers, therefore it might try to read some more data than user has demanded. Also, for a case where we want to read X bytes, but neither enough data nor EOF arrives, read() will block until it could fill the buffer. If a counterpart station runs slowly or delivers not all the data at once, read() would still be waiting. If we quit too early, we possibly could loose some data from the pipe. Thus it has to emulate the read() behaviour, but obviously not completely, just to some grade. Reading big data amount is for sure an issue on any platforms, it depends on the pipe buffer size, which is controlled by the system. On Windows, the buffer size seems to be way too small, which causes buffer congestion and a dead lock. It is essential to read the pipe descriptors simultaneously and possibly in the same order as the opposite writes them. Thus, this will work with smaller buffer data sizes passed through pipes. As MSDN states, anonymous pipes don't support asynchronous operations. Neither anonymous pipes do support select() as they are not SOCKETs but file descriptors. Consequently - bigger data sizes will need a better solution based on threads. However it is much more expencive. Maybe a better solution could be exporting a part of the internal doing as a userspace function which could perform some kind of lookahead operation on the pipe descriptor. This is just the first stone, depending on the user feedback we might go for further improvements in this area. --- NEWS | 1 + .../tests/streams/proc_open_bug51800.phpt | 91 +++++++++++++++++++ .../streams/proc_open_bug51800_right.phpt | 75 +++++++++++++++ .../tests/streams/proc_open_bug60120.phpt | 67 ++++++++++++++ .../tests/streams/proc_open_bug64438.phpt | 66 ++++++++++++++ main/streams/plain_wrapper.c | 28 ++++++ 6 files changed, 328 insertions(+) create mode 100644 ext/standard/tests/streams/proc_open_bug51800.phpt create mode 100644 ext/standard/tests/streams/proc_open_bug51800_right.phpt create mode 100644 ext/standard/tests/streams/proc_open_bug60120.phpt create mode 100644 ext/standard/tests/streams/proc_open_bug64438.phpt diff --git a/NEWS b/NEWS index 2942c720edc..50d997875cc 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ PHP NEWS as 6.2 (instead of 6.3)). (Christian Wenz) . Fixed bug #67633 (A foreach on an array returned from a function not doing copy-on-write). (Nikita) + . Fixed bug #51800 (proc_open on Windows hangs forever). (Anatol) - FPM: . Fixed bug #65641 (PHP-FPM incorrectly defines the SCRIPT_NAME variable diff --git a/ext/standard/tests/streams/proc_open_bug51800.phpt b/ext/standard/tests/streams/proc_open_bug51800.phpt new file mode 100644 index 00000000000..024d9cd6c69 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800.phpt @@ -0,0 +1,91 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever +--SKIPIF-- + +--XFAIL-- +pipes have to be read/written simultaneously +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +unlink($callee); + +?> +===DONE=== +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(10000) "a%s" + ["stderr"]=> + string(10000) "b%s" +} +int(10000) +int(10000) +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug51800_right.phpt b/ext/standard/tests/streams/proc_open_bug51800_right.phpt new file mode 100644 index 00000000000..bab37a8ba41 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800_right.phpt @@ -0,0 +1,75 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever, the right way to do it +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +unlink($callee); + +?> +===DONE=== +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(10000) "a%s" + ["stderr"]=> + string(10000) "b%s" +} +int(10000) +int(10000) +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug60120.phpt b/ext/standard/tests/streams/proc_open_bug60120.phpt new file mode 100644 index 00000000000..978cbe62fe8 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug60120.phpt @@ -0,0 +1,67 @@ +--TEST-- +Bug #60120 proc_open hangs with stdin/out with 2048+ bytes +--FILE-- + true, 'binary_pipes' => true, 'bypass_shell' => false)); +$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); + +foreach ($pipes as $pipe) { + stream_set_blocking($pipe, false); +} +$writePipes = array($pipes[0]); +$stdinLen = strlen($stdin); +$stdinOffset = 0; + +unset($pipes[0]); + +while ($pipes || $writePipes) { + $r = $pipes; + $w = $writePipes; + $e = null; + $n = stream_select($r, $w, $e, 60); + + if (false === $n) { + break; + } elseif ($n === 0) { + proc_terminate($process); + + } + if ($w) { + $written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); + if (false !== $written) { + $stdinOffset += $written; + } + if ($stdinOffset >= $stdinLen) { + fclose($writePipes[0]); + $writePipes = null; + } + } + + foreach ($r as $pipe) { + $type = array_search($pipe, $pipes); + $data = fread($pipe, 8192); + var_dump($data); + if (false === $data || feof($pipe)) { + fclose($pipe); + unset($pipes[$type]); + } + } +} + + +?> +===DONE=== +--EXPECTF-- +string(2049) "%s" +string(2049) "%s" +string(0) "" +string(0) "" +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug64438.phpt b/ext/standard/tests/streams/proc_open_bug64438.phpt new file mode 100644 index 00000000000..e3288518d7f --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug64438.phpt @@ -0,0 +1,66 @@ +--TEST-- +Bug #64438 proc_open hangs with stdin/out with 4097+ bytes +--FILE-- + true, 'binary_pipes' => true, 'bypass_shell' => false)); +$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); + +foreach ($pipes as $pipe) { + stream_set_blocking($pipe, false); +} +$writePipes = array($pipes[0]); +$stdinLen = strlen($stdin); +$stdinOffset = 0; + +unset($pipes[0]); + +while ($pipes || $writePipes) { + $r = $pipes; + $w = $writePipes; + $e = null; + $n = stream_select($r, $w, $e, 60); + + if (false === $n) { + break; + } elseif ($n === 0) { + proc_terminate($process); + + } + if ($w) { + $written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); + if (false !== $written) { + $stdinOffset += $written; + } + if ($stdinOffset >= $stdinLen) { + fclose($writePipes[0]); + $writePipes = null; + } + } + + foreach ($r as $pipe) { + $type = array_search($pipe, $pipes); + $data = fread($pipe, 8192); + var_dump($data); + if (false === $data || feof($pipe)) { + fclose($pipe); + unset($pipes[$type]); + } + } +} + +?> +===DONE=== +--EXPECTF-- +string(4097) "%s" +string(4097) "%s" +string(0) "" +string(0) "" +===DONE=== + diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index a50662b78e4..20ec7c2423c 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -348,6 +348,34 @@ static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS assert(data != NULL); if (data->fd >= 0) { +#ifdef PHP_WIN32 + php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract; + + if (self->is_pipe || self->is_process_pipe) { + HANDLE ph = (HANDLE)_get_osfhandle(data->fd); + int retry = 0; + DWORD avail_read = 0; + + do { + /* Look ahead to get the available data amount to read. Do the same + as read() does, however not blocking forever. In case it failed, + no data will be read (better than block). */ + if (!PeekNamedPipe(ph, NULL, 0, NULL, &avail_read, NULL)) { + break; + } + /* If there's nothing to read, wait in 100ms periods. */ + if (0 == avail_read) { + usleep(100000); + } + } while (0 == avail_read && retry++ < 180); + + /* Reduce the required data amount to what is available, otherwise read() + will block.*/ + if (avail_read < count) { + count = avail_read; + } + } +#endif ret = read(data->fd, buf, count); if (ret == (size_t)-1 && errno == EINTR) { From 7e16bb263f959ddbb5ea9eac8326db9101dd5d5e Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 16:28:12 +0200 Subject: [PATCH 02/31] updated NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index be52e3f0da6..67bcda61538 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PHP NEWS as 6.2 (instead of 6.3)). (Christian Wenz) . Fixed bug #67633 (A foreach on an array returned from a function not doing copy-on-write). (Nikita) + . Fixed bug #51800 (proc_open on Windows hangs forever). (Anatol) - FPM: . Fixed bug #65641 (PHP-FPM incorrectly defines the SCRIPT_NAME variable From 46aa2c396bf32b81c76ed2330e8e116eef8886a8 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 17:27:24 +0200 Subject: [PATCH 03/31] increase the polling period to not to break existing behaviours --- main/streams/plain_wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 20ec7c2423c..4b5dc55276f 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -367,7 +367,7 @@ static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS if (0 == avail_read) { usleep(100000); } - } while (0 == avail_read && retry++ < 180); + } while (0 == avail_read && retry++ < 320); /* Reduce the required data amount to what is available, otherwise read() will block.*/ From e15be6c8cd9fc04a3e527c9470d7f8c773200d7c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 29 Sep 2014 19:41:00 +0400 Subject: [PATCH 04/31] Use more readable inline functions --- Zend/zend_execute.c | 10 ++++--- Zend/zend_execute.h | 63 ++++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c44456d7ae3..0c15e06b6c8 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1610,11 +1610,13 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data */ zend_execute_data *execute_data; uint32_t num_args = call->num_args; + size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval); EG(argument_stack) = zend_vm_stack_new_page( - MAX(ZEND_VM_STACK_PAGE_SIZE, - ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args))); - EG(argument_stack)->prev = NULL; + EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE) ? + ZEND_VM_STACK_PAGE_SIZE : + ZEND_VM_STACK_PAGE_ALIGNED_SIZE(stack_size), + NULL); execute_data = zend_vm_stack_push_call_frame( (zend_function*)op_array, @@ -1664,7 +1666,7 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args; /* copy call frame into new stack segment */ - zend_vm_stack_extend(used_stack TSRMLS_CC); + zend_vm_stack_extend(used_stack * sizeof(zval) TSRMLS_CC); new_call = (zend_execute_data*)EG(argument_stack)->top; EG(argument_stack)->top += used_stack; *new_call = *call; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 334a4ccc038..193da6ba6c0 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -137,7 +137,9 @@ ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *s ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC); /* dedicated Zend executor functions - do not use! */ -#define ZEND_VM_STACK_PAGE_SIZE (16 * 1024) /* should be a power of 2 */ +#define ZEND_VM_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */ + +#define ZEND_VM_STACK_PAGE_SIZE (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval)) struct _zend_vm_stack { zval *top; @@ -145,33 +147,30 @@ struct _zend_vm_stack { zend_vm_stack prev; }; -#define ZEND_VM_STACK_HEADER_SLOT \ +#define ZEND_VM_STACK_HEADER_SLOTS \ ((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) +#define ZEND_VM_STACK_FREE_PAGE_SIZE \ + ((ZEND_VM_STACK_PAGE_SLOTS - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval)) + +#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size) \ + (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE - 1)) & ~ZEND_VM_STACK_PAGE_SIZE) + #define ZEND_VM_STACK_ELEMETS(stack) \ - (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT) + (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOTS) -#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ - do { \ - if (UNEXPECTED(((count) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) > \ - (size_t)(((char*)EG(argument_stack)->end) - \ - ((char*)EG(argument_stack)->top)))) { \ - zend_vm_stack_extend((count) TSRMLS_CC); \ - } \ - } while (0) - -static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { - zend_vm_stack page = (zend_vm_stack)emalloc(count * ZEND_MM_ALIGNED_SIZE(sizeof(zval))); +static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) { + zend_vm_stack page = (zend_vm_stack)emalloc(size); page->top = ZEND_VM_STACK_ELEMETS(page); - page->end = (zval*)page + count; - page->prev = NULL; + page->end = (zval*)((char*)page + size); + page->prev = prev; return page; } static zend_always_inline void zend_vm_stack_init(TSRMLS_D) { - EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE); + EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL); EG(argument_stack)->top++; } @@ -186,16 +185,24 @@ static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) } } -static zend_always_inline void zend_vm_stack_extend(uint32_t count TSRMLS_DC) +static zend_always_inline void zend_vm_stack_extend(size_t size TSRMLS_DC) { - uint32_t size = count * ZEND_MM_ALIGNED_SIZE(sizeof(zval)); - zend_vm_stack p = zend_vm_stack_new_page( - (size >= (ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) ? - (size + ((ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) & - ~((ZEND_VM_STACK_PAGE_SIZE * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) : - ZEND_VM_STACK_PAGE_SIZE); - p->prev = EG(argument_stack); - EG(argument_stack) = p; + EG(argument_stack) = zend_vm_stack_new_page( + EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE) ? + ZEND_VM_STACK_PAGE_SIZE : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size), + EG(argument_stack)); +} + +static zend_always_inline zval* zend_vm_stack_alloc(size_t size TSRMLS_DC) +{ + char *top = (char*)EG(argument_stack)->top; + + if (UNEXPECTED(size > (size_t)(((char*)EG(argument_stack)->end) - top))) { + zend_vm_stack_extend(size TSRMLS_CC); + top = (char*)EG(argument_stack)->top; + } + EG(argument_stack)->top = (zval*)(top + size); + return (zval*)top; } static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, uint32_t num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) @@ -206,9 +213,7 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_ if (ZEND_USER_CODE(func->type)) { used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args); } - ZEND_VM_STACK_GROW_IF_NEEDED(used_stack); - call = (zend_execute_data*)EG(argument_stack)->top; - EG(argument_stack)->top += used_stack; + call = (zend_execute_data*)zend_vm_stack_alloc(used_stack * sizeof(zval) TSRMLS_CC); call->func = func; call->num_args = 0; call->flags = flags; From 91d3cd85593a19ff6ab3c334f74198472788021d Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 18:11:06 +0200 Subject: [PATCH 05/31] better test cleanup and even force the XFAIL to fail as it would take too long anyway, even if it passes --- ext/standard/tests/streams/proc_open_bug51800.phpt | 10 +++++++--- .../tests/streams/proc_open_bug51800_right.phpt | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ext/standard/tests/streams/proc_open_bug51800.phpt b/ext/standard/tests/streams/proc_open_bug51800.phpt index 024d9cd6c69..53cafd85551 100644 --- a/ext/standard/tests/streams/proc_open_bug51800.phpt +++ b/ext/standard/tests/streams/proc_open_bug51800.phpt @@ -2,6 +2,7 @@ Bug #51800 proc_open on Windows hangs forever --SKIPIF-- $stderr, ), strlen($stdout), strlen($stderr)); -unlink($callee); - ?> ===DONE=== +--CLEAN-- + --EXPECTF-- array(3) { ["status"]=> diff --git a/ext/standard/tests/streams/proc_open_bug51800_right.phpt b/ext/standard/tests/streams/proc_open_bug51800_right.phpt index bab37a8ba41..b14fed2e5df 100644 --- a/ext/standard/tests/streams/proc_open_bug51800_right.phpt +++ b/ext/standard/tests/streams/proc_open_bug51800_right.phpt @@ -2,7 +2,7 @@ Bug #51800 proc_open on Windows hangs forever, the right way to do it --FILE-- $stderr, ), strlen($stdout), strlen($stderr)); -unlink($callee); - ?> ===DONE=== +--CLEAN-- + --EXPECTF-- array(3) { ["status"]=> From 859913f6d40611ff3987c6ddee7aa9427d94988c Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 18:12:25 +0200 Subject: [PATCH 06/31] fix tests on linux --- ext/standard/tests/streams/proc_open_bug60120.phpt | 6 +++++- ext/standard/tests/streams/proc_open_bug64438.phpt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/streams/proc_open_bug60120.phpt b/ext/standard/tests/streams/proc_open_bug60120.phpt index 978cbe62fe8..8768257a2ea 100644 --- a/ext/standard/tests/streams/proc_open_bug60120.phpt +++ b/ext/standard/tests/streams/proc_open_bug60120.phpt @@ -4,7 +4,11 @@ Bug #60120 proc_open hangs with stdin/out with 2048+ bytes Date: Mon, 29 Sep 2014 20:18:33 +0200 Subject: [PATCH 07/31] one more test to illustrate transfer of an arbitrary data amount throug pipes --- .../streams/proc_open_bug51800_right2.phpt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 ext/standard/tests/streams/proc_open_bug51800_right2.phpt diff --git a/ext/standard/tests/streams/proc_open_bug51800_right2.phpt b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt new file mode 100644 index 00000000000..69c75cf2630 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt @@ -0,0 +1,84 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever, the right way to do it with more data +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(1000000) "a%s" + ["stderr"]=> + string(1000000) "b%s" +} +int(1000000) +int(1000000) +===DONE=== + From 7f1239232e569d511912511fede9c2646ce725c9 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 29 Sep 2014 20:30:18 +0200 Subject: [PATCH 08/31] fix test filename --- ext/standard/tests/streams/proc_open_bug51800_right2.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/streams/proc_open_bug51800_right2.phpt b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt index 69c75cf2630..1e742745c1e 100644 --- a/ext/standard/tests/streams/proc_open_bug51800_right2.phpt +++ b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt @@ -2,7 +2,7 @@ Bug #51800 proc_open on Windows hangs forever, the right way to do it with more data --FILE-- --EXPECTF-- From 142a01db92100f65ab13995236b327e71eaa39b2 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 28 Sep 2014 21:30:49 +0200 Subject: [PATCH 09/31] Fix a couple compile warnings --- Zend/zend_builtin_functions.c | 2 +- ext/standard/basic_functions.c | 2 +- ext/standard/browscap.c | 10 ++++------ ext/standard/cyr_convert.c | 9 ++++----- ext/standard/dns.c | 2 +- ext/standard/iptc.c | 4 ++-- ext/standard/md5.c | 4 ++-- ext/standard/sha1.c | 14 +++++--------- ext/standard/string.c | 2 +- 9 files changed, 21 insertions(+), 28 deletions(-) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 9d8cda84d68..03a148a473a 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1761,7 +1761,7 @@ static int copy_function_name(zval *zv TSRMLS_DC, int num_args, va_list args, ze Returns an array of all defined functions */ ZEND_FUNCTION(get_defined_functions) { - zval internal, user, *ret; + zval internal, user; if (zend_parse_parameters_none() == FAILURE) { return; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 36611b812b8..e952ad90252 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5126,7 +5126,7 @@ PHP_FUNCTION(php_strip_whitespace) char *filename; size_t filename_len; zend_lex_state original_lex_state; - zend_file_handle file_handle = {0}; + zend_file_handle file_handle = {{0}}; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { RETURN_FALSE; diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index a591a67d442..a76fb136a3a 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -221,7 +221,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb static int browscap_read_file(char *filename, browser_data *browdata, int persistent TSRMLS_DC) /* {{{ */ { - zend_file_handle fh = {0}; + zend_file_handle fh = {{0}}; if (filename == NULL || filename[0] == '\0') { return FAILURE; @@ -379,15 +379,13 @@ static int browser_reg_compare(zval *browser TSRMLS_DC, int num_args, va_list ar number of characters changed in the user agent being checked versus the previous match found and the current match. */ if (Z_TYPE_P(found_browser_entry) == IS_ARRAY) { - int i, prev_len = 0, curr_len = 0, ua_len; - zval *current_match; + size_t i, prev_len = 0, curr_len = 0; + zval *current_match = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_pattern", sizeof("browser_name_pattern")-1); - if ((current_match = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_pattern", sizeof("browser_name_pattern")-1)) == NULL) { + if (!current_match) { return 0; } - ua_len = lookup_browser_length; - for (i = 0; i < Z_STRLEN_P(previous_match); i++) { switch (Z_STRVAL_P(previous_match)[i]) { case '?': diff --git a/ext/standard/cyr_convert.c b/ext/standard/cyr_convert.c index ea5cc193870..1718b757298 100644 --- a/ext/standard/cyr_convert.c +++ b/ext/standard/cyr_convert.c @@ -201,11 +201,11 @@ _cyr_mac = { * d - x-cp866 * m - x-mac-cyrillic *****************************************************************************/ -static char * php_convert_cyr_string(unsigned char *str, int length, char from, char to TSRMLS_DC) +static char * php_convert_cyr_string(unsigned char *str, size_t length, char from, char to TSRMLS_DC) { const unsigned char *from_table, *to_table; unsigned char tmp; - int i; + size_t i; from_table = NULL; to_table = NULL; @@ -258,8 +258,7 @@ static char * php_convert_cyr_string(unsigned char *str, int length, char from, if (!str) return (char *)str; - for( i = 0; ival, str->len, fr_cs[0], to_cs[0] TSRMLS_CC); + php_convert_cyr_string((unsigned char *) str->val, str->len, fr_cs[0], to_cs[0] TSRMLS_CC); RETVAL_NEW_STR(str); } /* }}} */ diff --git a/ext/standard/dns.c b/ext/standard/dns.c index a000ad9638a..13a1ab75df1 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -535,7 +535,7 @@ static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_t } if (n) { memcpy(tp->val + l2 , cp + l1 + 1, n); - add_next_index_stringl(&entries, cp + l1 + 1, n); + add_next_index_stringl(&entries, (char *) cp + l1 + 1, n); } l1 = l1 + n + 1; l2 = l2 + n; diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 692d856757b..75bbdd22ce8 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -300,8 +300,8 @@ PHP_FUNCTION(iptcparse) { int inx = 0, len; unsigned int tagsfound = 0; - unsigned char *buffer, recnum, dataset, key[ 16 ]; - char *str; + unsigned char *buffer, recnum, dataset; + char *str, key[16]; size_t str_len; zval values, *element; diff --git a/ext/standard/md5.c b/ext/standard/md5.c index dc241180ed8..e5359c2bcfb 100644 --- a/ext/standard/md5.c +++ b/ext/standard/md5.c @@ -61,7 +61,7 @@ PHP_NAMED_FUNCTION(php_if_md5) PHP_MD5Update(&context, arg->val, arg->len); PHP_MD5Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 16); + RETURN_STRINGL((char *) digest, 16); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str); @@ -112,7 +112,7 @@ PHP_NAMED_FUNCTION(php_if_md5_file) PHP_MD5Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 16); + RETURN_STRINGL((char *) digest, 16); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str); diff --git a/ext/standard/sha1.c b/ext/standard/sha1.c index cd8b82f5e1e..249828fb3d6 100644 --- a/ext/standard/sha1.c +++ b/ext/standard/sha1.c @@ -46,10 +46,10 @@ PHP_FUNCTION(sha1) sha1str[0] = '\0'; PHP_SHA1Init(&context); - PHP_SHA1Update(&context, arg->val, arg->len); + PHP_SHA1Update(&context, (unsigned char *) arg->val, arg->len); PHP_SHA1Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 20); + RETURN_STRINGL((char *) digest, 20); } else { make_digest_ex(sha1str, digest, 20); RETVAL_STRING(sha1str); @@ -71,7 +71,7 @@ PHP_FUNCTION(sha1_file) unsigned char buf[1024]; unsigned char digest[20]; PHP_SHA1_CTX context; - int n; + size_t n; php_stream *stream; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|b", &arg, &arg_len, &raw_output) == FAILURE) { @@ -85,7 +85,7 @@ PHP_FUNCTION(sha1_file) PHP_SHA1Init(&context); - while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) { + while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) { PHP_SHA1Update(&context, buf, n); } @@ -93,12 +93,8 @@ PHP_FUNCTION(sha1_file) php_stream_close(stream); - if (n<0) { - RETURN_FALSE; - } - if (raw_output) { - RETURN_STRINGL(digest, 20); + RETURN_STRINGL((char *) digest, 20); } else { make_digest_ex(sha1str, digest, 20); RETVAL_STRING(sha1str); diff --git a/ext/standard/string.c b/ext/standard/string.c index dcd6f09a9c9..4a37f7a5b30 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -3983,7 +3983,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines) while (1) { char_count=0; - while ((!max_chars || max_chars > 0 && char_count < max_chars) && begin > 0) { + while ((!max_chars || (max_chars > 0 && char_count < max_chars)) && begin > 0) { char_count++; begin--; if (begin <= 0 || _isnewline(heb_str[begin])) { From ab288b01d54cd5b19c2eb4a48dc352d1bf2cf0c5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 28 Sep 2014 23:17:29 +0200 Subject: [PATCH 10/31] CT substitute unqualified true/false/null in namespaces Substituation now always happens on the resolved name and unqualified usages of true/false/null in namespaced code are substituted as well. --- Zend/zend_compile.c | 142 ++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 59 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ee256e4d8d1..4ecdd36e0cb 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -132,6 +132,19 @@ static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigne } /* }}} */ +static zend_bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */ +{ + const char *ns_separator = zend_memrchr(name->val, '\\', name->len); + if (ns_separator != NULL) { + *result = ns_separator + 1; + *result_len = name->val + name->len - *result; + return 1; + } + + return 0; +} +/* }}} */ + static void init_compiler_declarables(TSRMLS_D) /* {{{ */ { ZVAL_LONG(&CG(declarables).ticks, 0); @@ -331,8 +344,10 @@ static inline int zend_add_literal_string(zend_op_array *op_array, zend_string * static int zend_add_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); @@ -343,19 +358,21 @@ static int zend_add_func_name_literal(zend_op_array *op_array, zend_string *name static int zend_add_ns_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { - const char *ns_separator; + const char *unqualified_name; + size_t unqualified_name_len; + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); - ns_separator = zend_memrchr(name->val, '\\', name->len); - if (ns_separator != NULL) { - size_t len = name->len - (ns_separator - name->val + 1); - lc_name = zend_string_alloc(len, 0); - zend_str_tolower_copy(lc_name->val, ns_separator + 1, len); + /* Lowercased unqualfied name */ + if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) { + lc_name = zend_string_alloc(unqualified_name_len, 0); + zend_str_tolower_copy(lc_name->val, unqualified_name, unqualified_name_len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); } @@ -365,8 +382,10 @@ static int zend_add_ns_func_name_literal(zend_op_array *op_array, zend_string *n static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); @@ -576,12 +595,16 @@ zend_string *zend_prefix_with_ns(zend_string *name TSRMLS_DC) { } } -void *zend_hash_find_ptr_lc(HashTable *ht, char *str, size_t len) { +void *zend_hash_find_ptr_lc(HashTable *ht, const char *str, size_t len) { void *result; - zend_string *lcname = zend_string_alloc(len, 0); + zend_string *lcname; + ALLOCA_FLAG(use_heap); + + STR_ALLOCA_ALLOC(lcname, len, use_heap); zend_str_tolower_copy(lcname->val, str, len); result = zend_hash_find_ptr(ht, lcname); - zend_string_free(lcname); + STR_ALLOCA_FREE(lcname, use_heap); + return result; } @@ -1131,55 +1154,45 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char } /* }}} */ -static zend_constant *zend_get_ct_const(zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */ +static zend_constant *zend_lookup_reserved_const(const char *name, size_t len TSRMLS_DC) /* {{{ */ { - zend_constant *c = NULL; - char *lookup_name; - - if (name->val[0] == '\\') { - c = zend_hash_str_find_ptr(EG(zend_constants), name->val + 1, name->len - 1); - if (!c) { - lookup_name = zend_str_tolower_dup(name->val + 1, name->len - 1); - c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len - 1); - efree(lookup_name); - - if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) { - return c; - } - return NULL; - } - } else if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) { - lookup_name = zend_str_tolower_dup(name->val, name->len); - c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len); - efree(lookup_name); - - if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) { - return c; - } - return NULL; - } - - if (c->flags & CONST_CT_SUBST) { - return c; - } - if (all_internal_constants_substitution && - (c->flags & CONST_PERSISTENT) && - !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) && - !Z_CONSTANT(c->value)) { + zend_constant *c = zend_hash_find_ptr_lc(EG(zend_constants), name, len); + if (c && !(c->flags & CONST_CS) && (c->flags & CONST_CT_SUBST)) { return c; } return NULL; } /* }}} */ -static int zend_constant_ct_subst(zval *result, zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */ +static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool is_fully_qualified TSRMLS_DC) /* {{{ */ { - zend_constant *c = zend_get_ct_const(name, all_internal_constants_substitution TSRMLS_CC); + zend_constant *c; - if (c) { - ZVAL_DUP(result, &c->value); - return 1; + if (!(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { + /* Substitute case-sensitive (or lowercase) persistent constants */ + c = zend_hash_find_ptr(EG(zend_constants), name); + if (c && (c->flags & CONST_PERSISTENT)) { + ZVAL_DUP(zv, &c->value); + return 1; + } } + + { + /* Substitute true, false and null (including unqualified usage in namespaces) */ + const char *lookup_name = name->val; + size_t lookup_len = name->len; + + if (!is_fully_qualified) { + zend_get_unqualified_name(name, &lookup_name, &lookup_len); + } + + c = zend_lookup_reserved_const(lookup_name, lookup_len TSRMLS_CC); + if (c) { + ZVAL_DUP(zv, &c->value); + return 1; + } + } + return 0; } /* }}} */ @@ -4692,10 +4705,11 @@ void zend_compile_use(zend_ast *ast TSRMLS_DC) /* {{{ */ if (new_name_ast) { new_name = zend_string_copy(zend_ast_get_str(new_name_ast)); } else { - /* The form "use A\B" is eqivalent to "use A\B as B" */ - const char *p = zend_memrchr(old_name->val, '\\', old_name->len); - if (p) { - new_name = zend_string_init(p + 1, old_name->len - (p - old_name->val + 1), 0); + const char *unqualified_name; + size_t unqualified_name_len; + if (zend_get_unqualified_name(old_name, &unqualified_name, &unqualified_name_len)) { + /* The form "use A\B" is eqivalent to "use A\B as B" */ + new_name = zend_string_init(unqualified_name, unqualified_name_len, 0); } else { new_name = zend_string_copy(old_name); @@ -4799,7 +4813,7 @@ void zend_compile_const_decl(zend_ast *ast TSRMLS_DC) /* {{{ */ value_node.op_type = IS_CONST; zend_const_expr_to_zval(value_zv, value_ast TSRMLS_CC); - if (zend_get_ct_const(name, 0 TSRMLS_CC)) { + if (zend_lookup_reserved_const(name->val, name->len TSRMLS_CC)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare constant '%s'", name->val); } @@ -5622,7 +5636,7 @@ void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ zend_string *resolved_name = zend_resolve_const_name( orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC); - if (zend_constant_ct_subst(&result->u.constant, resolved_name, 1 TSRMLS_CC)) { + if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified TSRMLS_CC)) { result->op_type = IS_CONST; zend_string_release(resolved_name); return; @@ -5858,16 +5872,16 @@ void zend_compile_const_expr_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */ zend_bool is_fully_qualified; zval result, resolved_name; + ZVAL_STR(&resolved_name, zend_resolve_const_name( + orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC)); - if (zend_constant_ct_subst(&result, orig_name, 0 TSRMLS_CC)) { + if (zend_try_ct_eval_const(&result, Z_STR(resolved_name), is_fully_qualified TSRMLS_CC)) { + zend_string_release(Z_STR(resolved_name)); zend_ast_destroy(ast); *ast_ptr = zend_ast_create_zval(&result); return; } - ZVAL_STR(&resolved_name, zend_resolve_const_name( - orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC)); - Z_TYPE_INFO(resolved_name) = IS_CONSTANT_EX; if (!is_fully_qualified) { Z_CONST_FLAGS(resolved_name) = IS_CONSTANT_UNQUALIFIED; @@ -6352,10 +6366,20 @@ void zend_eval_const_expr(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */ } break; case ZEND_AST_CONST: - if (!zend_constant_ct_subst(&result, zend_ast_get_str(ast->child[0]), 0 TSRMLS_CC)) { + { + zend_ast *name_ast = ast->child[0]; + zend_bool is_fully_qualified; + zend_string *resolved_name = zend_resolve_const_name( + zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified TSRMLS_CC); + + if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified TSRMLS_CC)) { + zend_string_release(resolved_name); return; } + + zend_string_release(resolved_name); break; + } default: return; } From 290d71de7513ec1fcdfc073389aefe9f9660477c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 29 Sep 2014 22:50:56 +0200 Subject: [PATCH 11/31] Drop unused RAISE_ABSTRACT_ERROR opcode Abstract methods are being prevented from being called in DO_FCALL etc. --- Zend/zend_compile.c | 7 ----- Zend/zend_vm_def.h | 7 ----- Zend/zend_vm_execute.h | 61 +++++++++++++++++++----------------------- Zend/zend_vm_opcodes.c | 2 +- Zend/zend_vm_opcodes.h | 1 - 5 files changed, 28 insertions(+), 50 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 4ecdd36e0cb..41e3189dabd 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3935,8 +3935,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } if (op_array->fn_flags & ZEND_ACC_ABSTRACT) { - //zend_op *opline; - if (op_array->fn_flags & ZEND_ACC_PRIVATE) { zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", in_interface ? "Interface" : "Abstract", ce->name->val, name->val); @@ -3948,11 +3946,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; - - /*opline = get_next_op(op_array TSRMLS_CC); - opline->opcode = ZEND_RAISE_ABSTRACT_ERROR; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2);*/ } else if (!has_body) { zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", ce->name->val, name->val); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 405c3f45c96..0a9a3306968 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5082,13 +5082,6 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) -{ - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(scope)->name->val, EX(func)->op_array.function_name->val); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ -} - ZEND_VM_HANDLER(58, ZEND_END_SILENCE, TMP, ANY) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d49926aa1c0..77f43ffdf9c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1142,13 +1142,6 @@ static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(scope)->name->val, EX(func)->op_array.function_name->val); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ -} - static int ZEND_FASTCALL ZEND_EXT_STMT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); @@ -10070,12 +10063,12 @@ static int ZEND_FASTCALL ZEND_COALESCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } else if (IS_TMP_VAR == IS_VAR && is_ref) { if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); - zval_dtor(free_op1.var); + zval_ptr_dtor_nogc(free_op1.var); } ZEND_VM_JMP(opline->op2.jmp_addr); } - zval_dtor(free_op1.var); + zval_ptr_dtor_nogc(free_op1.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -46851,31 +46844,31 @@ void zend_init_opcodes_handlers(void) ZEND_DECLARE_FUNCTION_SPEC_HANDLER, ZEND_DECLARE_FUNCTION_SPEC_HANDLER, ZEND_DECLARE_FUNCTION_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 23b49e3d71c..45dfe598452 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -164,7 +164,7 @@ const char *zend_vm_opcodes_map[170] = { "ZEND_DECLARE_CLASS", "ZEND_DECLARE_INHERITED_CLASS", "ZEND_DECLARE_FUNCTION", - "ZEND_RAISE_ABSTRACT_ERROR", + NULL, "ZEND_DECLARE_CONST", "ZEND_ADD_INTERFACE", "ZEND_DECLARE_INHERITED_CLASS_DELAYED", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index c1ecebb2f38..32a856a63cc 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -155,7 +155,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_DECLARE_CLASS 139 #define ZEND_DECLARE_INHERITED_CLASS 140 #define ZEND_DECLARE_FUNCTION 141 -#define ZEND_RAISE_ABSTRACT_ERROR 142 #define ZEND_DECLARE_CONST 143 #define ZEND_ADD_INTERFACE 144 #define ZEND_DECLARE_INHERITED_CLASS_DELAYED 145 From 67a11b61cd9ce09cd353f5ca5edddc5440bf5e3c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 29 Sep 2014 22:59:57 +0200 Subject: [PATCH 12/31] Drop unused INIT_STRING opcode INIT_STRING has been implemented as an UNUSED op1 to ADD_* for some time now. --- Zend/zend_vm_def.h | 11 ------ Zend/zend_vm_execute.h | 61 ++++++++++++------------------ Zend/zend_vm_opcodes.c | 2 +- Zend/zend_vm_opcodes.h | 1 - ext/opcache/Optimizer/block_pass.c | 36 ------------------ 5 files changed, 26 insertions(+), 85 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0a9a3306968..02c93477e3b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1985,17 +1985,6 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 77f43ffdf9c..17858c28758 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -488,17 +488,6 @@ static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_CONTINUE(); } -static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -44619,31 +44608,31 @@ void zend_init_opcodes_handlers(void) ZEND_BOOL_SPEC_CV_HANDLER, ZEND_BOOL_SPEC_CV_HANDLER, ZEND_BOOL_SPEC_CV_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 45dfe598452..d31eb141414 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -75,7 +75,7 @@ const char *zend_vm_opcodes_map[170] = { "ZEND_BRK", "ZEND_CONT", "ZEND_BOOL", - "ZEND_INIT_STRING", + NULL, "ZEND_ADD_CHAR", "ZEND_ADD_STRING", "ZEND_ADD_VAR", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 32a856a63cc..43aea9ee950 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -75,7 +75,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_BRK 50 #define ZEND_CONT 51 #define ZEND_BOOL 52 -#define ZEND_INIT_STRING 53 #define ZEND_ADD_CHAR 54 #define ZEND_ADD_STRING 55 #define ZEND_ADD_VAR 56 diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 73a65485a53..869bd3ccba7 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1054,25 +1054,6 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, VAR_UNSET(opline->op1); COPY_NODE(opline->op1, src->op1); MAKE_NOP(src); - } else if ((opline->opcode == ZEND_ADD_STRING || - opline->opcode == ZEND_ADD_CHAR) && - ZEND_OP1_TYPE(opline) == IS_TMP_VAR && - VAR_SOURCE(opline->op1) && - VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) { - /* convert T = INIT_STRING(), T = ADD_STRING(T, X) to T = QM_ASSIGN(X) */ - /* CHECKME: Remove ZEND_ADD_VAR optimization, since some conversions - - namely, BOOL(false)->string - don't allocate memory but use empty_string - and ADD_CHAR fails */ - zend_op *src = VAR_SOURCE(opline->op1); - VAR_UNSET(opline->op1); - COPY_NODE(opline->op1, opline->op2); - if (opline->opcode == ZEND_ADD_CHAR) { - char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline)); - ZVAL_STRINGL(&ZEND_OP1_LITERAL(opline), &c, 1); - } - SET_UNUSED(opline->op2); - MAKE_NOP(src); - opline->opcode = ZEND_QM_ASSIGN; } else if ((opline->opcode == ZEND_ADD_STRING || opline->opcode == ZEND_ADD_CHAR || opline->opcode == ZEND_ADD_VAR || @@ -1094,23 +1075,6 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline->opcode = ZEND_CONCAT; literal_dtor(&ZEND_OP2_LITERAL(src)); /* will take care of empty_string too */ MAKE_NOP(src); -//??? This optimization can't work anymore because ADD_VAR returns IS_TMP_VAR -//??? and ZEND_CAST returns IS_VAR. -//??? BTW: it wan't used for long time, because we don't use INIT_STRING -#if 0 - } else if (opline->opcode == ZEND_ADD_VAR && - ZEND_OP1_TYPE(opline) == IS_TMP_VAR && - VAR_SOURCE(opline->op1) && - VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) { - /* convert T = INIT_STRING(), T = ADD_VAR(T, X) to T = CAST(STRING, X) */ - zend_op *src = VAR_SOURCE(opline->op1); - VAR_UNSET(opline->op1); - COPY_NODE(opline->op1, opline->op2); - SET_UNUSED(opline->op2); - MAKE_NOP(src); - opline->opcode = ZEND_CAST; - opline->extended_value = IS_STRING; -#endif } else if ((opline->opcode == ZEND_ADD_STRING || opline->opcode == ZEND_ADD_CHAR || opline->opcode == ZEND_ADD_VAR || From 63dc9bbc027dc22ad4ef580c964744cd7db7fc33 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 30 Sep 2014 15:19:51 +0400 Subject: [PATCH 13/31] Micro optimization --- Zend/zend_execute.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 193da6ba6c0..e5ab12d9c5c 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -254,13 +254,12 @@ static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call T static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (zval*)call)) { - zend_vm_stack p = EG(argument_stack); - + zend_vm_stack p = EG(argument_stack); + if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(p) == (zval*)call)) { EG(argument_stack) = p->prev; efree(p); } else { - EG(argument_stack)->top = (zval*)call; + p->top = (zval*)call; } } From 9f7564b12b6e57d018bbc158e00f41499017d29e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 1 Oct 2014 10:46:13 +0400 Subject: [PATCH 14/31] Removed zend_execute_data->prev_nested_call. Reuse prev_execute_data instead. --- Zend/zend_compile.h | 1 - Zend/zend_execute.h | 2 +- Zend/zend_execute_API.c | 1 - Zend/zend_generators.c | 2 +- Zend/zend_vm_def.h | 4 ++-- Zend/zend_vm_execute.h | 4 ++-- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 573f1fe5ec0..cf1256ab3c7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -367,7 +367,6 @@ struct _zend_execute_data { zend_uchar frame_kind; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *prev_nested_call; zend_execute_data *prev_execute_data; zval *return_value; zend_class_entry *scope; /* function scope (self) */ diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index e5ab12d9c5c..ce01e51d3f5 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -219,7 +219,7 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_ call->flags = flags; call->called_scope = called_scope; call->object = object; - call->prev_nested_call = prev; + call->prev_execute_data = prev; return call; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index f59a10179b6..b528bd0ab5f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -703,7 +703,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS dummy_execute_data = *EG(current_execute_data); dummy_execute_data.prev_execute_data = EG(current_execute_data); dummy_execute_data.call = NULL; - dummy_execute_data.prev_nested_call = NULL; dummy_execute_data.opline = NULL; dummy_execute_data.func = NULL; EG(current_execute_data) = &dummy_execute_data; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index b038600ead2..4c64cb75907 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -71,7 +71,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato if (execute_data->call->object) { OBJ_RELEASE(execute_data->call->object); } - execute_data->call = execute_data->call->prev_nested_call; + execute_data->call = execute_data->call->prev_execute_data; } } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 02c93477e3b..c215fc35f82 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2534,7 +2534,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_function *fbc = call->func; SAVE_OPLINE(); - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -5409,7 +5409,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call TSRMLS_CC); call = EX(call); } while (call); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 17858c28758..cb6fd8b5e27 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -495,7 +495,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_function *fbc = call->func; SAVE_OPLINE(); - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -1312,7 +1312,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call TSRMLS_CC); call = EX(call); } while (call); From 7319298ffe514aa0ddfbcd522a4f5286f6a6c3cc Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 1 Oct 2014 09:26:21 +0200 Subject: [PATCH 15/31] use $PHP_LIBDIR instread of "lib" in skel example --- ext/ext_skel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/ext_skel b/ext/ext_skel index 650dae1e57a..cd545ecf392 100755 --- a/ext/ext_skel +++ b/ext/ext_skel @@ -156,12 +156,12 @@ if test "\$PHP_$EXTNAME" != "no"; then dnl PHP_CHECK_LIBRARY(\$LIBNAME,\$LIBSYMBOL, dnl [ - dnl PHP_ADD_LIBRARY_WITH_PATH(\$LIBNAME, \$${EXTNAME}_DIR/lib, ${EXTNAME}_SHARED_LIBADD) + dnl PHP_ADD_LIBRARY_WITH_PATH(\$LIBNAME, \$${EXTNAME}_DIR/\$PHP_LIBDIR, ${EXTNAME}_SHARED_LIBADD) dnl AC_DEFINE(HAVE_${EXTNAME}LIB,1,[ ]) dnl ],[ dnl AC_MSG_ERROR([wrong $extname lib version or lib not found]) dnl ],[ - dnl -L\$${EXTNAME}_DIR/lib -lm + dnl -L\$${EXTNAME}_DIR/\$PHP_LIBDIR -lm dnl ]) dnl dnl PHP_SUBST(${EXTNAME}_SHARED_LIBADD) From 7cbd8f8b8a662c1e74cb1c97dac6f606f8f477c9 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Thu, 21 Aug 2014 10:03:48 +0100 Subject: [PATCH 16/31] remove bogus locale use from test --- ext/standard/tests/strings/setlocale_variation2.phpt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/strings/setlocale_variation2.phpt b/ext/standard/tests/strings/setlocale_variation2.phpt index 038ba58c5ec..10ae22fe0c6 100644 --- a/ext/standard/tests/strings/setlocale_variation2.phpt +++ b/ext/standard/tests/strings/setlocale_variation2.phpt @@ -18,8 +18,11 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { /* setlocale() to set all available locales in the system and check the success count */ echo "*** Testing setlocale() : usage variations ***\n"; -function good_locale($locale) { - return $locale !== 'tt_RU@iqtelif.UTF-8'; +function good_locale($locale) { + /** + * Note: no_NO is a bogus locale and should not be used, see https://bugzilla.redhat.com/show_bug.cgi?id=532487 + **/ + return $locale !== 'tt_RU@iqtelif.UTF-8' && substr($locale, 0, 5) !== "no_NO"; } /* Prototype : array list_system_locales( void ) From 3e6f17673338034724c8b637c214b53a51a9db14 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 1 Oct 2014 10:14:14 +0200 Subject: [PATCH 17/31] only no_NO.ISO-8859-1 have to be ignored --- ext/standard/tests/strings/setlocale_variation2.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/strings/setlocale_variation2.phpt b/ext/standard/tests/strings/setlocale_variation2.phpt index 10ae22fe0c6..5ebdfe8d507 100644 --- a/ext/standard/tests/strings/setlocale_variation2.phpt +++ b/ext/standard/tests/strings/setlocale_variation2.phpt @@ -20,9 +20,9 @@ echo "*** Testing setlocale() : usage variations ***\n"; function good_locale($locale) { /** - * Note: no_NO is a bogus locale and should not be used, see https://bugzilla.redhat.com/show_bug.cgi?id=532487 + * Note: no_NO is a bogus locale and should not be used, see https://bugzilla.redhat.com/971416 **/ - return $locale !== 'tt_RU@iqtelif.UTF-8' && substr($locale, 0, 5) !== "no_NO"; + return $locale !== 'tt_RU@iqtelif.UTF-8' && $locale !== 'no_NO.ISO-8859-1'; } /* Prototype : array list_system_locales( void ) From 26f4e406222fe428dc5f8853db0bab5d8afa372d Mon Sep 17 00:00:00 2001 From: Ferenc Kovacs Date: Wed, 1 Oct 2014 11:15:59 +0200 Subject: [PATCH 18/31] update NEWS about the release date of 5.6.1 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 67bcda61538..bcd53296b09 100644 --- a/NEWS +++ b/NEWS @@ -21,7 +21,7 @@ PHP NEWS value). (Remi) -25 Sep 2014, PHP 5.6.1 +02 Oct 2014, PHP 5.6.1 - Core: . Implemented FR #38409 (parse_ini_file() looses the type of booleans). (Tjerk) From 8857af8494db84242d666c0baf11ca6f08aab3e3 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 1 Oct 2014 16:35:56 +0400 Subject: [PATCH 19/31] Use inline finction for OBJ_RELEASE() macro --- Zend/zend_objects_API.h | 18 ++++++++++-------- Zend/zend_vm_def.h | 6 +----- Zend/zend_vm_execute.h | 6 +----- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index df22a26cc92..baa1a28bb44 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -37,14 +37,7 @@ } while (0) -#define OBJ_RELEASE(obj) do { \ - zend_object *_obj = (obj); \ - if (--GC_REFCOUNT(_obj) == 0) { \ - zend_objects_store_del(_obj TSRMLS_CC); \ - } else { \ - gc_possible_root(&_obj->gc TSRMLS_CC); \ - } \ - } while (0) +#define OBJ_RELEASE(obj) zend_object_release(obj TSRMLS_CC) typedef struct _zend_objects_store { zend_object **object_buckets; @@ -78,6 +71,15 @@ ZEND_API zend_object *zend_object_create_proxy(zval *object, zval *member TSRMLS ZEND_API zend_object_handlers *zend_get_std_object_handlers(void); END_EXTERN_C() +static zend_always_inline void zend_object_release(zend_object *obj TSRMLS_CC) +{ + if (--GC_REFCOUNT(obj) == 0) { + zend_objects_store_del(obj TSRMLS_CC); + } else if (UNEXPECTED(!GC_INFO(obj))) { + gc_possible_root(&obj->gc TSRMLS_CC); + } +} + #endif /* ZEND_OBJECTS_H */ /* diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c215fc35f82..489e27202b7 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2710,11 +2710,7 @@ ZEND_VM_C_LABEL(fcall_end_change_scope): zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - if (!Z_DELREF(EG(This))) { - _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); - } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { - gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); - } + OBJ_RELEASE(Z_OBJ(EG(This))); } Z_OBJ(EG(This)) = EX(object); EG(scope) = EX(scope); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index cb6fd8b5e27..f1fde5034b6 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -671,11 +671,7 @@ fcall_end_change_scope: zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - if (!Z_DELREF(EG(This))) { - _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); - } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { - gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); - } + OBJ_RELEASE(Z_OBJ(EG(This))); } Z_OBJ(EG(This)) = EX(object); EG(scope) = EX(scope); From c4419e7a5bcbe30f568b17164ae30799aaaa5aba Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 1 Oct 2014 16:37:21 +0400 Subject: [PATCH 20/31] Expose zend_throw_exception_internal() --- Zend/zend_exceptions.c | 2 +- Zend/zend_exceptions.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 999b6d790e0..b3770526dbb 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -85,7 +85,7 @@ void zend_exception_restore(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ +ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ { #ifdef HAVE_DTRACE if (DTRACE_EXCEPTION_THROWN_ENABLED()) { diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 5aa6544e5da..3118ce10538 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -30,7 +30,7 @@ ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *a ZEND_API void zend_exception_save(TSRMLS_D); ZEND_API void zend_exception_restore(TSRMLS_D); -void zend_throw_exception_internal(zval *exception TSRMLS_DC); +ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC); void zend_register_default_exception(TSRMLS_D); From cfe8a8b96839eb9fec5a06bb062dc2daa8dc1fcc Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Wed, 1 Oct 2014 16:16:05 +0200 Subject: [PATCH 21/31] 5.5.19 now --- NEWS | 3 +++ configure.in | 2 +- main/php_version.h | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 50d997875cc..66474514f10 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +?? ??? 2014, PHP 5.5.19 + + ?? ??? 2014, PHP 5.5.18 - Core: diff --git a/configure.in b/configure.in index 92b49006e64..cc5ec47ac71 100644 --- a/configure.in +++ b/configure.in @@ -119,7 +119,7 @@ int zend_sprintf(char *buffer, const char *format, ...); PHP_MAJOR_VERSION=5 PHP_MINOR_VERSION=5 -PHP_RELEASE_VERSION=18 +PHP_RELEASE_VERSION=19 PHP_EXTRA_VERSION="-dev" PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION" PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION` diff --git a/main/php_version.h b/main/php_version.h index e7478d5ce6f..b198ad69b1d 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.in to change version number */ #define PHP_MAJOR_VERSION 5 #define PHP_MINOR_VERSION 5 -#define PHP_RELEASE_VERSION 18 +#define PHP_RELEASE_VERSION 19 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "5.5.18-dev" -#define PHP_VERSION_ID 50518 +#define PHP_VERSION "5.5.19-dev" +#define PHP_VERSION_ID 50519 From ccb24caa6d2e8bb0a8f3959543173a1f65c84b2d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 2 Oct 2014 13:37:44 +0400 Subject: [PATCH 22/31] Fixed incorrect compilation --- Zend/zend_compile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 41e3189dabd..91bfbfeebba 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5559,7 +5559,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(ast); zend_op *opline; - uint32_t i, opnum_init; + uint32_t i, opnum_init = -1; zend_bool packed = 1; if (zend_try_ct_eval_array(&result->u.constant, ast TSRMLS_CC)) { @@ -5567,8 +5567,6 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ return; } - opnum_init = get_next_op_number(CG(active_op_array)); - for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; zend_ast *value_ast = elem_ast->child[0]; @@ -5591,6 +5589,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ } if (i == 0) { + opnum_init = get_next_op_number(CG(active_op_array)); opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC); opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT; } else { @@ -5612,6 +5611,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ /* Add a flag to INIT_ARRAY if we know this array cannot be packed */ if (!packed) { + ZEND_ASSERT(opnum_init != -1); opline = &CG(active_op_array)->opcodes[opnum_init]; opline->extended_value |= ZEND_ARRAY_NOT_PACKED; } From c41fbcfb4c68392dc7c561b81ad0f6c25672034f Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 2 Oct 2014 12:15:34 +0200 Subject: [PATCH 23/31] improved file size computation in stat() On 32 bit it's still overwlowing, so nothing is changed there. But the usage of LARGE_INTEGER instead of bit shifting is a better way to go. --- Zend/zend_virtual_cwd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index b061d5a00d0..01a91cad80f 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -294,7 +294,7 @@ CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{{ */ { WIN32_FILE_ATTRIBUTE_DATA data; - __int64 t; + LARGE_INTEGER t; const size_t path_len = strlen(path); ALLOCA_FLAG(use_heap_large); @@ -393,10 +393,11 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{ } buf->st_nlink = 1; - t = data.nFileSizeHigh; - t = t << 32; - t |= data.nFileSizeLow; - buf->st_size = t; + t.HighPart = data.nFileSizeHigh; + t.LowPart = data.nFileSizeLow; + /* It's an overflow on 32 bit, however it won't fix as long + as zend_long is 32 bit. */ + buf->st_size = (zend_long)t.QuadPart; buf->st_atime = FileTimeToUnixTime(&data.ftLastAccessTime); buf->st_ctime = FileTimeToUnixTime(&data.ftCreationTime); buf->st_mtime = FileTimeToUnixTime(&data.ftLastWriteTime); From 51c90e999fabda0cc10b82e0617e6e45797bf81d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 2 Oct 2014 21:58:29 +0200 Subject: [PATCH 24/31] Fix ZTS build --- Zend/zend_objects_API.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index baa1a28bb44..362d79a68c2 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -71,7 +71,7 @@ ZEND_API zend_object *zend_object_create_proxy(zval *object, zval *member TSRMLS ZEND_API zend_object_handlers *zend_get_std_object_handlers(void); END_EXTERN_C() -static zend_always_inline void zend_object_release(zend_object *obj TSRMLS_CC) +static zend_always_inline void zend_object_release(zend_object *obj TSRMLS_DC) { if (--GC_REFCOUNT(obj) == 0) { zend_objects_store_del(obj TSRMLS_CC); From d7b01aff89bab42c6672b3a432983137fae8a0ab Mon Sep 17 00:00:00 2001 From: Ferenc Kovacs Date: Thu, 2 Oct 2014 22:28:19 +0200 Subject: [PATCH 25/31] we also have xz release tarballs since 5.5 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8d0e7565f20..f696b15ebf9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.tgz *.tar.gz *.tar.bz2 +*.tar.xz .FBCIndex .FBCLockFolder .deps From 1721bbedabfaa230ff3c5fb90e365ee0eed6a89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Schl=C3=BCter?= Date: Fri, 3 Oct 2014 02:12:09 +0200 Subject: [PATCH 26/31] Remove extensions which are long gone --- EXTENSIONS | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/EXTENSIONS b/EXTENSIONS index 61a1688b3c9..6ec12436863 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -228,13 +228,6 @@ MAINTENANCE: Maintained STATUS: Working COMMENT: Use PostgreSQL 7.0.x or later. PostgreSQL 6.5.3 or less have fatal bug. ------------------------------------------------------------------------------- -EXTENSION: sqlite -PRIMARY MAINTAINER: Marcus Boerger , Wez Furlong , Ilia Alshanetsky -MAINTENANCE: Maintained -STATUS: Working -SINCE: 5.0 (Since 4.3.2 in PECL) -COMMENT: Integrates SQLite 2 embeddable SQL database engine. -------------------------------------------------------------------------------- EXTENSION: sqlite3 PRIMARY MAINTAINER: Scott MacVicar MAINTENANCE: Maintained @@ -422,22 +415,6 @@ PRIMARY MAINTAINER: Derick Rethans MAINTENANCE: Maintained STATUS: Working ------------------------------------------------------------------------------- -EXTENSION: mhash -PRIMARY MAINTAINER: Sascha Schumann , Scott MacVicar -MAINTENANCE: Unknown -STATUS: Working -------------------------------------------------------------------------------- -EXTENSION: mime_magic -PRIMARY MAINTAINER: Unknown -MAINTENANCE: Deprecated -STATUS: Experimental -COMMENT: Use the fileinfo extension instead -------------------------------------------------------------------------------- -EXTENSION: ming -PRIMARY MAINTAINER: Frank M. Kromann -MAINTENANCE: Unknown -STATUS: Experimental -------------------------------------------------------------------------------- EXTENSION: openssl PRIMARY MAINTAINER: Wez Furlong , Pierre-Alain Joye MAINTENANCE: Maintained From 4e7b31a0dbe47d9218ff6a30f50121ddb612ce19 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Thu, 2 Oct 2014 18:54:46 -0700 Subject: [PATCH 27/31] Add hash to EXTENSIONS file --- EXTENSIONS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/EXTENSIONS b/EXTENSIONS index 53085820235..05f5dca5de2 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -385,6 +385,12 @@ MAINTENANCE: Maintained STATUS: Working SINCE: 4.0.4 ------------------------------------------------------------------------------- +EXTENSION: hash +PRIMARY MAINTAINER: Sara Golemon , Mike Wallner , Anatol Belski +MAINTENANCE: Maintained +STATUS: Working +SINCE: 5.1.2 +------------------------------------------------------------------------------- EXTENSION: iconv PRIMARY MAINTAINER: Moriyoshi Koizumi MAINTENANCE: Maintained From 5c63a4f72bd618ff8260892347765d8b4375df98 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 3 Oct 2014 12:18:15 +0400 Subject: [PATCH 28/31] Micro optimization for the most frequency case --- Zend/zend_vm_def.h | 6 ++++-- Zend/zend_vm_execute.h | 15 ++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 489e27202b7..966cf915763 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2658,11 +2658,12 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_vm_stack_free_call_frame(call TSRMLS_CC); } else { call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_FUNCTION : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + i_init_func_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_FUNCTION; zend_execute_ex(call TSRMLS_CC); } } @@ -4130,10 +4131,11 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f1fde5034b6..eeb6d5cd3f0 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -619,11 +619,12 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_vm_stack_free_call_frame(call TSRMLS_CC); } else { call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_FUNCTION : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + i_init_func_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_FUNCTION; zend_execute_ex(call TSRMLS_CC); } } @@ -3001,10 +3002,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -9739,10 +9741,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -16327,10 +16330,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -33608,10 +33612,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } From 15ba757a2b7c6810bc23ac9e158a7b901232b2aa Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Fri, 3 Oct 2014 11:35:27 +0200 Subject: [PATCH 29/31] add IPv6 support to php-fpm --- sapi/fpm/fpm/fpm_sockets.c | 85 +++++++++++++++++++------------------- sapi/fpm/fpm/fpm_sockets.h | 6 --- sapi/fpm/php-fpm.conf.in | 2 + sapi/fpm/tests/003.phpt | 53 ++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 48 deletions(-) create mode 100644 sapi/fpm/tests/003.phpt diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index e056565ea41..da14d63d8c3 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -39,29 +39,6 @@ struct listening_socket_s { static struct fpm_array_s sockets_list; -static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr) /* {{{ */ -{ - struct addrinfo *res; - struct addrinfo hints; - int ret; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - ret = getaddrinfo(node, service, &hints, &res); - - if (ret != 0) { - zlog(ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n", - node, service ? ":" : "", service ? service : "", - gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : ""); - return -1; - } - - *addr = *(struct sockaddr_in *) res->ai_addr; - freeaddrinfo(res); - return 0; -} -/* }}} */ - enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 }; static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */ @@ -98,14 +75,23 @@ static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */ } /* }}} */ +static void *fpm_get_in_addr(struct sockaddr *sa) /* {{{ */ +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} +/* }}} */ + static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) /* {{{ */ { if (key == NULL) { switch (type) { case FPM_AF_INET : { - struct sockaddr_in *sa_in = (struct sockaddr_in *) sa; - key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp")); - sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port)); + key = alloca(INET6_ADDRSTRLEN); + inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, sizeof key); break; } @@ -254,11 +240,14 @@ enum fpm_address_domain fpm_sockets_domain_from_address(char *address) /* {{{ */ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* {{{ */ { - struct sockaddr_in sa_in; + struct addrinfo hints, *servinfo, *p; char *dup_address = strdup(wp->config->listen_address); - char *port_str = strchr(dup_address, ':'); + char *port_str = strrchr(dup_address, ':'); char *addr = NULL; + int addr_len; int port = 0; + int sock; + int status; if (port_str) { /* this is host:port pair */ *port_str++ = '\0'; @@ -274,23 +263,35 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* return -1; } - memset(&sa_in, 0, sizeof(sa_in)); - - if (addr) { - sa_in.sin_addr.s_addr = inet_addr(addr); - if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */ - if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) { - return -1; - } - zlog(ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr)); + // strip brackets from address for getaddrinfo + if (addr != NULL) { + addr_len = strlen(addr); + if (addr[0] == '[' && addr[addr_len - 1] == ']') { + addr[addr_len - 1] = '\0'; + addr++; } - } else { - sa_in.sin_addr.s_addr = htonl(INADDR_ANY); } - sa_in.sin_family = AF_INET; - sa_in.sin_port = htons(port); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(addr, port_str, &hints, &servinfo)) != 0) { + zlog(ZLOG_ERROR, "getaddrinfo: %s\n", gai_strerror(status)); + return -1; + } + free(dup_address); - return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in)); + + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sock = fpm_sockets_get_listening_socket(wp, p->ai_addr, p->ai_addrlen)) != -1) { + break; + } + } + + freeaddrinfo(servinfo); + + return sock; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_sockets.h b/sapi/fpm/fpm/fpm_sockets.h index 121c016a7b8..446c78e410a 100644 --- a/sapi/fpm/fpm/fpm_sockets.h +++ b/sapi/fpm/fpm/fpm_sockets.h @@ -45,10 +45,4 @@ static inline int fd_set_blocked(int fd, int blocked) /* {{{ */ } /* }}} */ -#define IPQUAD(sin_addr) \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3] - #endif diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index c5f4abc59ca..631bc46f42a 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -152,6 +152,8 @@ group = @php_fpm_group@ ; Valid syntaxes are: ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on ; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; ; 'port' - to listen on a TCP socket to all addresses on a ; specific port; ; '/path/to/unix/socket' - to listen on a unix socket. diff --git a/sapi/fpm/tests/003.phpt b/sapi/fpm/tests/003.phpt new file mode 100644 index 00000000000..389cb2401ef --- /dev/null +++ b/sapi/fpm/tests/003.phpt @@ -0,0 +1,53 @@ +--TEST-- +FPM: Test IPv6 support +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d +" +string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections +" +Done +--CLEAN-- + From 25e65a7599893783e86ac4711f8ca3a3b7c84063 Mon Sep 17 00:00:00 2001 From: Ferenc Kovacs Date: Fri, 3 Oct 2014 11:38:32 +0200 Subject: [PATCH 30/31] NEWS entry for previous commit --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 66474514f10..d4f6c3e9fb8 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,8 @@ PHP NEWS - FPM: . Fixed bug #65641 (PHP-FPM incorrectly defines the SCRIPT_NAME variable when using Apache, mod_proxy-fcgi and ProxyPass). (Remi) + . Implemented FR #55508 (listen and listen.allowed_clients should take IPv6 + addresses). (Robin Gloster) - Reflection: . Fixed bug #68103 (Duplicate entry in Reflection for class alias). (Remi) From 79e05bf5578f09bb26e4a8826eb94f7f4601d4f6 Mon Sep 17 00:00:00 2001 From: Ferenc Kovacs Date: Fri, 3 Oct 2014 11:39:53 +0200 Subject: [PATCH 31/31] NEWS entry for previous commit --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index bcd53296b09..7a79da32fdf 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ PHP NEWS - FPM: . Fixed bug #65641 (PHP-FPM incorrectly defines the SCRIPT_NAME variable when using Apache, mod_proxy-fcgi and ProxyPass). (Remi) + . Implemented FR #55508 (listen and listen.allowed_clients should take IPv6 + addresses). (Robin Gloster) - Reflection: . Fixed bug #68103 (Duplicate entry in Reflection for class alias). (Remi)