diff options
author | krakjoe <joe.watkins@live.co.uk> | 2014-02-02 13:50:54 +0000 |
---|---|---|
committer | krakjoe <joe.watkins@live.co.uk> | 2014-02-02 13:50:54 +0000 |
commit | dc02b5a1fd77222ffb3802b03f4db597172f284a (patch) | |
tree | 83f54631f80a21bf2894142e00c663d8ae21cd04 | |
parent | 6fe34014f025b02cf429746b42184399e41835e1 (diff) | |
parent | f08e8772a7671482ea8f911978965bada9137c42 (diff) | |
download | php-git-dc02b5a1fd77222ffb3802b03f4db597172f284a.tar.gz |
Merge branch 'master' of https://git.php.net/repository/php-src
158 files changed, 4323 insertions, 1274 deletions
diff --git a/.gitignore b/.gitignore index cf615c6e92..8d0e7565f2 100644 --- a/.gitignore +++ b/.gitignore @@ -206,6 +206,8 @@ ext/pdo_sqlite/sqlite3.h ext/pdo_sqlite/tests/*.db ext/pdo_sqlite/tests/*.tmp ext/phar/phar.phar +ext/phar/phar.1 +ext/phar/phar.phar.1 ext/pspell/tests/*.tmp ext/reflection/xml ext/reflection/html @@ -237,12 +239,14 @@ sapi/apache/libphp5.module sapi/apache2handler/libphp5.module sapi/apache_hooks/libphp5.module sapi/cgi/php-cgi +sapi/cgi/php-cgi.1 sapi/cli/php.1 sapi/fpm/php-fpm sapi/fpm/php-fpm.1 sapi/fpm/init.d.php-fpm sapi/fpm/php-fpm.conf sapi/fpm/fpm/php-cgi +sapi/phpdbg/phpdbg scripts/php-config scripts/phpize scripts/man1/*.1 diff --git a/CODING_STANDARDS b/CODING_STANDARDS index 5fd3f9f35a..27fff07f60 100644 --- a/CODING_STANDARDS +++ b/CODING_STANDARDS @@ -82,7 +82,7 @@ Exceptions: library may need to control or free the memory, or when the memory in question needs to survive between multiple requests. -Naming Conventions +User Functions/Methods Naming Conventions ------------------ 1. Function names for user-level functions should be enclosed with in @@ -163,6 +163,26 @@ Naming Conventions 'foobar' 'foo_bar' +Internal Function Naming Convensions +---------------------- + +1. Functions that are part of the external API should be named + 'php_modulename_function()' to avoid symbol collision. They should be in + lowercase, with words underscore delimited. Exposed API must be defined + in 'php_modulename.h'. + + PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS); + + Unexposed module function should be static and should not be defined in + 'php_modulename.h'. + + static int php_session_destroy(TSRMLS_D) + +2. Main module source file must be named 'modulename.c'. + +3. Header file that is used by other sources must be named 'php_modulename.h'. + + Syntax and indentation ---------------------- @@ -181,9 +201,9 @@ Syntax and indentation of PHP or one of its standard modules, please maintain the K&R style. This applies to just about everything, starting with indentation and comment styles and up to function declaration - syntax. Also see Indentstyle_. + syntax. Also see Indentstyle. -.. _Indentstyle: http://www.catb.org/~esr/jargon/html/I/indent-style.html + Indentstyle: http://www.catb.org/~esr/jargon/html/I/indent-style.html 3. Be generous with whitespace and braces. Keep one empty line between the variable declaration section and the statements in a block, as well as diff --git a/Makefile.global b/Makefile.global index bd82daf4d8..11a7d5c43e 100644 --- a/Makefile.global +++ b/Makefile.global @@ -115,6 +115,7 @@ clean: find . -name \*.la -o -name \*.a | xargs rm -f find . -name \*.so | xargs rm -f find . -name .libs -a -type d|xargs rm -rf + find . -name \*.1 | xargs rm -f rm -f libphp$(PHP_MAJOR_VERSION).la $(SAPI_CLI_PATH) $(SAPI_CGI_PATH) $(SAPI_MILTER_PATH) $(SAPI_LITESPEED_PATH) $(SAPI_FPM_PATH) $(OVERALL_TARGET) modules/* libs/* distclean: clean diff --git a/README.EXT_SKEL b/README.EXT_SKEL index d44fcc5c6a..42df006d24 100644 --- a/README.EXT_SKEL +++ b/README.EXT_SKEL @@ -45,12 +45,29 @@ HOW TO USE IT --proto=filename. +SOURCE AND HEADER FILE NAME + + ./ext_skel generates 'module_name.c' and 'php_module_name.h' as main source + and header files. Keep these names. + + Module functions (User functions) must be named + + module_name_function() + + When you need to expose module functions to other modules, expose functions + strictly needed by others. Exposed internal function must be named + + php_module_name_function() + + See also CODING_STANDARDS. + + FORMAT OF FUNCTION DEFINITIONS FILE All the definitions must be on one line. In it's simplest form, it's just the function name, e.g. - my_function + module_name_function but then you'll be left with an almost empty function body without any argument handling. @@ -72,8 +89,9 @@ FORMAT OF FUNCTION DEFINITIONS FILE An example: - my_function(int arg1, int arg2 [, int arg3 [, int arg4]]) this is my 1st + module_name_function(int arg1, int arg2 [, int arg3 [, int arg4]]) + Arguments arg1 and arg2 are required. Arguments arg3 and arg4 are optional. If possible, the function definition should also contain it's return type @@ -133,15 +151,15 @@ EXAMPLE The following _one_ line - bool my_drawtext(resource image, string text, resource font, int x, int y [, int color]) + bool module_name_drawtext(resource image, string text, resource font, int x, int y [, int color]) will create this function definition for you (note that there are a few question marks to be replaced by you, and you must of course add your own value definitions too): -/* {{{ proto bool my_drawtext(resource image, string text, resource font, int x, int y [, int color]) +/* {{{ proto bool module_name_drawtext(resource image, string text, resource font, int x, int y [, int color]) */ -PHP_FUNCTION(my_drawtext) +PHP_FUNCTION(module_name_drawtext) { char *text = NULL; int argc = ZEND_NUM_ARGS(); @@ -164,7 +182,7 @@ PHP_FUNCTION(my_drawtext) ZEND_FETCH_RESOURCE(???, ???, font, font_id, "???", ???_rsrc_id); } - php_error(E_WARNING, "my_drawtext: not yet implemented"); + php_error(E_WARNING, "module_name_drawtext: not yet implemented"); } /* }}} */ diff --git a/README.RELEASE_PROCESS b/README.RELEASE_PROCESS index a0c34f8f7a..4343b6213c 100644 --- a/README.RELEASE_PROCESS +++ b/README.RELEASE_PROCESS @@ -101,10 +101,10 @@ pointing out "the location of the release" and "the possible release date of either the next RC, or the final release". 2. Send an email (see example here http://news.php.net/php.pear.qa/5201) **To** -``php-qa@lists.php.net`` and ``primary-qa-tests@lists.php.net``. +``php-qa@lists.php.net`` and ``primary-qa-tester@lists.php.net``. This email is to notify the selected projects about a new release so that they can make sure their projects keep working. Make sure that you have been setup -as a moderator for ``primary-qa-tests@lists.php.net`` by having someone (Wez, +as a moderator for ``primary-qa-tester@lists.php.net`` by having someone (Hannes, Dan, Derick) run the following commands for you: ``ssh lists.php.net`` diff --git a/README.SUBMITTING_PATCH b/README.SUBMITTING_PATCH index d1b74bd18d..50a1664a71 100644 --- a/README.SUBMITTING_PATCH +++ b/README.SUBMITTING_PATCH @@ -50,6 +50,17 @@ Please make the mail subject prefix "[PATCH]". If attaching a patch, ensure it has a file extension of ".txt". This is because only MIME attachments of type 'text/*' are accepted. +The preferred way to propose PHP patch is sending pull request from +github. + +https://github.com/php/php-src + +Fork the official PHP repository and send a pull request. A +notification will be sent to the pull request mailing list. Sending a +note to PHP Internals list (internals@lists.php.net) may help getting +more feedback and quicker turnaround. You can also add pull requests +to bug reports at http://bugs.php.net/. + PHP Documentation Patches ------------------------- diff --git a/README.TESTING b/README.TESTING index 5e0ee11be0..3ed5e6b2ab 100644 --- a/README.TESTING +++ b/README.TESTING @@ -2,7 +2,7 @@ ------------------ Failed tests usually indicate a problem with your local system setup and not within PHP itself (at least for official PHP release versions). -You may decide to automaticaly submit a test summary to our QA workflow +You may decide to automatically submit a test summary to our QA workflow at the end of a test run. Please do *not* submit a failed test as a bug or ask for help on why it failed on your system without providing substantial backup information diff --git a/TSRM/TSRM.dsp b/TSRM/TSRM.dsp index 6c3e8bfb8b..8604bc0da8 100644 --- a/TSRM/TSRM.dsp +++ b/TSRM/TSRM.dsp @@ -171,10 +171,6 @@ SOURCE=.\tsrm_strtok_r.h # End Source File # Begin Source File -SOURCE=.\tsrm_virtual_cwd.h -# End Source File -# Begin Source File - SOURCE=.\tsrm_win32.h # End Source File # End Group diff --git a/Zend/Zend.dsp b/Zend/Zend.dsp index 348e1abaa5..98d368fb16 100644 --- a/Zend/Zend.dsp +++ b/Zend/Zend.dsp @@ -269,6 +269,10 @@ SOURCE=.\zend_variables.c SOURCE=.\zend_vm_opcodes.c
# End Source File
+# Begin Source File
+
+SOURCE=.\zend_virtual_cwd.c
+# End Source File
# End Group
# Begin Group "Header Files"
@@ -437,10 +441,6 @@ SOURCE=.\zend_ts_hash.h SOURCE=.\zend_variables.h
# End Source File
-# Begin Source File
-
-SOURCE=.\zend_virtual_cwd.c
-# End Source File
# End Group
# Begin Group "Parsers"
diff --git a/Zend/tests/arg_unpack/basic.phpt b/Zend/tests/arg_unpack/basic.phpt new file mode 100644 index 0000000000..9c0365586a --- /dev/null +++ b/Zend/tests/arg_unpack/basic.phpt @@ -0,0 +1,114 @@ +--TEST-- +Basic argument unpacking +--FILE-- +<?php + +function test(...$args) { + var_dump($args); +} + +function test2($arg1, $arg2, $arg3 = null) { + var_dump($arg1, $arg2, $arg3); +} + +function getArray($array) { + return $array; +} + +function arrayGen($array) { + foreach ($array as $element) { + yield $element; + } +} + +$array = [1, 2, 3]; + +test(...[]); +test(...[1, 2, 3]); +test(...$array); +test(...getArray([1, 2, 3])); +test(...arrayGen([])); +test(...arrayGen([1, 2, 3])); + +test(1, ...[2, 3], ...[4, 5], 6); +test(1, ...getArray([2, 3]), ...arrayGen([4, 5]), 6); + +test2(...[1, 2]); +test2(...[1, 2, 3]); +test2(...[1], ...[], ...[], ...[2, 3], 4, ...[5, 6]); + +?> +--EXPECT-- +array(0) { +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(0) { +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(6) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) +} +array(6) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) +} +int(1) +int(2) +NULL +int(1) +int(2) +int(3) +int(1) +int(2) +int(3) diff --git a/Zend/tests/arg_unpack/by_ref.phpt b/Zend/tests/arg_unpack/by_ref.phpt new file mode 100644 index 0000000000..0619a3bab8 --- /dev/null +++ b/Zend/tests/arg_unpack/by_ref.phpt @@ -0,0 +1,149 @@ +--TEST-- +Argument unpacking with by-ref arguments +--FILE-- +<?php + +error_reporting(E_ALL); + +function test1(&...$args) { + foreach ($args as &$arg) { + $arg++; + } +} + +test1(...[1, 2, 3]); + +$array = [1, 2, 3]; +test1(...$array); +var_dump($array); + +$array1 = [1, 2]; $val2 = 3; $array2 = [4, 5]; +test1(...$array1, $val2, ...$array2); +var_dump($array1, $val2, $array2); + +function test2($val1, &$ref1, $val2, &$ref2) { + $ref1++; + $ref2++; +} + +$array = [1, 2, 3, 4]; +test2(...$array); +var_dump($array); + +$a = $b = $c = $d = 0; + +$array = []; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1, 2]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$array = [1, 2, 3]; +test2(...$array, $a, $b, $c, $d); +var_dump($array, $a, $b, $c, $d); + +$vars = []; +$array = []; +test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']); +var_dump($vars); + +$vars = []; +$array = [1]; +test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']); +var_dump($vars); + +?> +--EXPECTF-- +array(3) { + [0]=> + int(2) + [1]=> + int(3) + [2]=> + int(4) +} +array(2) { + [0]=> + int(2) + [1]=> + int(3) +} +int(4) +array(2) { + [0]=> + int(5) + [1]=> + int(6) +} +array(4) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(3) + [3]=> + int(5) +} +array(0) { +} +int(0) +int(1) +int(0) +int(1) +array(1) { + [0]=> + int(1) +} +int(1) +int(1) +int(1) +int(1) +array(2) { + [0]=> + int(1) + [1]=> + int(3) +} +int(1) +int(2) +int(1) +int(1) +array(3) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(3) +} +int(2) +int(2) +int(1) +int(1) + +Notice: Undefined index: a in %s on line %d + +Notice: Undefined index: c in %s on line %d +array(2) { + ["b"]=> + int(1) + ["d"]=> + int(1) +} + +Notice: Undefined index: b in %s on line %d + +Notice: Undefined index: d in %s on line %d +array(2) { + ["a"]=> + int(1) + ["c"]=> + int(1) +} diff --git a/Zend/tests/arg_unpack/dynamic.phpt b/Zend/tests/arg_unpack/dynamic.phpt new file mode 100644 index 0000000000..efed84da78 --- /dev/null +++ b/Zend/tests/arg_unpack/dynamic.phpt @@ -0,0 +1,37 @@ +--TEST-- +Unpack arguments for dynamic call +--FILE-- +<?php + +$fn = function(...$args) { + var_dump($args); +}; + +$fn(...[]); +$fn(...[1, 2, 3]); +$fn(1, ...[2, 3], ...[], 4, 5); + +?> +--EXPECT-- +array(0) { +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} diff --git a/Zend/tests/arg_unpack/internal.phpt b/Zend/tests/arg_unpack/internal.phpt new file mode 100644 index 0000000000..adc985d940 --- /dev/null +++ b/Zend/tests/arg_unpack/internal.phpt @@ -0,0 +1,43 @@ +--TEST-- +Argument unpacking with internal functions +--FILE-- +<?php + +$arrays = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]; +var_dump(array_map(null, ...$arrays)); + +?> +--EXPECT-- +array(3) { + [0]=> + array(3) { + [0]=> + int(1) + [1]=> + int(4) + [2]=> + int(7) + } + [1]=> + array(3) { + [0]=> + int(2) + [1]=> + int(5) + [2]=> + int(8) + } + [2]=> + array(3) { + [0]=> + int(3) + [1]=> + int(6) + [2]=> + int(9) + } +} diff --git a/Zend/tests/arg_unpack/invalid_type.phpt b/Zend/tests/arg_unpack/invalid_type.phpt new file mode 100644 index 0000000000..3efffebc76 --- /dev/null +++ b/Zend/tests/arg_unpack/invalid_type.phpt @@ -0,0 +1,59 @@ +--TEST-- +Only arrays and Traversables can be unpacked +--FILE-- +<?php + +function test(...$args) { + var_dump($args); +} + +test(...null); +test(...42); +test(...new stdClass); + +test(1, 2, 3, ..."foo", ...[4, 5]); +test(1, 2, ...new StdClass, 3, ...3.14, ...[4, 5]); + +?> +--EXPECTF-- +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(0) { +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} + +Warning: Only arrays and Traversables can be unpacked in %s on line %d + +Warning: Only arrays and Traversables can be unpacked in %s on line %d +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} diff --git a/Zend/tests/arg_unpack/many_args.phpt b/Zend/tests/arg_unpack/many_args.phpt new file mode 100644 index 0000000000..0ef5a30d6d --- /dev/null +++ b/Zend/tests/arg_unpack/many_args.phpt @@ -0,0 +1,15 @@ +--TEST-- +Argument unpacking with many arguments +--FILE-- +<?php + +function fn(...$args) { + var_dump(count($args)); +} + +$array = array_fill(0, 10000, 42); +fn(...$array, ...$array); + +?> +--EXPECT-- +int(20000) diff --git a/Zend/tests/arg_unpack/method.phpt b/Zend/tests/arg_unpack/method.phpt new file mode 100644 index 0000000000..d6a6e4712b --- /dev/null +++ b/Zend/tests/arg_unpack/method.phpt @@ -0,0 +1,45 @@ +--TEST-- +Unpack arguments for method calls +--FILE-- +<?php + +class Foo { + public function test(...$args) { + var_dump($args); + } + + public static function test2(...$args) { + var_dump($args); + } +} + +$foo = new Foo; +$foo->test(...[1, 2], 3, 4, ...[], 5); +Foo::test2(1, 2, ...[3, 4], ...[], 5); + +?> +--EXPECT-- +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} diff --git a/Zend/tests/arg_unpack/new.phpt b/Zend/tests/arg_unpack/new.phpt new file mode 100644 index 0000000000..3cf224f288 --- /dev/null +++ b/Zend/tests/arg_unpack/new.phpt @@ -0,0 +1,39 @@ +--TEST-- +Unpack arguments for new expression +--FILE-- +<?php + +class Foo { + public function __construct(...$args) { + var_dump($args); + } +} + +new Foo(...[]); +new Foo(...[1, 2, 3]); +new Foo(...[1], 2, ...[], ...[3, 4], 5); + +?> +--EXPECT-- +array(0) { +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +} diff --git a/Zend/tests/arg_unpack/string_keys.phpt b/Zend/tests/arg_unpack/string_keys.phpt new file mode 100644 index 0000000000..443a882941 --- /dev/null +++ b/Zend/tests/arg_unpack/string_keys.phpt @@ -0,0 +1,20 @@ +--TEST-- +Argument unpacking does not work with string keys (forward compatibility for named args) +--FILE-- +<?php + +set_error_handler(function($errno, $errstr) { + var_dump($errstr); +}); + +var_dump(...[1, 2, "foo" => 3, 4]); +var_dump(...new ArrayIterator([1, 2, "foo" => 3, 4])); + +?> +--EXPECTF-- +string(36) "Cannot unpack array with string keys" +int(1) +int(2) +string(42) "Cannot unpack Traversable with string keys" +int(1) +int(2) diff --git a/Zend/tests/arg_unpack/traversable_throwing_exception.phpt b/Zend/tests/arg_unpack/traversable_throwing_exception.phpt new file mode 100644 index 0000000000..8ddc24dc74 --- /dev/null +++ b/Zend/tests/arg_unpack/traversable_throwing_exception.phpt @@ -0,0 +1,33 @@ +--TEST-- +Traversables that throw exceptions are properly handled during argument unpack +--FILE-- +<?php + +function test(...$args) { + var_dump($args); +} + +class Foo implements IteratorAggregate { + public function getIterator() { + throw new Exception('getIterator'); + } +} + +function gen() { + yield 1; + yield 2; + throw new Exception('gen'); +} + +try { + test(1, 2, ...new Foo, 3, 4); +} catch (Exception $e) { var_dump($e->getMessage()); } + +try { + test(1, 2, ...gen(), 3, 4); +} catch (Exception $e) { var_dump($e->getMessage()); } + +?> +--EXPECT-- +string(11) "getIterator" +string(3) "gen" diff --git a/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt b/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt new file mode 100644 index 0000000000..e862341652 --- /dev/null +++ b/Zend/tests/arg_unpack/traversable_with_by_ref_parameters.phpt @@ -0,0 +1,34 @@ +--TEST-- +Traversables cannot be unpacked into by-reference parameters +--FILE-- +<?php + +function test($val1, $val2, $val3, &$ref) { + $ref = 42; +} + +function gen($array) { + foreach ($array as $element) { + yield $element; + } +} + +test(...gen([1, 2, 3]), $a); +var_dump($a); +test(1, 2, 3, $b, ...gen([4, 5, 6])); +var_dump($b); + +test(...gen([1, 2, 3, 4])); +test(1, 2, ...gen([3, 4])); +test(...gen([1, 2]), ...gen([3, 4])); + +?> +--EXPECTF-- +int(42) +int(42) + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d + +Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3f43b091db..f789e3397f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2549,8 +2549,11 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { + zend_function **function_ptr_ptr; + zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { + if (*function_ptr_ptr) { opline->opcode = ZEND_DO_FCALL; SET_NODE(opline->op1, function_name); SET_UNUSED(opline->op2); @@ -2562,6 +2565,13 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); opline->op2.num = --CG(context).nested_calls; + + /* This would normally be a ZEND_DO_FCALL, but was forced to use + * ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to + * free the function_name */ + if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { + zval_dtor(&function_name->u.constant); + } } } @@ -2582,9 +2592,9 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */ { zend_op *opline; - int original_op=op; + int original_op = op; zend_function **function_ptr_ptr, *function_ptr; - int send_by_reference; + int send_by_reference = 0; int send_function = 0; zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); @@ -2607,22 +2617,19 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ if (function_ptr) { if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { - if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) { - send_by_reference = 1; - if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { + if (op == ZEND_SEND_VAR && param->op_type & (IS_VAR|IS_CV)) { + send_by_reference = ZEND_ARG_SEND_BY_REF; + if (zend_is_function_or_method_call(param)) { /* Method call */ op = ZEND_SEND_VAR_NO_REF; send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT; } } else { op = ZEND_SEND_VAL; - send_by_reference = 0; } - } else { - send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0; + } else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + send_by_reference = ZEND_ARG_SEND_BY_REF; } - } else { - send_by_reference = 0; } if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { @@ -2690,6 +2697,39 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } /* }}} */ +void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ +{ + zend_op *opline; + zend_function **function_ptr_ptr; + + zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); + if (*function_ptr_ptr) { + /* If argument unpacking is used argument numbers and sending modes can no longer be + * computed at compile time, thus we need access to EX(call). In order to have it we + * retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */ + zval func_name; + ZVAL_STRING(&func_name, (*function_ptr_ptr)->common.function_name, 1); + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->result.num = CG(context).nested_calls; + SET_UNUSED(opline->op1); + opline->op2_type = IS_CONST; + opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC); + GET_CACHE_SLOT(opline->op2.constant); + + ++CG(context).nested_calls; + *function_ptr_ptr = NULL; + } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_SEND_UNPACK; + SET_NODE(opline->op1, params); + SET_UNUSED(opline->op2); + opline->op2.num = (zend_uint) offset; +} +/* }}} */ + static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */ { zend_op *opline; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a32a0c888b..f884df1946 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -383,6 +383,7 @@ typedef struct _call_slot { zend_function *fbc; zval *object; zend_class_entry *called_scope; + zend_uint num_additional_args; zend_bool is_ctor_call; zend_bool is_ctor_result_used; } call_slot; @@ -554,6 +555,7 @@ void zend_do_early_binding(TSRMLS_D); ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC); void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC); +void zend_do_unpack_params(znode *params, int offset TSRMLS_DC); void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 99bb5e02a9..31caceecbe 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1684,6 +1684,49 @@ ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array } /* }}} */ +static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, call_slot *call TSRMLS_DC) /* {{{ */ +{ + zend_uint arg_num = (opline->extended_value & ZEND_FETCH_ARG_MASK) + call->num_additional_args; + return ARG_SHOULD_BE_SENT_BY_REF(call->fbc, arg_num); +} +/* }}} */ + +static void **zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */ +{ + zend_vm_stack p = EG(argument_stack); + + zend_vm_stack_extend(count + 1 TSRMLS_CC); + + EG(argument_stack)->top += count; + *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count; + while (count-- > 0) { + void *data = *(--p->top); + + if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { + zend_vm_stack r = p; + + EG(argument_stack)->prev = p->prev; + p = p->prev; + efree(r); + } + *(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data; + } + return EG(argument_stack)->top++; +} +/* }}} */ + +static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC) /* {{{ */ +{ + if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) + || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { + return zend_vm_stack_push_args_with_copy(count TSRMLS_CC); + } + *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count; + return EG(argument_stack)->top++; +} +/* }}} */ + + #define ZEND_VM_NEXT_OPCODE() \ CHECK_SYMBOL_TABLES() \ ZEND_VM_INC_OPCODE(); \ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 752e27fff4..a4bc612bcb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -585,9 +585,11 @@ non_empty_function_call_parameter_list: expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } + | T_ELLIPSIS expr { Z_LVAL($$.u.constant) = 0; zend_do_unpack_params(&$2, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } | non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' T_ELLIPSIS expr { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant); zend_do_unpack_params(&$4, Z_LVAL($$.u.constant) TSRMLS_CC); } ; global_var_list: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b06adafbf0..b2cecf229e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1143,7 +1143,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) USE_OPLINE ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, - ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R); + zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R); } ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) @@ -1251,9 +1251,8 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -1488,7 +1487,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -1902,6 +1901,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) USE_OPLINE zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_uint num_args; SAVE_OPLINE(); EX(object) = EX(call)->object; @@ -1946,19 +1946,22 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EG(called_scope) = EX(call)->called_scope; } - EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); - zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC); + num_args = opline->extended_value + EX(call)->num_additional_args; + if (EX(call)->num_additional_args) { + EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); + } else { + EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); + zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC); + } LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i=0; - zval **p = (zval**)EX(function_state).arguments; - ulong arg_count = opline->extended_value; + zend_uint i; + void **p = EX(function_state).arguments - num_args; - while (arg_count>0) { - zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); - arg_count--; + for (i = 0; i < num_args; ++i, ++p) { + zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC); } } @@ -1972,7 +1975,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(opline->extended_value, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC); } @@ -2022,7 +2025,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) /* Not sure what should be done here if it's a static method */ if (EXPECTED(EX(object) != NULL)) { - Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -2476,6 +2479,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2602,6 +2607,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2625,10 +2632,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2653,10 +2663,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } efree(lcname); FREE_OP2(); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && @@ -2673,8 +2686,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { FREE_OP2(); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && @@ -2740,8 +2756,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + FREE_OP2(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2779,7 +2798,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -2805,9 +2826,11 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } + call->fbc = EX(function_state).function; call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -3039,10 +3062,13 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -3100,14 +3126,18 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) USE_OPLINE zend_free_op free_op1; zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } } varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -3125,7 +3155,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -3162,9 +3192,11 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -3181,14 +3213,164 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + } } SAVE_OPLINE(); ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } +ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num; + SAVE_OPLINE(); + + args = GET_OP1_ZVAL_PTR(BP_VAR_R); + arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + + switch (Z_TYPE_P(args)) { + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_P(args); + HashPosition pos; + zval **arg_ptr, *arg; + + ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void **) &arg_ptr, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos), ++arg_num + ) { + char *name; + zend_uint name_len; + zend_ulong index; + + if (zend_hash_get_current_key_ex(ht, &name, &name_len, &index, 0, &pos) == HASH_KEY_IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys"); + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(arg_ptr); + arg = *arg_ptr; + Z_ADDREF_P(arg); + } else if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + } + break; + } + case IS_OBJECT: { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + break; + } + + iter = ce->get_iterator(ce, args, 0 TSRMLS_CC); + if (UNEXPECTED(!iter)) { + FREE_OP1(); + if (!EG(exception)) { + zend_throw_exception_ex( + NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name + ); + } + HANDLE_EXCEPTION(); + } + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + } + + for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { + zval **arg_ptr, *arg; + + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + iter->funcs->get_current_data(iter, &arg_ptr TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + if (Z_TYPE(key) == IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, + "Cannot unpack Traversable with string keys"); + zval_dtor(&key); + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + + zval_dtor(&key); + } + + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error( + E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" + " by unpacking a Traversable, passing by-value instead", arg_num, + EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name : "", + EX(call)->fbc->common.scope ? "::" : "", + EX(call)->fbc->common.function_name + ); + } + + if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + ZEND_VM_STACK_GROW_IF_NEEDED(1); + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + + iter->funcs->move_forward(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + ZEND_VM_C_GOTO(unpack_iter_dtor); + } + } + +ZEND_VM_C_LABEL(unpack_iter_dtor): + iter->funcs->dtor(iter TSRMLS_CC); + break; + } + default: + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + } + + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE @@ -3424,6 +3606,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) call->fbc = constructor; call->object = object_zval; call->called_scope = EX_T(opline->op1.var).class_entry; + call->num_additional_args = 0; call->is_ctor_call = 1; call->is_ctor_result_used = RETURN_VALUE_USED(opline); EX(call) = call; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1bf417ed0d..49d04a2bae 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -481,6 +481,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR USE_OPLINE zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_uint num_args; SAVE_OPLINE(); EX(object) = EX(call)->object; @@ -525,19 +526,22 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR EG(called_scope) = EX(call)->called_scope; } - EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); - zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC); + num_args = opline->extended_value + EX(call)->num_additional_args; + if (EX(call)->num_additional_args) { + EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); + } else { + EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); + zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC); + } LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i=0; - zval **p = (zval**)EX(function_state).arguments; - ulong arg_count = opline->extended_value; + zend_uint i; + void **p = EX(function_state).arguments - num_args; - while (arg_count>0) { - zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); - arg_count--; + for (i = 0; i < num_args; ++i, ++p) { + zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC); } } @@ -551,7 +555,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(opline->extended_value, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC); } @@ -601,7 +605,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR /* Not sure what should be done here if it's a static method */ if (EXPECTED(EX(object) != NULL)) { - Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -701,6 +705,154 @@ static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER ZEND_VM_RETURN(); } +static int ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num; + SAVE_OPLINE(); + + args = get_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, BP_VAR_R); + arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + + switch (Z_TYPE_P(args)) { + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_P(args); + HashPosition pos; + zval **arg_ptr, *arg; + + ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void **) &arg_ptr, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos), ++arg_num + ) { + char *name; + zend_uint name_len; + zend_ulong index; + + if (zend_hash_get_current_key_ex(ht, &name, &name_len, &index, 0, &pos) == HASH_KEY_IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys"); + FREE_OP(free_op1); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(arg_ptr); + arg = *arg_ptr; + Z_ADDREF_P(arg); + } else if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + } + break; + } + case IS_OBJECT: { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + break; + } + + iter = ce->get_iterator(ce, args, 0 TSRMLS_CC); + if (UNEXPECTED(!iter)) { + FREE_OP(free_op1); + if (!EG(exception)) { + zend_throw_exception_ex( + NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name + ); + } + HANDLE_EXCEPTION(); + } + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + + for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { + zval **arg_ptr, *arg; + + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + iter->funcs->get_current_data(iter, &arg_ptr TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (Z_TYPE(key) == IS_STRING) { + zend_error(E_RECOVERABLE_ERROR, + "Cannot unpack Traversable with string keys"); + zval_dtor(&key); + goto unpack_iter_dtor; + } + + zval_dtor(&key); + } + + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error( + E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" + " by unpacking a Traversable, passing by-value instead", arg_num, + EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name : "", + EX(call)->fbc->common.scope ? "::" : "", + EX(call)->fbc->common.function_name + ); + } + + if (Z_ISREF_PP(arg_ptr)) { + ALLOC_ZVAL(arg); + MAKE_COPY_ZVAL(arg_ptr, arg); + } else { + arg = *arg_ptr; + Z_ADDREF_P(arg); + } + + ZEND_VM_STACK_GROW_IF_NEEDED(1); + zend_vm_stack_push(arg TSRMLS_CC); + EX(call)->num_additional_args++; + + iter->funcs->move_forward(iter TSRMLS_CC); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + +unpack_iter_dtor: + iter->funcs->dtor(iter TSRMLS_CC); + break; + } + default: + zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + } + + FREE_OP(free_op1); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -814,6 +966,7 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) call->fbc = constructor; call->object = object_zval; call->called_scope = EX_T(opline->op1.var).class_entry; + call->num_additional_args = 0; call->is_ctor_call = 1; call->is_ctor_result_used = RETURN_VALUE_USED(opline); EX(call) = call; @@ -1285,10 +1438,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1315,8 +1471,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && @@ -1333,8 +1491,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && @@ -1400,6 +1561,8 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -1439,7 +1602,9 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -1609,10 +1774,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1637,10 +1805,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } efree(lcname); zval_dtor(free_op2.var); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && @@ -1657,8 +1828,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { zval_dtor(free_op2.var); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && @@ -1724,8 +1898,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + zval_dtor(free_op2.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1796,10 +1973,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1824,10 +2004,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } efree(lcname); zval_ptr_dtor_nogc(&free_op2.var); + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && @@ -1844,8 +2027,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { zval_ptr_dtor_nogc(&free_op2.var); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && @@ -1911,8 +2097,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + zval_ptr_dtor_nogc(&free_op2.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2021,10 +2210,13 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } + call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2051,8 +2243,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && @@ -2069,8 +2263,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && @@ -2136,6 +2333,8 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2375,9 +2574,11 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } + call->fbc = EX(function_state).function; call->object = NULL; call->called_scope = NULL; + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -2534,10 +2735,13 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -3542,7 +3746,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCO { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -3712,6 +3916,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -4695,6 +4901,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -5396,7 +5604,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5542,6 +5750,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -6131,7 +6341,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPC { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6260,6 +6470,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -7111,6 +7323,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -7819,10 +8033,13 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG USE_OPLINE SAVE_OPLINE(); - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num); + } } + { zval *valptr; zval *value; @@ -8880,7 +9097,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -9051,6 +9268,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -9899,6 +10118,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -10602,7 +10823,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -10748,6 +10969,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -11339,7 +11562,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -12177,6 +12400,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -13040,14 +13265,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND USE_OPLINE zend_free_op free_op1; zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -13065,7 +13294,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -13102,9 +13331,11 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -13121,9 +13352,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SAVE_OPLINE(); return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -14738,7 +14971,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14846,9 +15079,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -15083,7 +15315,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -15395,6 +15627,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -15520,6 +15754,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -17169,9 +17405,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -17406,7 +17641,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -17719,6 +17954,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -17845,6 +18082,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -19290,7 +19529,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -19398,9 +19637,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -19635,7 +19873,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -20003,6 +20241,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -20129,6 +20369,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -21255,7 +21497,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -21331,9 +21573,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_O SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -21554,6 +21795,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -22829,9 +23072,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -23066,7 +23308,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -23431,6 +23673,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -23556,6 +23800,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ call->called_scope = Z_OBJCE_P(call->object); } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -24827,7 +25073,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -25049,6 +25295,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -26230,7 +26478,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_TMP_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -26451,6 +26699,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -27537,7 +27787,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_VAR_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -27758,6 +28008,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -29268,7 +29520,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CV_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -29488,6 +29740,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -30516,14 +30770,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL USE_OPLINE zval *varptr; + int arg_num; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else { + arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); @@ -30541,7 +30799,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -30578,9 +30836,11 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && - EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); @@ -30596,9 +30856,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS { USE_OPLINE - if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { - return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { + int arg_num = opline->op2.num + EX(call)->num_additional_args; + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } } SAVE_OPLINE(); return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -32067,7 +32329,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_ { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_CONST(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -32174,9 +32436,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -32408,7 +32669,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -32717,6 +32978,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -34264,9 +34527,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -34498,7 +34760,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -34808,6 +35070,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -36249,7 +36513,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HA { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_VAR(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -36356,9 +36620,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -36590,7 +36853,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -36954,6 +37217,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -38076,7 +38341,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_UNUSED(zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -38151,9 +38416,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -39502,9 +39766,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { zval **container = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } @@ -39736,7 +39999,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -40097,6 +40360,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H call->object = this_ptr; } } + + call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; @@ -44788,6 +45053,31 @@ void zend_init_opcodes_handlers(void) ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_SEND_UNPACK_SPEC_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 3e8df979c8..d6f51cce5c 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include <stdio.h> #include <zend.h> -const char *zend_vm_opcodes_map[165] = { +const char *zend_vm_opcodes_map[166] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -187,6 +187,7 @@ const char *zend_vm_opcodes_map[165] = { "ZEND_FAST_CALL", "ZEND_FAST_RET", "ZEND_RECV_VARIADIC", + "ZEND_SEND_UNPACK", }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 50741d1873..0f75196ffb 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -170,5 +170,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_FAST_CALL 162 #define ZEND_FAST_RET 163 #define ZEND_RECV_VARIADIC 164 +#define ZEND_SEND_UNPACK 165 #endif diff --git a/ext/date/lib/fallbackmap.h b/ext/date/lib/fallbackmap.h index 4e4c23c96e..af69482c0c 100644 --- a/ext/date/lib/fallbackmap.h +++ b/ext/date/lib/fallbackmap.h @@ -1,40 +1,42 @@ - { "sst", 0, -11, "Pacific/Apia" }, - { "hst", 0, -10, "Pacific/Honolulu" }, - { "akst", 0, -9, "America/Anchorage" }, - { "akdt", 1, -8, "America/Anchorage" }, - { "pst", 0, -8, "America/Los_Angeles" }, - { "pdt", 1, -7, "America/Los_Angeles" }, - { "mst", 0, -7, "America/Denver" }, - { "mdt", 1, -6, "America/Denver" }, - { "cst", 0, -6, "America/Chicago" }, - { "cdt", 1, -5, "America/Chicago" }, - { "est", 0, -5, "America/New_York" }, - { "edt", 1, -4, "America/New_York" }, - { "ast", 0, -4, "America/Halifax" }, - { "adt", 1, -3, "America/Halifax" }, - { "brt", 0, -3, "America/Sao_Paulo" }, - { "brst", 1, -2, "America/Sao_Paulo" }, - { "azost", 0, -1, "Atlantic/Azores" }, - { "azodt", 1, 0, "Atlantic/Azores" }, - { "gmt", 0, 0, "Europe/London" }, - { "bst", 1, 1, "Europe/London" }, - { "cet", 0, 1, "Europe/Paris" }, - { "cest", 1, 2, "Europe/Paris" }, - { "eet", 0, 2, "Europe/Helsinki" }, - { "eest", 1, 3, "Europe/Helsinki" }, - { "msk", 0, 3, "Europe/Moscow" }, - { "msd", 1, 4, "Europe/Moscow" }, - { "gst", 0, 4, "Asia/Dubai" }, - { "pkt", 0, 5, "Asia/Karachi" }, - { "ist", 0, 5.5, "Asia/Kolkata" }, - { "npt", 0, 5.75, "Asia/Katmandu" }, - { "yekt", 1, 6, "Asia/Yekaterinburg" }, - { "novst", 1, 7, "Asia/Novosibirsk" }, - { "krat", 0, 7, "Asia/Krasnoyarsk" }, - { "krast", 1, 8, "Asia/Krasnoyarsk" }, - { "jst", 0, 9, "Asia/Tokyo" }, - { "est", 0, 10, "Australia/Melbourne" }, - { "cst", 1, 10.5, "Australia/Adelaide" }, - { "est", 1, 11, "Australia/Melbourne" }, - { "nzst", 0, 12, "Pacific/Auckland" }, - { "nzdt", 1, 13, "Pacific/Auckland" }, + { "sst", 0, -660, "Pacific/Apia" }, + { "hst", 0, -600, "Pacific/Honolulu" }, + { "akst", 0, -540, "America/Anchorage" }, + { "akdt", 1, -480, "America/Anchorage" }, + { "pst", 0, -480, "America/Los_Angeles" }, + { "pdt", 1, -420, "America/Los_Angeles" }, + { "mst", 0, -420, "America/Denver" }, + { "mdt", 1, -360, "America/Denver" }, + { "cst", 0, -360, "America/Chicago" }, + { "cdt", 1, -300, "America/Chicago" }, + { "est", 0, -300, "America/New_York" }, + { "vet", 0, -270, "America/Caracas" }, + { "edt", 1, -240, "America/New_York" }, + { "ast", 0, -240, "America/Halifax" }, + { "adt", 1, -180, "America/Halifax" }, + { "brt", 0, -180, "America/Sao_Paulo" }, + { "brst", 1, -120, "America/Sao_Paulo" }, + { "azost", 0, -60, "Atlantic/Azores" }, + { "azodt", 1, 0, "Atlantic/Azores" }, + { "gmt", 0, 0, "Europe/London" }, + { "bst", 1, 60, "Europe/London" }, + { "cet", 0, 60, "Europe/Paris" }, + { "cest", 1, 120, "Europe/Paris" }, + { "eet", 0, 120, "Europe/Helsinki" }, + { "eest", 1, 180, "Europe/Helsinki" }, + { "msk", 0, 180, "Europe/Moscow" }, + { "msd", 1, 240, "Europe/Moscow" }, + { "gst", 0, 240, "Asia/Dubai" }, + { "pkt", 0, 300, "Asia/Karachi" }, + { "ist", 0, 330, "Asia/Kolkata" }, + { "npt", 0, 345, "Asia/Katmandu" }, + { "yekt", 1, 360, "Asia/Yekaterinburg" }, + { "novst", 1, 420, "Asia/Novosibirsk" }, + { "krat", 0, 420, "Asia/Krasnoyarsk" }, + { "cst", 0, 480, "Asia/Shanghai" }, + { "krast", 1, 480, "Asia/Krasnoyarsk" }, + { "jst", 0, 540, "Asia/Tokyo" }, + { "est", 0, 600, "Australia/Melbourne" }, + { "cst", 1, 630, "Australia/Adelaide" }, + { "est", 1, 660, "Australia/Melbourne" }, + { "nzst", 0, 720, "Pacific/Auckland" }, + { "nzdt", 1, 780, "Pacific/Auckland" }, diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index e8dec50292..bb4c700d39 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,10 +1,10 @@ -/* Generated by re2c 0.13.5 on Sun Aug 25 15:12:48 2013 */ +/* Generated by re2c 0.13.5 on Sat Jan 25 16:16:11 2014 */ #line 1 "ext/date/lib/parse_date.re" /* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2014 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -717,7 +717,7 @@ const static timelib_tz_lookup_table* zone_search(const char *word, long gmtoffs /* Still didn't find anything, let's find the zone solely based on * offset/isdst then */ for (fmp = timelib_timezone_fallbackmap; fmp->name; fmp++) { - if ((fmp->gmtoffset * 3600) == gmtoffset && fmp->type == isdst) { + if ((fmp->gmtoffset * 60) == gmtoffset && fmp->type == isdst) { return fmp; } } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index af1dcc045f..f9595889ec 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -715,7 +715,7 @@ const static timelib_tz_lookup_table* zone_search(const char *word, long gmtoffs /* Still didn't find anything, let's find the zone solely based on * offset/isdst then */ for (fmp = timelib_timezone_fallbackmap; fmp->name; fmp++) { - if ((fmp->gmtoffset * 3600) == gmtoffset && fmp->type == isdst) { + if ((fmp->gmtoffset * 60) == gmtoffset && fmp->type == isdst) { return fmp; } } diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index f5e7597835..866eaf3dd2 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -92,6 +92,8 @@ int timelib_apply_localtime(timelib_time *t, unsigned int localtime); void timelib_unixtime2gmt(timelib_time* tm, timelib_sll ts); void timelib_unixtime2local(timelib_time *tm, timelib_sll ts); void timelib_update_from_sse(timelib_time *tm); +void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset); +void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info); void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz); /* From parse_tz.c */ diff --git a/ext/date/lib/timelib_structs.h b/ext/date/lib/timelib_structs.h index de75545c48..5033321356 100644 --- a/ext/date/lib/timelib_structs.h +++ b/ext/date/lib/timelib_structs.h @@ -142,6 +142,12 @@ typedef struct timelib_time { * 2 TimeZone abbreviation */ } timelib_time; +typedef struct timelib_abbr_info { + timelib_sll utc_offset; + char *abbr; + int dst; +} timelib_abbr_info; + typedef struct timelib_error_message { int position; char character; diff --git a/ext/date/lib/unixtime2tm.c b/ext/date/lib/unixtime2tm.c index eefbaa8f37..9870313fbc 100644 --- a/ext/date/lib/unixtime2tm.c +++ b/ext/date/lib/unixtime2tm.c @@ -214,6 +214,34 @@ void timelib_unixtime2local(timelib_time *tm, timelib_sll ts) tm->have_zone = 1; } +void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset) +{ + if (t->tz_abbr) { + free(t->tz_abbr); + } + t->tz_abbr = NULL; + + t->z = utc_offset; + t->have_zone = 1; + t->zone_type = TIMELIB_ZONETYPE_OFFSET; + t->dst = 0; + t->tz_info = NULL; +} + +void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info) +{ + if (t->tz_abbr) { + free(t->tz_abbr); + } + t->tz_abbr = strdup(abbr_info.abbr); + + t->z = abbr_info.utc_offset; + t->have_zone = 1; + t->zone_type = TIMELIB_ZONETYPE_ABBR; + t->dst = abbr_info.dst; + t->tz_info = NULL; +} + void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz) { timelib_time_offset *gmt_offset; diff --git a/ext/date/php_date.c b/ext/date/php_date.c index c069e0ccae..0e21baffa6 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -3284,11 +3284,18 @@ static void php_date_timezone_set(zval *object, zval *timezone_object, zval *ret dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC); - if (tzobj->type != TIMELIB_ZONETYPE_ID) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now"); - return; + + switch (tzobj->type) { + case TIMELIB_ZONETYPE_OFFSET: + timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset); + break; + case TIMELIB_ZONETYPE_ABBR: + timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z); + break; + case TIMELIB_ZONETYPE_ID: + timelib_set_timezone(dateobj->time, tzobj->tzi.tz); + break; } - timelib_set_timezone(dateobj->time, tzobj->tzi.tz); timelib_unixtime2local(dateobj->time, dateobj->time->sse); } diff --git a/ext/date/php_date.h b/ext/date/php_date.h index d4204ebd79..d7343e02bc 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -137,14 +137,9 @@ struct _php_timezone_obj { int initialized; int type; union { - timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID; */ - timelib_sll utc_offset; /* TIMELIB_ZONETYPE_OFFSET */ - struct /* TIMELIB_ZONETYPE_ABBR */ - { - timelib_sll utc_offset; - char *abbr; - int dst; - } z; + timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID */ + timelib_sll utc_offset; /* TIMELIB_ZONETYPE_OFFSET */ + timelib_abbr_info z; /* TIMELIB_ZONETYPE_ABBR */ } tzi; HashTable *props; }; diff --git a/ext/date/tests/bug44780.phpt b/ext/date/tests/bug44780.phpt new file mode 100644 index 0000000000..5c822d48e6 --- /dev/null +++ b/ext/date/tests/bug44780.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #44780 (some time zone offsets not recognized by timezone_name_from_abbr) +--FILE-- +<?php +var_dump( timezone_name_from_abbr("", 5.5*3600, false) ); +var_dump( timezone_name_from_abbr("", 28800, false) ); +?> +--EXPECT-- +string(12) "Asia/Kolkata" +string(13) "Asia/Shanghai" diff --git a/ext/date/tests/bug45543.phpt b/ext/date/tests/bug45543.phpt new file mode 100644 index 0000000000..8e36e6287c --- /dev/null +++ b/ext/date/tests/bug45543.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test for bug #45543: DateTime::setTimezone can not set timezones without ID. +--INI-- +date.timezone=UTC +--FILE-- +<?php +$test_dates = array( + '2008-01-01 12:00:00 PDT', + '2008-01-01 12:00:00 +02:00', +); + +foreach ($test_dates as $test_date) +{ + $d1 = new DateTime($test_date); + $d2 = new DateTime('2008-01-01 12:00:00 UTC'); + echo $d1->format(DATE_ISO8601), PHP_EOL; + echo $d2->format(DATE_ISO8601), PHP_EOL; + $tz = $d1->getTimeZone(); + $d2->setTimeZone($tz); + echo $d1->format(DATE_ISO8601), PHP_EOL; + echo $d2->format(DATE_ISO8601), PHP_EOL; + echo PHP_EOL; +} +--EXPECT-- +2008-01-01T12:00:00-0700 +2008-01-01T12:00:00+0000 +2008-01-01T12:00:00-0700 +2008-01-01T05:00:00-0700 + +2008-01-01T12:00:00+0200 +2008-01-01T12:00:00+0000 +2008-01-01T12:00:00+0200 +2008-01-01T14:00:00+0200 + diff --git a/ext/date/tests/bug65371.phpt b/ext/date/tests/bug65371.phpt new file mode 100644 index 0000000000..a6e3126514 --- /dev/null +++ b/ext/date/tests/bug65371.phpt @@ -0,0 +1,22 @@ +--TEST-- +Testing bug #65371 +--INI-- +date.timezone=Europe/Berlin +--FILE-- +<?php + +function p($str) +{ + echo $str, "\n"; + echo strftime($str), "\n"; + echo bin2hex($str), "\n"; + echo bin2hex(strftime($str)); +} + +setlocale(LC_ALL, 'C'); +p('ã‚'); +--EXPECT-- +ã‚ +ã‚ +e38182 +e38182 diff --git a/ext/gd/libgd/gdft.c b/ext/gd/libgd/gdft.c index ac2bf344ff..aa8e8d3a74 100644 --- a/ext/gd/libgd/gdft.c +++ b/ext/gd/libgd/gdft.c @@ -1050,7 +1050,15 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi } /* transform glyph image */ - FT_Get_Glyph(slot, &image); + if (FT_Get_Glyph(slot, &image)) { + if (tmpstr) { + gdFree(tmpstr); + } + gdCacheDelete(tc_cache); + gdMutexUnlock(gdFontCacheMutex); + return "Problem loading glyph"; + } + if (brect) { /* only if need brect */ FT_Glyph_Get_CBox(image, ft_glyph_bbox_gridfit, &glyph_bbox); glyph_bbox.xMin += penf.x; diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index bb1dca8124..22cde6bd6d 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -118,6 +118,7 @@ if (PHP_INTL != "no") { "intl"); ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib"); + ADD_FLAG("CFLAGS_INTL", "/EHsc"); AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled"); } else { WARNING("intl not enabled; libraries and/or headers not found"); diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index e9b9d2e97c..f5583cd8c0 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -155,6 +155,15 @@ PHP_MINIT_FUNCTION(ldap) REGISTER_LONG_CONSTANT("LDAP_DEREF_FINDING", LDAP_DEREF_FINDING, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("LDAP_DEREF_ALWAYS", LDAP_DEREF_ALWAYS, CONST_PERSISTENT | CONST_CS); + /* Constants to be used with ldap_modify_batch() */ + REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_ADD", LDAP_MODIFY_BATCH_ADD, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE", LDAP_MODIFY_BATCH_REMOVE, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE_ALL", LDAP_MODIFY_BATCH_REMOVE_ALL, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REPLACE", LDAP_MODIFY_BATCH_REPLACE, CONST_PERSISTENT | CONST_CS); + REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_ATTRIB", LDAP_MODIFY_BATCH_ATTRIB, CONST_PERSISTENT | CONST_CS); + REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_MODTYPE", LDAP_MODIFY_BATCH_MODTYPE, CONST_PERSISTENT | CONST_CS); + REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_VALUES", LDAP_MODIFY_BATCH_VALUES, CONST_PERSISTENT | CONST_CS); + #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP /* LDAP options */ REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT | CONST_CS); @@ -1438,6 +1447,355 @@ PHP_FUNCTION(ldap_delete) } /* }}} */ +/* {{{ _ldap_str_equal_to_const + */ +static int _ldap_str_equal_to_const(const char *str, uint str_len, const char *cstr) +{ + int i; + + if (strlen(cstr) != str_len) + return 0; + + for (i = 0; i < str_len; ++i) { + if (str[i] != cstr[i]) { + return 0; + } + } + + return 1; +} +/* }}} */ + +/* {{{ _ldap_strlen_max + */ +static int _ldap_strlen_max(const char *str, uint max_len) +{ + int i; + + for (i = 0; i < max_len; ++i) { + if (str[i] == '\0') { + return i; + } + } + + return max_len; +} +/* }}} */ + +/* {{{ _ldap_hash_fetch + */ +static void _ldap_hash_fetch(zval *hashTbl, const char *key, zval **out) +{ + zval **fetched; + if (zend_hash_find(Z_ARRVAL_P(hashTbl), key, strlen(key)+1, (void **) &fetched) == SUCCESS) { + *out = *fetched; + } + else { + *out = NULL; + } +} +/* }}} */ + +/* {{{ proto bool ldap_modify_batch(resource link, string dn, array modifs) + Perform multiple modifications as part of one operation */ +PHP_FUNCTION(ldap_modify_batch) +{ + ldap_linkdata *ld; + zval *link, *mods, *mod, *modinfo, *modval; + zval *attrib, *modtype, *vals; + zval **fetched; + char *dn; + int dn_len; + int i, j, k; + int num_mods, num_modprops, num_modvals; + LDAPMod **ldap_mods; + uint oper; + + /* + $mods = array( + array( + "attrib" => "unicodePwd", + "modtype" => LDAP_MODIFY_BATCH_REMOVE, + "values" => array($oldpw) + ), + array( + "attrib" => "unicodePwd", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => array($newpw) + ), + array( + "attrib" => "userPrincipalName", + "modtype" => LDAP_MODIFY_BATCH_REPLACE, + "values" => array("janitor@corp.contoso.com") + ), + array( + "attrib" => "userCert", + "modtype" => LDAP_MODIFY_BATCH_REMOVE_ALL + ) + ); + */ + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &mods) != SUCCESS) { + return; + } + + ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link); + + /* perform validation */ + { + char *modkey; + uint modkeylen; + long modtype; + + /* to store the wrongly-typed keys */ + ulong tmpUlong; + + /* make sure the DN contains no NUL bytes */ + if (_ldap_strlen_max(dn, dn_len) != dn_len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "DN must not contain NUL bytes"); + RETURN_FALSE; + } + + /* make sure the top level is a normal array */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(mods)); + if (zend_hash_get_current_key_type(Z_ARRVAL_P(mods)) != HASH_KEY_IS_LONG) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modifications array must not be string-indexed"); + RETURN_FALSE; + } + + num_mods = zend_hash_num_elements(Z_ARRVAL_P(mods)); + + for (i = 0; i < num_mods; i++) { + /* is the numbering consecutive? */ + if (zend_hash_index_find(Z_ARRVAL_P(mods), i, (void **) &fetched) != SUCCESS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modifications array must have consecutive indices 0, 1, ..."); + RETURN_FALSE; + } + mod = *fetched; + + /* is it an array? */ + if (Z_TYPE_P(mod) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Each entry of modifications array must be an array itself"); + RETURN_FALSE; + } + + /* for the modification hashtable... */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(mod)); + num_modprops = zend_hash_num_elements(Z_ARRVAL_P(mod)); + + for (j = 0; j < num_modprops; j++) { + /* are the keys strings? */ + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(mod), &modkey, &modkeylen, &tmpUlong, 0, NULL) != HASH_KEY_IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Each entry of modifications array must be string-indexed"); + RETURN_FALSE; + } + + /* modkeylen includes the terminating NUL byte; remove that */ + --modkeylen; + + /* is this a valid entry? */ + if ( + !_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_ATTRIB) && + !_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_MODTYPE) && + !_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_VALUES) + ) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The only allowed keys in entries of the modifications array are '" LDAP_MODIFY_BATCH_ATTRIB "', '" LDAP_MODIFY_BATCH_MODTYPE "' and '" LDAP_MODIFY_BATCH_VALUES "'"); + RETURN_FALSE; + } + + zend_hash_get_current_data(Z_ARRVAL_P(mod), (void **) &fetched); + modinfo = *fetched; + + /* does the value type match the key? */ + if (_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_ATTRIB)) { + if (Z_TYPE_P(modinfo) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must be a string"); + RETURN_FALSE; + } + + if (Z_STRLEN_P(modinfo) != _ldap_strlen_max(Z_STRVAL_P(modinfo), Z_STRLEN_P(modinfo))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must not contain NUL bytes"); + RETURN_FALSE; + } + } + else if (_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_MODTYPE)) { + if (Z_TYPE_P(modinfo) != IS_LONG) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_MODTYPE "' value must be a long"); + RETURN_FALSE; + } + + /* is the value in range? */ + modtype = Z_LVAL_P(modinfo); + if ( + modtype != LDAP_MODIFY_BATCH_ADD && + modtype != LDAP_MODIFY_BATCH_REMOVE && + modtype != LDAP_MODIFY_BATCH_REPLACE && + modtype != LDAP_MODIFY_BATCH_REMOVE_ALL + ) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The '" LDAP_MODIFY_BATCH_MODTYPE "' value must match one of the LDAP_MODIFY_BATCH_* constants"); + RETURN_FALSE; + } + + /* if it's REMOVE_ALL, there must not be a values array; otherwise, there must */ + if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL) { + if (zend_hash_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES) + 1)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "If '" LDAP_MODIFY_BATCH_MODTYPE "' is LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must not be provided"); + RETURN_FALSE; + } + } + else { + if (!zend_hash_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES) + 1)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "If '" LDAP_MODIFY_BATCH_MODTYPE "' is not LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must be provided"); + RETURN_FALSE; + } + } + } + else if (_ldap_str_equal_to_const(modkey, modkeylen, LDAP_MODIFY_BATCH_VALUES)) { + if (Z_TYPE_P(modinfo) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' value must be an array"); + RETURN_FALSE; + } + + /* is the array not empty? */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(modinfo)); + num_modvals = zend_hash_num_elements(Z_ARRVAL_P(modinfo)); + if (num_modvals == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have at least one element"); + RETURN_FALSE; + } + + /* are its keys integers? */ + if (zend_hash_get_current_key_type(Z_ARRVAL_P(modinfo)) != HASH_KEY_IS_LONG) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must not be string-indexed"); + RETURN_FALSE; + } + + /* are the keys consecutive? */ + for (k = 0; k < num_modvals; k++) { + if (zend_hash_index_find(Z_ARRVAL_P(modinfo), k, (void **) &fetched) != SUCCESS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have consecutive indices 0, 1, ..."); + RETURN_FALSE; + } + modval = *fetched; + + /* is the data element a string? */ + if (Z_TYPE_P(modval) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Each element of a '" LDAP_MODIFY_BATCH_VALUES "' array must be a string"); + RETURN_FALSE; + } + } + } + + zend_hash_move_forward(Z_ARRVAL_P(mod)); + } + } + } + /* validation was successful */ + + /* allocate array of modifications */ + ldap_mods = safe_emalloc((num_mods+1), sizeof(LDAPMod *), 0); + + /* for each modification */ + for (i = 0; i < num_mods; i++) { + /* allocate the modification struct */ + ldap_mods[i] = safe_emalloc(1, sizeof(LDAPMod), 0); + + /* fetch the relevant data */ + zend_hash_index_find(Z_ARRVAL_P(mods), i, (void **) &fetched); + mod = *fetched; + + _ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_ATTRIB, &attrib); + _ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_MODTYPE, &modtype); + _ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_VALUES, &vals); + + /* map the modification type */ + switch (Z_LVAL_P(modtype)) { + case LDAP_MODIFY_BATCH_ADD: + oper = LDAP_MOD_ADD; + break; + case LDAP_MODIFY_BATCH_REMOVE: + case LDAP_MODIFY_BATCH_REMOVE_ALL: + oper = LDAP_MOD_DELETE; + break; + case LDAP_MODIFY_BATCH_REPLACE: + oper = LDAP_MOD_REPLACE; + break; + default: + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown and uncaught modification type."); + RETURN_FALSE; + } + + /* fill in the basic info */ + ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES; + ldap_mods[i]->mod_type = estrndup(Z_STRVAL_P(attrib), Z_STRLEN_P(attrib)); + + if (Z_LVAL_P(modtype) == LDAP_MODIFY_BATCH_REMOVE_ALL) { + /* no values */ + ldap_mods[i]->mod_bvalues = NULL; + } + else { + /* allocate space for the values as part of this modification */ + num_modvals = zend_hash_num_elements(Z_ARRVAL_P(vals)); + ldap_mods[i]->mod_bvalues = safe_emalloc((num_modvals+1), sizeof(struct berval *), 0); + + /* for each value */ + for (j = 0; j < num_modvals; j++) { + /* fetch it */ + zend_hash_index_find(Z_ARRVAL_P(vals), j, (void **) &fetched); + modval = *fetched; + + /* allocate the data struct */ + ldap_mods[i]->mod_bvalues[j] = safe_emalloc(1, sizeof(struct berval), 0); + + /* fill it */ + ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_P(modval); + ldap_mods[i]->mod_bvalues[j]->bv_val = estrndup(Z_STRVAL_P(modval), Z_STRLEN_P(modval)); + } + + /* NULL-terminate values */ + ldap_mods[i]->mod_bvalues[num_modvals] = NULL; + } + } + + /* NULL-terminate modifications */ + ldap_mods[num_mods] = NULL; + + /* perform (finally) */ + if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Batch Modify: %s", ldap_err2string(i)); + RETVAL_FALSE; + } else RETVAL_TRUE; + + /* clean up */ + { + for (i = 0; i < num_mods; i++) { + /* attribute */ + efree(ldap_mods[i]->mod_type); + + if (ldap_mods[i]->mod_bvalues != NULL) { + /* each BER value */ + for (j = 0; ldap_mods[i]->mod_bvalues[j] != NULL; j++) { + /* free the data bytes */ + efree(ldap_mods[i]->mod_bvalues[j]->bv_val); + + /* free the bvalue struct */ + efree(ldap_mods[i]->mod_bvalues[j]); + } + + /* the BER value array */ + efree(ldap_mods[i]->mod_bvalues); + } + + /* the modification */ + efree(ldap_mods[i]); + } + + /* the modifications array */ + efree(ldap_mods); + } +} +/* }}} */ + /* {{{ proto int ldap_errno(resource link) Get the current ldap error number */ PHP_FUNCTION(ldap_errno) @@ -2599,6 +2957,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3) ZEND_ARG_INFO(0, entry) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify_batch, 0, 0, 3) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, dn) + ZEND_ARG_ARRAY_INFO(0, modifications_info, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add, 0, 0, 3) ZEND_ARG_INFO(0, link_identifier) ZEND_ARG_INFO(0, dn) @@ -2758,6 +3122,7 @@ const zend_function_entry ldap_functions[] = { PHP_FE(ldap_dn2ufn, arginfo_ldap_dn2ufn) PHP_FE(ldap_add, arginfo_ldap_add) PHP_FE(ldap_delete, arginfo_ldap_delete) + PHP_FE(ldap_modify_batch, arginfo_ldap_modify_batch) PHP_FALIAS(ldap_modify, ldap_mod_replace, arginfo_ldap_modify) /* additional functions for attribute based modifications, Gerrit Thomson */ diff --git a/ext/ldap/php_ldap.h b/ext/ldap/php_ldap.h index e10c8a7e61..bd3731819d 100644 --- a/ext/ldap/php_ldap.h +++ b/ext/ldap/php_ldap.h @@ -50,4 +50,14 @@ ZEND_END_MODULE_GLOBALS(ldap) #define phpext_ldap_ptr ldap_module_ptr +/* Constants for ldap_modify_batch */ +#define LDAP_MODIFY_BATCH_ADD 0x01 +#define LDAP_MODIFY_BATCH_REMOVE 0x02 +#define LDAP_MODIFY_BATCH_REMOVE_ALL 0x12 +#define LDAP_MODIFY_BATCH_REPLACE 0x03 + +#define LDAP_MODIFY_BATCH_ATTRIB "attrib" +#define LDAP_MODIFY_BATCH_MODTYPE "modtype" +#define LDAP_MODIFY_BATCH_VALUES "values" + #endif /* PHP_LDAP_H */ diff --git a/ext/ldap/tests/ldap_modify_batch_basic.phpt b/ext/ldap/tests/ldap_modify_batch_basic.phpt new file mode 100644 index 0000000000..4f6705c7e8 --- /dev/null +++ b/ext/ldap/tests/ldap_modify_batch_basic.phpt @@ -0,0 +1,109 @@ +--TEST-- +ldap_modify_batch() - Basic batch modify operation +--CREDITS-- +Patrick Allaert <patrickallaert@php.net> +OndÅ™ej HoÅ¡ek <ondra.hosek@gmail.com> +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +<?php require_once('skipifbindfailure.inc'); ?> +--FILE-- +<?php +require "connect.inc"; + +$link = ldap_connect_and_bind($host, $port, $user, $passwd, $protocol_version); +insert_dummy_data($link); + +$mods = array( + array( + "attrib" => "telephoneNumber", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => array( + "+1 555 5551717" + ) + ), + array( + "attrib" => "sn", + "modtype" => LDAP_MODIFY_BATCH_REPLACE, + "values" => array("Brown-Smith") + ), + array( + "attrib" => "description", + "modtype" => LDAP_MODIFY_BATCH_REMOVE_ALL + ) +); + +var_dump( + ldap_modify_batch($link, "cn=userA,dc=my-domain,dc=com", $mods), + ldap_get_entries($link, ldap_search($link, "dc=my-domain,dc=com", "(sn=Brown-Smith)")) +); +?> +===DONE=== +--CLEAN-- +<?php +require "connect.inc"; + +$link = ldap_connect_and_bind($host, $port, $user, $passwd, $protocol_version); + +remove_dummy_data($link); +?> +--EXPECT-- +bool(true) +array(2) { + ["count"]=> + int(1) + [0]=> + array(12) { + ["objectclass"]=> + array(2) { + ["count"]=> + int(1) + [0]=> + string(6) "person" + } + [0]=> + string(11) "objectclass" + ["cn"]=> + array(2) { + ["count"]=> + int(1) + [0]=> + string(5) "userA" + } + [1]=> + string(2) "cn" + ["userpassword"]=> + array(2) { + ["count"]=> + int(1) + [0]=> + string(4) "oops" + } + [2]=> + string(12) "userpassword" + ["telephonenumber"]=> + array(3) { + ["count"]=> + int(2) + [0]=> + string(14) "xx-xx-xx-xx-xx" + [1]=> + string(14) "+1 555 5551717" + } + [3]=> + string(15) "telephonenumber" + ["sn"]=> + array(2) { + ["count"]=> + int(1) + [0]=> + string(11) "Brown-Smith" + } + [4]=> + string(2) "sn" + ["count"]=> + int(5) + ["dn"]=> + string(28) "cn=userA,dc=my-domain,dc=com" + } +} +===DONE=== diff --git a/ext/ldap/tests/ldap_modify_batch_error.phpt b/ext/ldap/tests/ldap_modify_batch_error.phpt new file mode 100644 index 0000000000..687c371c4d --- /dev/null +++ b/ext/ldap/tests/ldap_modify_batch_error.phpt @@ -0,0 +1,104 @@ +--TEST-- +ldap_modify_batch() - Batch modify operations that should fail +--CREDITS-- +Patrick Allaert <patrickallaert@php.net> +OndÅ™ej HoÅ¡ek <ondra.hosek@gmail.com> +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +<?php require_once('skipifbindfailure.inc'); ?> +--FILE-- +<?php +require "connect.inc"; + +$link = ldap_connect_and_bind($host, $port, $user, $passwd, $protocol_version); + +$addGivenName = array( + array( + "attrib" => "givenName", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => array("Jack") + ) +); + +// Too few parameters +var_dump(ldap_modify_batch()); +var_dump(ldap_modify_batch($link)); +var_dump(ldap_modify_batch($link, "dc=my-domain,dc=com")); + +// Too many parameters +var_dump(ldap_modify_batch($link, "dc=my-domain,dc=com", $addGivenName, "Invalid additional parameter")); + +// DN not found +var_dump(ldap_modify_batch($link, "dc=my-domain,dc=com", $addGivenName)); + +// Invalid DN +var_dump(ldap_modify_batch($link, "weirdAttribute=val", $addGivenName)); + +// prepare +$entry = array( + "objectClass" => array( + "top", + "dcObject", + "organization"), + "dc" => "my-domain", + "o" => "my-domain", +); + +ldap_add($link, "dc=my-domain,dc=com", $entry); + +// invalid domain +$mods = array( + array( + "attrib" => "dc", + "modtype" => LDAP_MODIFY_BATCH_REPLACE, + "values" => array("Wrong Domain") + ) +); + +var_dump(ldap_modify_batch($link, "dc=my-domain,dc=com", $mods)); + +// invalid attribute +$mods = array( + array( + "attrib" => "weirdAttribute", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => array("weirdVal", "anotherWeirdval") + ) +); + +var_dump(ldap_modify_batch($link, "dc=my-domain,dc=com", $mods)); +?> +===DONE=== +--CLEAN-- +<?php +require "connect.inc"; + +$link = ldap_connect_and_bind($host, $port, $user, $passwd, $protocol_version); + +ldap_delete($link, "dc=my-domain,dc=com"); +?> +--EXPECTF-- +Warning: ldap_modify_batch() expects exactly 3 parameters, 0 given in %s on line %d +NULL + +Warning: ldap_modify_batch() expects exactly 3 parameters, 1 given in %s on line %d +NULL + +Warning: ldap_modify_batch() expects exactly 3 parameters, 2 given in %s on line %d +NULL + +Warning: ldap_modify_batch() expects exactly 3 parameters, 4 given in %s on line %d +NULL + +Warning: ldap_modify_batch(): Batch Modify: No such object in %s on line %d +bool(false) + +Warning: ldap_modify_batch(): Batch Modify: Invalid DN syntax in %s on line %d +bool(false) + +Warning: ldap_modify_batch(): Batch Modify: Naming violation in %s on line %d +bool(false) + +Warning: ldap_modify_batch(): Batch Modify: Undefined attribute type in %s on line %d +bool(false) +===DONE=== diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 2e6e00b106..3114b25199 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -88,7 +88,7 @@ static PHP_MINIT_FUNCTION(libxml); static PHP_RINIT_FUNCTION(libxml); static PHP_MSHUTDOWN_FUNCTION(libxml); static PHP_MINFO_FUNCTION(libxml); -static int php_libxml_post_deactivate(); +static int php_libxml_post_deactivate(void); /* }}} */ @@ -876,7 +876,7 @@ static PHP_MSHUTDOWN_FUNCTION(libxml) return SUCCESS; } -static int php_libxml_post_deactivate() +static int php_libxml_post_deactivate(void) { TSRMLS_FETCH(); /* reset libxml generic error handling */ diff --git a/ext/mbstring/tests/zend_multibyte-01.phpt b/ext/mbstring/tests/zend_multibyte-01.phpt index d96e0f07d3..f2403abcac 100644 --- a/ext/mbstring/tests/zend_multibyte-01.phpt +++ b/ext/mbstring/tests/zend_multibyte-01.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (1) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=Shift_JIS +zend.multibyte=On +zend.script_encoding=Shift_JIS mbstring.internal_encoding=Shift_JIS --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-02.phpt b/ext/mbstring/tests/zend_multibyte-02.phpt index c94dee5a28..ebc10b48be 100644 --- a/ext/mbstring/tests/zend_multibyte-02.phpt +++ b/ext/mbstring/tests/zend_multibyte-02.phpt @@ -1,18 +1,14 @@ --TEST-- zend multibyte (2) ---SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--XFAIL-- +https://bugs.php.net/bug.php?id=66582 --INI-- -mbstring.script_encoding=UTF-8 +zend.multibyte=On +zend.script_encoding=UTF-8 mbstring.internal_encoding=CP932 --FILE-- <?php var_dump(bin2hex("テスト")); ?> ---EXPECT-- -string(12) "836583588367" +--EXPECTF-- +php: Zend/zend_language_scanner.l:%d: encoding_filter_script_to_internal: Assertion `internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding)' failed. diff --git a/ext/mbstring/tests/zend_multibyte-03.phpt b/ext/mbstring/tests/zend_multibyte-03.phpt index 46a262c32e..99c58bce70 100644 --- a/ext/mbstring/tests/zend_multibyte-03.phpt +++ b/ext/mbstring/tests/zend_multibyte-03.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (3) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=UTF-8 +zend.multibyte=On +zend.script_encoding=UTF-8 mbstring.internal_encoding=EUC-JP --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-04.phpt b/ext/mbstring/tests/zend_multibyte-04.phpt index f1295b6afe..e7fdf81cdd 100644 --- a/ext/mbstring/tests/zend_multibyte-04.phpt +++ b/ext/mbstring/tests/zend_multibyte-04.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (4) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=CP932 +zend.multibyte=On +zend.script_encoding=CP932 mbstring.internal_encoding=UTF-8 --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-05.phpt b/ext/mbstring/tests/zend_multibyte-05.phpt index 0a01c231fc..3dd56d043d 100644 --- a/ext/mbstring/tests/zend_multibyte-05.phpt +++ b/ext/mbstring/tests/zend_multibyte-05.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (5) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=EUC-JP +zend.multibyte=On +zend.script_encoding=EUC-JP mbstring.internal_encoding=UTF-8 --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-06.phpt b/ext/mbstring/tests/zend_multibyte-06.phpt index 9acd6a951d..e0b4ead545 100644 --- a/ext/mbstring/tests/zend_multibyte-06.phpt +++ b/ext/mbstring/tests/zend_multibyte-06.phpt @@ -1,19 +1,15 @@ --TEST-- zend multibyte (6) ---SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--XFAIL-- +https://bugs.php.net/bug.php?id=66582 --INI-- -mbstring.script_encoding=EUC-JP +zend.multibyte=On +zend.script_encoding=EUC-JP mbstring.internal_encoding=CP932 --FILE-- <?php declare(encoding="UTF-8"); var_dump(bin2hex("テスト")); ?> ---EXPECT-- -string(12) "836583588367" +--EXPECTF-- +php: Zend/zend_language_scanner.l:%d: encoding_filter_script_to_internal: Assertion `internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding)' failed. diff --git a/ext/mbstring/tests/zend_multibyte-07.phpt b/ext/mbstring/tests/zend_multibyte-07.phpt index 30305f5fdf..08db1d0f70 100644 --- a/ext/mbstring/tests/zend_multibyte-07.phpt +++ b/ext/mbstring/tests/zend_multibyte-07.phpt @@ -1,14 +1,11 @@ --TEST-- zend multibyte (7) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--XFAIL-- +https://bugs.php.net/bug.php?id=66582 --INI-- -mbstring.script_encoding=ISO-8859-1 +zend.multibyte=On +zend.script_encoding=ISO-8859-1 mbstring.internal_encoding=EUC-JP --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-08.phpt b/ext/mbstring/tests/zend_multibyte-08.phpt index ab27461355..488e2a00ca 100644 --- a/ext/mbstring/tests/zend_multibyte-08.phpt +++ b/ext/mbstring/tests/zend_multibyte-08.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (8) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=ISO-8859-1 +zend.multibyte=On +zend.script_encoding=ISO-8859-1 mbstring.internal_encoding=UTF-8 --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-09.phpt b/ext/mbstring/tests/zend_multibyte-09.phpt index 79ee435aa0..8ad00b4e1e 100644 --- a/ext/mbstring/tests/zend_multibyte-09.phpt +++ b/ext/mbstring/tests/zend_multibyte-09.phpt @@ -1,14 +1,11 @@ --TEST-- zend multibyte (9) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--XFAIL-- +https://bugs.php.net/bug.php?id=66582 --INI-- -mbstring.script_encoding=cp1251 +zend.multibyte=On +zend.script_encoding=cp1251 mbstring.internal_encoding=UTF-8 --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-10.phpt b/ext/mbstring/tests/zend_multibyte-10.phpt index 435c339752..139d973b95 100644 --- a/ext/mbstring/tests/zend_multibyte-10.phpt +++ b/ext/mbstring/tests/zend_multibyte-10.phpt @@ -1,12 +1,8 @@ --TEST-- zend multibyte (10) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--INI-- +zend.multibyte=1 --FILE-- <?php declare(encoding="ISO-8859-15"); diff --git a/ext/mbstring/tests/zend_multibyte-11.phpt b/ext/mbstring/tests/zend_multibyte-11.phpt index b79e4339ba..c6e45fa5cd 100644 --- a/ext/mbstring/tests/zend_multibyte-11.phpt +++ b/ext/mbstring/tests/zend_multibyte-11.phpt @@ -1,12 +1,8 @@ --TEST-- zend multibyte (11) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--INI-- +zend.multibyte=1 --FILE-- <?php declare(encoding="ISO-8859-15") { diff --git a/ext/mbstring/tests/zend_multibyte-12.phpt b/ext/mbstring/tests/zend_multibyte-12.phpt index e1c8ce52d1..90968e8820 100644 --- a/ext/mbstring/tests/zend_multibyte-12.phpt +++ b/ext/mbstring/tests/zend_multibyte-12.phpt @@ -1,12 +1,8 @@ --TEST-- zend multibyte (12) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> +--INI-- +zend.multibyte=1 --FILE-- <?php declare(encoding="ISO-8859-15"); diff --git a/ext/mbstring/tests/zend_multibyte-13.phpt b/ext/mbstring/tests/zend_multibyte-13.phpt index e601a6ceed..6eaef985f5 100644 --- a/ext/mbstring/tests/zend_multibyte-13.phpt +++ b/ext/mbstring/tests/zend_multibyte-13.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (13) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=UTF-8 +zend.multibyte=On +zend.script_encoding=UTF-8 mbstring.internal_encoding=ISO-8859-1 --FILE-- <?php diff --git a/ext/mbstring/tests/zend_multibyte-14.phpt b/ext/mbstring/tests/zend_multibyte-14.phpt index 04bc409fb6..98c2f87e25 100644 --- a/ext/mbstring/tests/zend_multibyte-14.phpt +++ b/ext/mbstring/tests/zend_multibyte-14.phpt @@ -1,14 +1,9 @@ --TEST-- zend multibyte (14) --SKIPIF-- -<?php -ini_set("mbstring.script_encoding","SJIS"); -if (ini_set("mbstring.script_encoding","SJIS") != "SJIS") { - die("skip zend-multibyte is not available"); -} -?> --INI-- -mbstring.script_encoding=UTF-8 +zend.multibyte=On +zend.script_encoding=UTF-8 mbstring.internal_encoding=UTF-8 --FILE-- <?php diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 929f776a43..2a5a8c61ff 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -558,6 +558,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY_EX("mysqli.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_mysqli_globals, mysqli_globals, display_link_numbers) STD_PHP_INI_ENTRY_EX("mysqli.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_mysqli_globals, mysqli_globals, display_link_numbers) STD_PHP_INI_BOOLEAN("mysqli.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_mysqli_globals, mysqli_globals) + STD_PHP_INI_BOOLEAN("mysqli.rollback_on_cached_plink", "0",PHP_INI_SYSTEM, OnUpdateBool, rollback_on_cached_plink, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_host", NULL, PHP_INI_ALL, OnUpdateString, default_host, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_pw", NULL, PHP_INI_ALL, OnUpdateString, default_pw, zend_mysqli_globals, mysqli_globals) @@ -597,6 +598,7 @@ static PHP_GINIT_FUNCTION(mysqli) #else mysqli_globals->embedded = 0; #endif + mysqli_globals->rollback_on_cached_plink = FALSE; } /* }}} */ diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 9028401595..d6f274b569 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -599,10 +599,20 @@ void php_mysqli_close(MY_MYSQL * mysql, int close_type, int resource_status TSRM #if defined(MYSQLI_USE_MYSQLND) mysqlnd_end_psession(mysql->mysql); #endif - zend_ptr_stack_push(&plist->free_links, mysql->mysql); + if (MyG(rollback_on_cached_plink) && +#if !defined(MYSQLI_USE_MYSQLND) + mysqli_commit_or_rollback_libmysql(mysql->mysql, FALSE, TRANS_COR_NO_OPT, NULL)) +#else + FAIL == mysqlnd_rollback(mysql->mysql, TRANS_COR_NO_OPT, NULL)) +#endif + { + mysqli_close(mysql->mysql, close_type); + } else { + zend_ptr_stack_push(&plist->free_links, mysql->mysql); + MyG(num_inactive_persistent)++; + } MyG(num_active_persistent)--; - MyG(num_inactive_persistent)++; } } mysql->persistent = FALSE; diff --git a/ext/mysqli/mysqli_fe.c b/ext/mysqli/mysqli_fe.c index 61e8e5c81e..3d31b8183c 100644 --- a/ext/mysqli/mysqli_fe.c +++ b/ext/mysqli/mysqli_fe.c @@ -373,6 +373,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_refresh, 0, 0, 1) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_no_options, 0, 0, 0) +ZEND_END_ARG_INFO() + /* {{{ mysqli_functions[] * @@ -425,6 +428,7 @@ const zend_function_entry mysqli_functions[] = { #endif PHP_FE(mysqli_get_client_info, arginfo_mysqli_only_link) PHP_FE(mysqli_get_client_version, arginfo_mysqli_only_link) + PHP_FE(mysqli_get_links_stats, arginfo_mysqli_no_options) PHP_FE(mysqli_get_host_info, arginfo_mysqli_only_link) PHP_FE(mysqli_get_proto_info, arginfo_mysqli_only_link) PHP_FE(mysqli_get_server_info, arginfo_mysqli_only_link) diff --git a/ext/mysqli/mysqli_fe.h b/ext/mysqli/mysqli_fe.h index d5ae8a6ff9..9a9f851248 100644 --- a/ext/mysqli/mysqli_fe.h +++ b/ext/mysqli/mysqli_fe.h @@ -60,6 +60,7 @@ PHP_FUNCTION(mysqli_get_charset); PHP_FUNCTION(mysqli_get_client_info); PHP_FUNCTION(mysqli_get_client_version); PHP_FUNCTION(mysqli_get_host_info); +PHP_FUNCTION(mysqli_get_links_stats); PHP_FUNCTION(mysqli_get_proto_info); PHP_FUNCTION(mysqli_get_server_info); PHP_FUNCTION(mysqli_get_server_version); diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index db0352baeb..312f2806ce 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -1207,6 +1207,23 @@ PHP_FUNCTION(mysqli_release_savepoint) /* }}} */ +/* {{{ proto bool mysqli_get_links_stats() + Returns information about open and cached links */ +PHP_FUNCTION(mysqli_get_links_stats) +{ + if (ZEND_NUM_ARGS()) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "no parameters expected"); + return; + } + array_init(return_value); + add_assoc_long_ex(return_value, "total", sizeof("total"), MyG(num_links)); + add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks"), MyG(num_active_persistent)); + add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks"), MyG(num_inactive_persistent)); +} +/* }}} */ + + + /* * Local variables: * tab-width: 4 diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h index e7c02f9c9b..cc0c8fe63f 100644 --- a/ext/mysqli/php_mysqli_structs.h +++ b/ext/mysqli/php_mysqli_structs.h @@ -334,6 +334,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqli) HashTable *report_ht; unsigned long multi_query; unsigned long embedded; + zend_bool rollback_on_cached_plink; ZEND_END_MODULE_GLOBALS(mysqli) diff --git a/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt b/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt index 988b82732a..95400e43e0 100644 --- a/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt +++ b/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt @@ -233,7 +233,7 @@ isDestructor: no isInternal: yes isUserDefined: no returnsReference: no -Modifiers: 256 +Modifiers: 268435712 Number of Parameters: 2 Number of Required Parameters: 0 @@ -366,4 +366,4 @@ Default property 'field_count' Default property 'lengths' Default property 'num_rows' Default property 'type' -done!
\ No newline at end of file +done! diff --git a/ext/mysqli/tests/mysqli_pconn_max_links.phpt b/ext/mysqli/tests/mysqli_pconn_max_links.phpt index e87ef00b21..99e51e7c5e 100644 --- a/ext/mysqli/tests/mysqli_pconn_max_links.phpt +++ b/ext/mysqli/tests/mysqli_pconn_max_links.phpt @@ -42,6 +42,7 @@ Persistent connections and mysqli.max_links --INI-- mysqli.allow_persistent=1 mysqli.max_persistent=2 +mysqli.rollback_on_cached_plink=1 --FILE-- <?php require_once("connect.inc"); @@ -58,10 +59,18 @@ mysqli.max_persistent=2 mysqli_errno($plink), mysqli_error($plink)); } + var_dump(mysqli_get_links_stats(1)); + + echo "Before pconnect:"; + var_dump(mysqli_get_links_stats()); + if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket)) printf("[001] Cannot connect using the second DB user created during SKIPIF, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()); + echo "After pconnect:"; + var_dump(mysqli_get_links_stats()); + ob_start(); phpinfo(); $phpinfo = strip_tags(ob_get_contents()); @@ -110,11 +119,17 @@ mysqli.max_persistent=2 if (isset($running_threads[$pthread_id])) printf("[009] Persistent connection has not been killed\n"); + echo "Before second pconnect:"; + var_dump(mysqli_get_links_stats()); + // this fails and we have 0 (<= $num_plinks) connections if ($plink = @my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket)) printf("[010] Can connect using the old password, [%d] %s\n", mysqli_connect_errno($link), mysqli_connect_error($link)); + echo "After second pconnect:"; + var_dump(mysqli_get_links_stats()); + ob_start(); phpinfo(); $phpinfo = strip_tags(ob_get_contents()); @@ -123,7 +138,13 @@ mysqli.max_persistent=2 if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches)) printf("[010] Cannot get # of active persistent links from phpinfo()\n"); + var_dump(mysqli_get_links_stats()); + $num_plinks_kill = $matches[1]; + $sstats = mysqli_get_links_stats(); + if ($sstats['active_plinks'] != $num_plinks_kill) { + printf("[010.2] Num of active plinks differ %s %s\n", $sstats['active_plinks'], $num_plinks_kill); + } if ($num_plinks_kill > $num_plinks) printf("[011] Expecting Active Persistent Links < %d, got %d\n", $num_plinks, $num_plinks_kill); @@ -141,9 +162,11 @@ mysqli.max_persistent=2 mysqli_free_result($res); var_dump($row); - if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket)) + if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket)) { printf("[015] Can open more persistent connections than allowed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()); + var_dump(mysqli_get_links_stats()); + } ob_start(); phpinfo(); @@ -179,18 +202,71 @@ mysqli_query($link, 'DROP USER pcontest'); mysqli_close($link); ?> --EXPECTF-- -array(2) { - [%u|b%"id"]=> - %unicode|string%(1) "1" - [%u|b%"label"]=> - %unicode|string%(1) "a" +Warning: mysqli_get_links_stats(): no parameters expected in %s on line %d +NULL +Before pconnect:array(3) { + ["total"]=> + int(1) + ["active_plinks"]=> + int(0) + ["cached_plinks"]=> + int(0) +} +After pconnect:array(3) { + ["total"]=> + int(2) + ["active_plinks"]=> + int(1) + ["cached_plinks"]=> + int(0) } array(2) { - [%u|b%"id"]=> - %unicode|string%(1) "1" - [%u|b%"label"]=> - %unicode|string%(1) "a" + ["id"]=> + string(1) "1" + ["label"]=> + string(1) "a" +} +Before second pconnect:array(3) { + ["total"]=> + int(2) + ["active_plinks"]=> + int(1) + ["cached_plinks"]=> + int(0) } -Warning: %s: Too many open persistent links (%d) in %s on line %d +Warning: main(): MySQL server has gone away in %s on line %d + +Warning: main(): Error reading result set's header in %s line %d +After second pconnect:array(3) { + ["total"]=> + int(1) + ["active_plinks"]=> + int(0) + ["cached_plinks"]=> + int(0) +} +array(3) { + ["total"]=> + int(1) + ["active_plinks"]=> + int(0) + ["cached_plinks"]=> + int(0) +} +array(2) { + ["id"]=> + string(1) "1" + ["label"]=> + string(1) "a" +} +[015] Can open more persistent connections than allowed, [0] +array(3) { + ["total"]=> + int(3) + ["active_plinks"]=> + int(2) + ["cached_plinks"]=> + int(0) +} done!
\ No newline at end of file diff --git a/ext/mysqlnd/CREDITS b/ext/mysqlnd/CREDITS index 5a7d69d665..08ebb21aa7 100644 --- a/ext/mysqlnd/CREDITS +++ b/ext/mysqlnd/CREDITS @@ -1,2 +1,2 @@ MySQLnd -Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlüter +Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlüter diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index 3d65001382..60ce28dbf2 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -561,6 +561,10 @@ enum mysqlnd_packet_type }; +/* + After adding new elements please update + `mysqlnd_command_to_text` in mysqlnd_wireprotocol.c +*/ enum php_mysqlnd_server_command { COM_SLEEP = 0, @@ -593,6 +597,8 @@ enum php_mysqlnd_server_command COM_SET_OPTION = 27, COM_STMT_FETCH = 28, COM_DAEMON, + COM_BINLOG_DUMP_GTID, + COM_RESET_CONNECTION, COM_END }; diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 8096cbbbd9..2d270c9b2f 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -38,6 +38,7 @@ const char * const mysqlnd_stmt_not_prepared = "Statement not prepared"; /* Exported by mysqlnd_ps_codec.c */ enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); +enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index d0e44fa275..d96a57721c 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -516,68 +516,70 @@ mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count, /* }}} */ -/* {{{ mysqlnd_stmt_execute_store_params */ -static enum_func_status -mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) +/* {{{ mysqlnd_stmt_free_copies */ +static void +mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC) { - MYSQLND_STMT_DATA * stmt = s->data; - unsigned int i = 0; - zend_uchar * provided_buffer = *buf; - size_t left = (*buf_len - (*p - *buf)); - size_t data_size = 0; - zval **copies = NULL;/* if there are different types */ - enum_func_status ret = FAIL; - int resend_types_next_time = 0; - size_t null_byte_offset; + if (copies) { + unsigned int i; + for (i = 0; i < stmt->param_count; i++) { + if (copies[i]) { + zval_ptr_dtor(&copies[i]); + } + } + mnd_efree(copies); + } +} +/* }}} */ - DBG_ENTER("mysqlnd_stmt_execute_store_params"); - { - unsigned int null_count = (stmt->param_count + 7) / 8; - /* give it some reserved space - 20 bytes */ - if (left < (null_count + 20)) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + null_count + 20; - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; +/* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */ +static enum_func_status +mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, size_t * buf_len, zend_uchar * const provided_buffer, size_t needed_bytes TSRMLS_DC) +{ + const size_t overalloc = 5; + size_t left = (*buf_len - (*p - *buf)); - /* Update our pos pointer */ - *p = *buf + offset; + if (left < (needed_bytes + overalloc)) { + size_t offset = *p - *buf; + zend_uchar *tmp_buf; + *buf_len = offset + needed_bytes + overalloc; + tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + return FAIL; } - /* put `null` bytes */ - null_byte_offset = *p - *buf; - memset(*p, 0, null_count); - *p += null_count; + memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } + *buf = tmp_buf; + /* Update our pos pointer */ + *p = *buf + offset; } + return PASS; +} +/* }}} */ - left = (*buf_len - (*p - *buf)); -/* 1. Store type information */ - /* - check if need to send the types even if stmt->send_types_to_server is 0. This is because - if we send "i" (42) then the type will be int and the server will expect int. However, if next - time we try to send > LONG_MAX, the conversion to string will send a string and the server - won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values - occur, and force resend for the next execution. - */ + +/* {{{ mysqlnd_stmt_execute_prepare_param_types */ +static enum_func_status +mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval *** copies_param, int * resend_types_next_time TSRMLS_DC) +{ + unsigned int i; + DBG_ENTER("mysqlnd_stmt_execute_prepare_param_types"); for (i = 0; i < stmt->param_count; i++) { short current_type = stmt->param_bind[i].type; + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + zval ** copies; /* always copy the var, because we do many conversions */ if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG && - PASS != mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) + PASS != mysqlnd_stmt_copy_it(copies_param, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } + copies = *copies_param; /* if it doesn't fit in a long send it as a string. Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX @@ -602,7 +604,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar We do transformation here, which will be used later when sending types. The code later relies on this. */ if (Z_DVAL_P(tmp_data_copy) > LONG_MAX || Z_DVAL_P(tmp_data_copy) < LONG_MIN) { - stmt->send_types_to_server = resend_types_next_time = 1; + stmt->send_types_to_server = *resend_types_next_time = 1; convert_to_string_ex(&tmp_data); } else { convert_to_long_ex(&tmp_data); @@ -612,69 +614,63 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } } } + DBG_RETURN(PASS); +end: + DBG_RETURN(FAIL); +} +/* }}} */ - int1store(*p, stmt->send_types_to_server); - (*p)++; - - if (stmt->send_types_to_server) { - /* 2 bytes per type, and leave 20 bytes for future use */ - if (left < ((stmt->param_count * 2) + 20)) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + stmt->param_count * 2 + 20; - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; - /* Update our pos pointer */ - *p = *buf + offset; - } - for (i = 0; i < stmt->param_count; i++) { - short current_type = stmt->param_bind[i].type; - /* our types are not unsigned */ +/* {{{ mysqlnd_stmt_execute_store_types */ +static void +mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar ** p) +{ + unsigned int i; + for (i = 0; i < stmt->param_count; i++) { + short current_type = stmt->param_bind[i].type; + /* our types are not unsigned */ #if SIZEOF_LONG==8 - if (current_type == MYSQL_TYPE_LONG) { - current_type = MYSQL_TYPE_LONGLONG; - } + if (current_type == MYSQL_TYPE_LONG) { + current_type = MYSQL_TYPE_LONGLONG; + } #endif - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + /* + if it doesn't fit in a long send it as a string. + Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + */ + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { + const zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; /* - if it doesn't fit in a long send it as a string. - Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type. + The actual transformation has been performed several dozens line above. */ - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + if (Z_TYPE_P(tmp_data) == IS_STRING) { + current_type = MYSQL_TYPE_VAR_STRING; /* - In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type. - The actual transformation has been performed several dozens line above. + don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING + we force convert_to_long_ex in all cases, thus the type will be right in the next switch. + if the type is however not long, then we will do a goto in the next switch. + We want to preserve the original bind type given by the user. Thus, we do these hacks. */ - if (Z_TYPE_P(tmp_data) == IS_STRING) { - current_type = MYSQL_TYPE_VAR_STRING; - /* - don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING - we force convert_to_long_ex in all cases, thus the type will be right in the next switch. - if the type is however not long, then we will do a goto in the next switch. - We want to preserve the original bind type given by the user. Thus, we do these hacks. - */ - } } } - int2store(*p, current_type); - *p+= 2; } + int2store(*p, current_type); + *p+= 2; } - stmt->send_types_to_server = resend_types_next_time; +} +/* }}} */ -/* 2. Store data */ - /* 2.1 Calculate how much space we need */ + +/* {{{ mysqlnd_stmt_execute_calculate_param_values_size */ +static enum_func_status +mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval *** copies_param, size_t * data_size TSRMLS_DC) +{ + unsigned int i; + DBG_ENTER("mysqlnd_stmt_execute_calculate_param_values_size"); for (i = 0; i < stmt->param_count; i++) { + unsigned short is_longlong = 0; unsigned int j; zval *the_var = stmt->param_bind[i].zv; @@ -684,22 +680,22 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar for (j = i + 1; j < stmt->param_count; j++) { if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } } - break; + break; } } switch (stmt->param_bind[i].type) { case MYSQL_TYPE_DOUBLE: - data_size += 8; + *data_size += 8; if (Z_TYPE_P(the_var) != IS_DOUBLE) { - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } @@ -707,24 +703,17 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } break; case MYSQL_TYPE_LONGLONG: - { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; - if (Z_TYPE_P(tmp_data) == IS_STRING) { - goto use_string; - } - convert_to_long_ex(&tmp_data); - } - data_size += 8; - break; + is_longlong = 4; + /* fall-through */ case MYSQL_TYPE_LONG: { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + zval *tmp_data = (*copies_param && (*copies_param)[i])? (*copies_param)[i]: stmt->param_bind[i].zv; if (Z_TYPE_P(tmp_data) == IS_STRING) { goto use_string; } convert_to_long_ex(&tmp_data); } - data_size += 4; + *data_size += 4 + is_longlong; break; case MYSQL_TYPE_LONG_BLOB: if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) { @@ -733,58 +722,43 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar Empty string has length of 0, encoded in 1 byte. No real data will follows after it. */ - data_size++; + (*data_size)++; } break; case MYSQL_TYPE_VAR_STRING: use_string: - data_size += 8; /* max 8 bytes for size */ + *data_size += 8; /* max 8 bytes for size */ if (Z_TYPE_P(the_var) != IS_STRING) { - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } } - the_var = copies[i]; + the_var = (*copies_param)[i]; } convert_to_string_ex(&the_var); - data_size += Z_STRLEN_P(the_var); + *data_size += Z_STRLEN_P(the_var); break; } } + DBG_RETURN(PASS); +end: + DBG_RETURN(FAIL); +} +/* }}} */ - /* 2.2 Enlarge the buffer, if needed */ - left = (*buf_len - (*p - *buf)); - if (left < data_size) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */ - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - /* - When too many columns the buffer provided to the function might not be sufficient. - In this case new buffer has been allocated above. When we allocate a buffer and then - allocate a bigger one here, we should free the first one. - */ - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; - /* Update our pos pointer */ - *p = *buf + offset; - } - /* 2.3 Store the actual data */ +/* {{{ mysqlnd_stmt_execute_store_param_values */ +static void +mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset) +{ + unsigned int i; for (i = 0; i < stmt->param_count; i++) { - zval *data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + zval * data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; /* Handle long data */ if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) { - (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); + (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); } else { switch (stmt->param_bind[i].type) { case MYSQL_TYPE_DOUBLE: @@ -819,7 +793,7 @@ use_string: case MYSQL_TYPE_VAR_STRING: send_string: { - unsigned int len = Z_STRLEN_P(data); + size_t len = Z_STRLEN_P(data); /* to is after p. The latter hasn't been moved */ *p = php_mysqlnd_net_store_length(*p, len); memcpy(*p, Z_STRVAL_P(data), len); @@ -828,22 +802,86 @@ send_string: break; default: /* Won't happen, but set to NULL */ - (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); + (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); break; } } } - ret = PASS; -end: - if (copies) { - for (i = 0; i < stmt->param_count; i++) { - if (copies[i]) { - zval_ptr_dtor(&copies[i]); - } +} +/* }}} */ + + +/* {{{ mysqlnd_stmt_execute_store_params */ +static enum_func_status +mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) +{ + MYSQLND_STMT_DATA * stmt = s->data; + unsigned int i = 0; + zend_uchar * provided_buffer = *buf; + size_t data_size = 0; + zval **copies = NULL;/* if there are different types */ + enum_func_status ret = FAIL; + int resend_types_next_time = 0; + size_t null_byte_offset; + + DBG_ENTER("mysqlnd_stmt_execute_store_params"); + + { + unsigned int null_count = (stmt->param_count + 7) / 8; + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; } - mnd_efree(copies); + /* put `null` bytes */ + null_byte_offset = *p - *buf; + memset(*p, 0, null_count); + *p += null_count; + } + +/* 1. Store type information */ + /* + check if need to send the types even if stmt->send_types_to_server is 0. This is because + if we send "i" (42) then the type will be int and the server will expect int. However, if next + time we try to send > LONG_MAX, the conversion to string will send a string and the server + won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values + occur, and force resend for the next execution. + */ + if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time TSRMLS_CC)) { + goto end; + } + + int1store(*p, stmt->send_types_to_server); + (*p)++; + + if (stmt->send_types_to_server) { + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2 TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; + } + mysqlnd_stmt_execute_store_types(stmt, copies, p); + } + + stmt->send_types_to_server = resend_types_next_time; + +/* 2. Store data */ + /* 2.1 Calculate how much space we need */ + if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size TSRMLS_CC)) { + goto end; + } + + /* 2.2 Enlarge the buffer, if needed */ + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; } + /* 2.3 Store the actual data */ + mysqlnd_stmt_execute_store_param_values(stmt, copies, *buf, p, null_byte_offset); + + ret = PASS; +end: + mysqlnd_stmt_free_copies(stmt, copies TSRMLS_CC); + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); DBG_RETURN(ret); } diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 74019b55bf..fbf8ea031c 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -187,9 +187,11 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC) if (set->data) { unsigned int copy_on_write_performed = 0; unsigned int copy_on_write_saved = 0; + zval **data = set->data; + set->data = NULL; /* prevent double free if following loop is interrupted */ for (row = set->row_count - 1; row >= 0; row--) { - zval **current_row = set->data + row * field_count; + zval **current_row = data + row * field_count; MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row]; int64_t col; @@ -211,8 +213,7 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC) MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_COPY_ON_WRITE_PERFORMED, copy_on_write_performed, STAT_COPY_ON_WRITE_SAVED, copy_on_write_saved); - mnd_efree(set->data); - set->data = NULL; + mnd_efree(data); } if (set->row_buffers) { diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index d78d29a2f1..df9dde592a 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -90,7 +90,8 @@ const char * const mysqlnd_command_to_text[COM_END] = "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP", "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE", "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE", - "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON" + "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID", + "RESET_CONNECTION" }; /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index 4bd33592bf..be71d06508 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -302,6 +302,7 @@ PHPAPI void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * c unsigned long php_mysqlnd_net_field_length(zend_uchar **packet); zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length); +size_t php_mysqlnd_net_store_length_size(uint64_t length); PHPAPI const extern char * const mysqlnd_empty_string; diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 835c9ee716..a6114733e3 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1057,6 +1057,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, /* BOOL */ result = ZEND_OP1_LITERAL(opline); convert_to_boolean(&result); + Z_TYPE(ZEND_OP1_LITERAL(opline)) = IS_NULL; } PZ_SET_REFCOUNT_P(&result, 1); PZ_UNSET_ISREF_P(&result); @@ -1908,7 +1909,9 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * if (RESULT_USED(opline)) { if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] && (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT || +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO opline->opcode == ZEND_RECV_VARIADIC || +#endif (opline->opcode == ZEND_OP_DATA && ZEND_RESULT_TYPE(opline) == IS_TMP_VAR) || opline->opcode == ZEND_ADD_ARRAY_ELEMENT)) { /* these opcodes use the result as argument */ @@ -1993,7 +1996,9 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * if (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT || +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO opline->opcode == ZEND_RECV_VARIADIC || +#endif opline->opcode == ZEND_ADD_ARRAY_ELEMENT) { if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) { usage[VAR_NUM(ZEND_RESULT(opline).var)] = 1; diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 98bfc1e99e..14f8255653 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -126,7 +126,12 @@ static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script call_stack[call - 1].opline = NULL; } break; - +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO + case ZEND_SEND_UNPACK: + call_stack[call - 1].func = NULL; + call_stack[call - 1].opline = NULL; + break; +#endif default: break; } diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 8f76c63d96..577d1b6609 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -433,7 +433,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { zval t; if (zend_get_persistent_constant(Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), - Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)), &t, 0 TSRMLS_CC)) { + Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)), &t, 1 TSRMLS_CC)) { if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); MAKE_NOP((opline - 1)); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index db37a301a5..d1c9dfcd35 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -36,7 +36,11 @@ #include "main/php_open_temporary_file.h" #include "zend_API.h" #include "zend_ini.h" -#include "zend_virtual_cwd.h" +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO +# include "zend_virtual_cwd.h" +#else +# include "TSRM/tsrm_virtual_cwd.h" +#endif #include "zend_accelerator_util_funcs.h" #include "zend_accelerator_hash.h" @@ -387,8 +391,10 @@ static void accel_use_shm_interned_strings(TSRMLS_D) { Bucket *p, *q; +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO /* empty string */ CG(interned_empty_string) = accel_new_interned_string("", sizeof(""), 0 TSRMLS_CC); +#endif /* function table hash keys */ p = CG(function_table)->pListHead; @@ -1115,7 +1121,9 @@ static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_ha char *new_key = zend_shared_alloc(key_length + 1); if (new_key) { memcpy(new_key, key, key_length + 1); - zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket); + if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket)) { + zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key); + } } else { zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); } @@ -1203,16 +1211,21 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr /* store script structure in the hash table */ bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1, 0, new_persistent_script); - if (bucket && !ZCG(accel_directives).revalidate_path && - /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */ - memcmp(key, "phar://", sizeof("phar://") - 1) != 0 && - (new_persistent_script->full_path_len != key_length || - memcmp(new_persistent_script->full_path, key, key_length) != 0)) { - /* link key to the same persistent script in hash table */ - if (!zend_accel_hash_update(&ZCSG(hash), key, key_length + 1, 1, bucket)) { - zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); - ZSMMG(memory_exhausted) = 1; - zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); + if (bucket) { + zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", new_persistent_script->full_path); + if (!ZCG(accel_directives).revalidate_path && + /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */ + memcmp(key, "phar://", sizeof("phar://") - 1) != 0 && + (new_persistent_script->full_path_len != key_length || + memcmp(new_persistent_script->full_path, key, key_length) != 0)) { + /* link key to the same persistent script in hash table */ + if (zend_accel_hash_update(&ZCSG(hash), key, key_length + 1, 1, bucket)) { + zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key); + } else { + zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); + ZSMMG(memory_exhausted) = 1; + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); + } } } @@ -2135,7 +2148,9 @@ static void accel_activate(void) } #if (ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO) && !defined(ZTS) - accel_interned_strings_restore_state(TSRMLS_C); + if (ZCG(accel_directives).interned_strings_buffer) { + accel_interned_strings_restore_state(TSRMLS_C); + } #endif zend_shared_alloc_restore_state(); @@ -2453,36 +2468,39 @@ static int zend_accel_init_shm(TSRMLS_D) #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL; # ifndef ZTS zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1); - ZCSG(interned_strings).nTableMask = ZCSG(interned_strings).nTableSize - 1; - ZCSG(interned_strings).arBuckets = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *)); - ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024)); - if (!ZCSG(interned_strings).arBuckets || !ZCSG(interned_strings_start)) { - zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings"); - return FAILURE; + if (ZCG(accel_directives).interned_strings_buffer) { + ZCSG(interned_strings).nTableMask = ZCSG(interned_strings).nTableSize - 1; + ZCSG(interned_strings).arBuckets = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *)); + ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024)); + if (!ZCSG(interned_strings).arBuckets || !ZCSG(interned_strings_start)) { + zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings"); + return FAILURE; + } + ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024); + ZCSG(interned_strings_top) = ZCSG(interned_strings_start); + + orig_interned_strings_start = CG(interned_strings_start); + orig_interned_strings_end = CG(interned_strings_end); + CG(interned_strings_start) = ZCSG(interned_strings_start); + CG(interned_strings_end) = ZCSG(interned_strings_end); } - ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024); - ZCSG(interned_strings_top) = ZCSG(interned_strings_start); -# else - ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL; # endif - orig_interned_strings_start = CG(interned_strings_start); - orig_interned_strings_end = CG(interned_strings_end); orig_new_interned_string = zend_new_interned_string; orig_interned_strings_snapshot = zend_interned_strings_snapshot; orig_interned_strings_restore = zend_interned_strings_restore; - - CG(interned_strings_start) = ZCSG(interned_strings_start); - CG(interned_strings_end) = ZCSG(interned_strings_end); zend_new_interned_string = accel_new_interned_string_for_php; zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php; zend_interned_strings_restore = accel_interned_strings_restore_for_php; # ifndef ZTS - accel_use_shm_interned_strings(TSRMLS_C); - accel_interned_strings_save_state(TSRMLS_C); + if (ZCG(accel_directives).interned_strings_buffer) { + accel_use_shm_interned_strings(TSRMLS_C); + accel_interned_strings_save_state(TSRMLS_C); + } # endif #endif @@ -2711,27 +2729,28 @@ void accel_shutdown(TSRMLS_D) return; } - accel_free_ts_resources(); - zend_shared_alloc_shutdown(); - zend_compile_file = accelerator_orig_compile_file; - - if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) { - ini_entry->on_modify = orig_include_path_on_modify; - } - #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + if (ZCG(accel_directives).interned_strings_buffer) { # ifndef ZTS - zend_hash_clean(CG(function_table)); - zend_hash_clean(CG(class_table)); - zend_hash_clean(EG(zend_constants)); + zend_hash_clean(CG(function_table)); + zend_hash_clean(CG(class_table)); + zend_hash_clean(EG(zend_constants)); # endif - CG(interned_strings_start) = orig_interned_strings_start; - CG(interned_strings_end) = orig_interned_strings_end; + CG(interned_strings_start) = orig_interned_strings_start; + CG(interned_strings_end) = orig_interned_strings_end; + } zend_new_interned_string = orig_new_interned_string; zend_interned_strings_snapshot = orig_interned_strings_snapshot; zend_interned_strings_restore = orig_interned_strings_restore; #endif + accel_free_ts_resources(); + zend_shared_alloc_shutdown(); + zend_compile_file = accelerator_orig_compile_file; + + if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) { + ini_entry->on_modify = orig_include_path_on_modify; + } } void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC) diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 169a751dc3..56e6cd508d 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -27,7 +27,7 @@ #endif #define ACCELERATOR_PRODUCT_NAME "Zend OPcache" -#define ACCELERATOR_VERSION "7.0.3-dev" +#define ACCELERATOR_VERSION "7.0.3" /* 2 - added Profiler support, on 20010712 */ /* 3 - added support for Optimizer's encoded-only-files mode */ /* 4 - works with the new Optimizer, that supports the file format with licenses */ diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 60edeed966..f6e6ca9444 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -362,7 +362,7 @@ AC_TRY_RUN([ if test "$flock_type" == "unknown"; then AC_MSG_ERROR([Don't know how to define struct flock on this system[,] set --enable-opcache=no]) fi - + PHP_NEW_EXTENSION(opcache, ZendAccelerator.c \ zend_accelerator_blacklist.c \ diff --git a/ext/opcache/tests/blacklist-win32.phpt b/ext/opcache/tests/blacklist-win32.phpt new file mode 100644 index 0000000000..909c695fcd --- /dev/null +++ b/ext/opcache/tests/blacklist-win32.phpt @@ -0,0 +1,34 @@ +--TEST-- +Blacklist (with glob, quote and comments) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.blacklist_filename={PWD}/opcache-*.blacklist +opcache.file_update_protection=0 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +<?php if (substr(PHP_OS, 0, 3) != 'WIN') { die('skip only for Windows'); } ?> +--FILE-- +<?php +$conf = opcache_get_configuration(); +$conf = $conf['blacklist']; +$conf[3] = preg_replace("!^\\Q".dirname(__FILE__)."\\E!", "__DIR__", $conf[3]); +$conf[4] = preg_replace("!^\\Q".dirname(__FILE__)."\\E!", "__DIR__", $conf[4]); +print_r($conf); +include("blacklist.inc"); +$status = opcache_get_status(); +print_r(count($status['scripts'])); +?> +--EXPECTF-- +Array +( + [0] => C:\path\to\foo + [1] => C:\path\to\foo2 + [2] => C:\path\to\bar + [3] => __DIR__\blacklist.inc + [4] => __DIR__\current.php + [5] => %scurrent.php + [6] => %scurrent.php +) +ok +1 diff --git a/ext/opcache/tests/blacklist.phpt b/ext/opcache/tests/blacklist.phpt index 18c205cacf..0c60425dac 100644 --- a/ext/opcache/tests/blacklist.phpt +++ b/ext/opcache/tests/blacklist.phpt @@ -7,6 +7,7 @@ opcache.blacklist_filename={PWD}/opcache-*.blacklist opcache.file_update_protection=0 --SKIPIF-- <?php require_once('skipif.inc'); ?> +<?php if (substr(PHP_OS, 0, 3) == 'WIN') { die('skip not for Windows'); } ?> --FILE-- <?php $conf = opcache_get_configuration(); diff --git a/ext/opcache/tests/bug66440.phpt b/ext/opcache/tests/bug66440.phpt new file mode 100644 index 0000000000..b546e32b3c --- /dev/null +++ b/ext/opcache/tests/bug66440.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #66440 (Optimisation of conditional JMPs based on pre-evaluate constant function calls) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +if(constant('PHP_BINARY')) { + echo "OK\n"; +} +--EXPECT-- +OK diff --git a/ext/opcache/tests/bug66461.phpt b/ext/opcache/tests/bug66461.phpt new file mode 100644 index 0000000000..33132abeed --- /dev/null +++ b/ext/opcache/tests/bug66461.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #66461 (PHP crashes if opcache.interned_strings_buffer=0) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +opcache.interned_strings_buffer=0 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +echo "ok\n"; +--EXPECT-- +ok diff --git a/ext/opcache/tests/bug66474.phpt b/ext/opcache/tests/bug66474.phpt new file mode 100644 index 0000000000..3bd038c0de --- /dev/null +++ b/ext/opcache/tests/bug66474.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #66474 (Optimizer bug in constant string to boolean conversion) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +function foo() { + $speed = 'slow' || 'fast'; +} +foo(); +echo "ok\n"; +--EXPECT-- +ok diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 01d350f128..b98623e1f2 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -28,7 +28,11 @@ #include "zend_accelerator_blacklist.h" #include "php_ini.h" #include "SAPI.h" -#include "zend_virtual_cwd.h" +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO +# include "zend_virtual_cwd.h" +#else +# include "TSRM/tsrm_virtual_cwd.h" +#endif #include "ext/standard/info.h" #include "ext/standard/php_filestat.h" diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index e0b9074c64..c899ec8ac9 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -33,11 +33,13 @@ #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO # define ADD_INTERNED_STRING(str, len) do { \ - const char *tmp = accel_new_interned_string((str), (len), !IS_INTERNED((str)) TSRMLS_CC); \ - if (tmp != (str)) { \ - (str) = (char*)tmp; \ - } else { \ - ADD_DUP_SIZE((str), (len)); \ + if (!IS_INTERNED(str)) { \ + const char *tmp = accel_new_interned_string((str), (len), 1 TSRMLS_CC); \ + if (tmp != (str)) { \ + (str) = (char*)tmp; \ + } else { \ + ADD_DUP_SIZE((str), (len)); \ + } \ } \ } while (0) #else diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index fd4b22076a..d57b3eafde 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -27,7 +27,9 @@ #endif #include "php.h" +#include "php_ini.h" #include "php_openssl.h" +#include "php_openssl_structs.h" /* PHP Includes */ #include "ext/standard/file.h" @@ -1071,6 +1073,13 @@ static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* { } /* }}} */ +/* {{{ INI Settings */ +PHP_INI_BEGIN() + PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_ALL, NULL) + PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_ALL, NULL) +PHP_INI_END() +/* }}} */ + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(openssl) @@ -1203,7 +1212,9 @@ PHP_MINIT_FUNCTION(openssl) php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC); php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC); - + + REGISTER_INI_ENTRIES(); + return SUCCESS; } /* }}} */ @@ -1217,6 +1228,7 @@ PHP_MINFO_FUNCTION(openssl) php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION)); php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT); php_info_print_table_end(); + DISPLAY_INI_ENTRIES(); } /* }}} */ @@ -1243,6 +1255,8 @@ PHP_MSHUTDOWN_FUNCTION(openssl) /* reinstate the default tcp handler */ php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC); + UNREGISTER_INI_ENTRIES(); + return SUCCESS; } /* }}} */ @@ -4999,9 +5013,9 @@ static zend_bool matches_wildcard_name(const char *subjectname, const char *cert return 0; } -static zend_bool matches_san_list(X509 *peer, const char *subject_name) +static zend_bool matches_san_list(X509 *peer, const char *subject_name TSRMLS_DC) { - int i; + int i, san_name_len; zend_bool is_match = 0; unsigned char *cert_name; @@ -5010,13 +5024,23 @@ static zend_bool matches_san_list(X509 *peer, const char *subject_name) for (i = 0; i < alt_name_count; i++) { GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i); + if (san->type != GEN_DNS) { + /* we only care about DNS names */ + continue; + } + + san_name_len = ASN1_STRING_length(san->d.dNSName); + ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); - if (GEN_DNS == san->type) { - ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); - is_match = matches_wildcard_name(subject_name, (char *) cert_name); - OPENSSL_free(cert_name); + /* prevent null byte poisoning */ + if (san_name_len != strlen(cert_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer SAN entry is malformed"); + } else { + is_match = strcasecmp(subject_name, cert_name) == 0; } + OPENSSL_free(cert_name); + if (is_match) { break; } @@ -5053,9 +5077,13 @@ int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stre zval **val = NULL; char *cnmatch = NULL; int err; + php_openssl_netstream_data_t *sslsock; + + sslsock = (php_openssl_netstream_data_t*)stream->abstract; - /* verification is turned off */ - if (!(GET_VER_OPT("verify_peer") && zval_is_true(*val))) { + if (!(GET_VER_OPT("verify_peer") || sslsock->is_client) + || (GET_VER_OPT("verify_peer") && !zval_is_true(*val)) + ) { return SUCCESS; } @@ -5095,8 +5123,13 @@ int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stre GET_VER_OPT_STRING("CN_match", cnmatch); + /* If no CN_match was specified assign the autodetected name when connecting as a client */ + if (cnmatch == NULL && sslsock->is_client) { + cnmatch = sslsock->url_name; + } + if (cnmatch) { - if (matches_san_list(peer, cnmatch)) { + if (matches_san_list(peer, cnmatch TSRMLS_CC)) { return SUCCESS; } else if (matches_common_name(peer, cnmatch TSRMLS_CC)) { return SUCCESS; @@ -5140,7 +5173,9 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ ERR_clear_error(); /* look at context options in the stream and set appropriate verification flags */ - if (GET_VER_OPT("verify_peer") && zval_is_true(*val)) { + if (GET_VER_OPT("verify_peer") && !zval_is_true(*val)) { + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } else { /* turn on verification callback */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback); @@ -5149,19 +5184,35 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ GET_VER_OPT_STRING("cafile", cafile); GET_VER_OPT_STRING("capath", capath); + if (!cafile) { + zend_bool exists = 1; + cafile = zend_ini_string_ex("openssl.cafile", sizeof("openssl.cafile"), 0, &exists); + } + + if (!capath) { + zend_bool exists = 1; + capath = zend_ini_string_ex("openssl.capath", sizeof("openssl.capath"), 0, &exists); + } + if (cafile || capath) { if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set verify locations `%s' `%s'", cafile, capath); return NULL; } + } else { + php_openssl_netstream_data_t *sslsock; + sslsock = (php_openssl_netstream_data_t*)stream->abstract; + if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "Unable to set default verify locations and no CA settings specified"); + return NULL; + } } if (GET_VER_OPT("verify_depth")) { convert_to_long_ex(val); SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val)); } - } else { - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); } /* callback for the passphrase (for localcert) */ @@ -5227,6 +5278,7 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ } } } + if (ok) { SSL *ssl = SSL_new(ctx); @@ -5655,3 +5707,4 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */ + diff --git a/ext/openssl/php_openssl_structs.h b/ext/openssl/php_openssl_structs.h new file mode 100644 index 0000000000..13f8f320f8 --- /dev/null +++ b/ext/openssl/php_openssl_structs.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Wez Furlong <wez@thebrainroom.com> | + | Daniel Lowrey <rdlowrey@gmail.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php_network.h" +#include <openssl/ssl.h> + +/* This implementation is very closely tied to the that of the native + * sockets implemented in the core. + * Don't try this technique in other extensions! + * */ + +typedef struct _php_openssl_netstream_data_t { + php_netstream_data_t s; + SSL *ssl_handle; + SSL_CTX *ctx; + struct timeval connect_timeout; + int enable_on_connect; + int is_client; + int ssl_active; + php_stream_xport_crypt_method_t method; + char *url_name; + unsigned state_set:1; + unsigned _spare:31; +} php_openssl_netstream_data_t; diff --git a/ext/openssl/tests/bug46127.phpt b/ext/openssl/tests/bug46127.phpt index a3bfd3a012..1de4eacd01 100644 --- a/ext/openssl/tests/bug46127.phpt +++ b/ext/openssl/tests/bug46127.phpt @@ -45,7 +45,10 @@ if ($pid == 0) { // child // client or failed sleep(1); -$sock = fsockopen('ssl://127.0.0.1', $port, $errno, $errstr); +$ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false +]]); +$sock = stream_socket_client("ssl://127.0.0.1:{$port}", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $ctx); if (!$sock) exit; echo fgets($sock); diff --git a/ext/openssl/tests/bug48182.phpt b/ext/openssl/tests/bug48182.phpt index 146c4c9226..b78ce57074 100644 --- a/ext/openssl/tests/bug48182.phpt +++ b/ext/openssl/tests/bug48182.phpt @@ -13,8 +13,7 @@ function ssl_server($port) { $host = 'ssl://127.0.0.1'.':'.$port; $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $data = "Sending bug48182\n"; - - $pem = dirname(__FILE__) . '/bug46127.pem'; + $pem = dirname(__FILE__) . '/bug54992.pem'; $ssl_params = array( 'verify_peer' => false, 'allow_self_signed' => true, 'local_cert' => $pem); $ssl = array('ssl' => $ssl_params); @@ -47,8 +46,11 @@ function ssl_async_client($port) { $host = 'ssl://127.0.0.1'.':'.$port; $flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT; $data = "Sending data over to SSL server in async mode with contents like Hello World\n"; - - $socket = stream_socket_client($host, $errno, $errstr, 10, $flags); + $context = stream_context_create(array('ssl' => array( + 'cafile' => dirname(__FILE__) . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local' + ))); + $socket = stream_socket_client($host, $errno, $errstr, 10, $flags, $context); stream_set_blocking($socket, 0); while ($socket && $data) { diff --git a/ext/openssl/tests/openssl_peer_fingerprint.phpt b/ext/openssl/tests/openssl_peer_fingerprint.phpt index 2960dffae5..2e4c192c03 100644 --- a/ext/openssl/tests/openssl_peer_fingerprint.phpt +++ b/ext/openssl/tests/openssl_peer_fingerprint.phpt @@ -24,6 +24,7 @@ if ($pid == -1) { 'verify_peer' => true, 'cafile' => __DIR__ . '/bug54992-ca.pem', 'capture_peer_cert' => true, + 'CN_match' => 'bug54992.local', 'peer_fingerprint' => '81cafc260aa8d82956ebc6212a362ece', ) ) @@ -38,6 +39,7 @@ if ($pid == -1) { 'verify_peer' => true, 'cafile' => __DIR__ . '/bug54992-ca.pem', 'capture_peer_cert' => true, + 'CN_match' => 'bug54992.local', 'peer_fingerprint' => array( 'sha256' => '78ea579f2c3b439359dec5dac9d445108772927427c4780037e87df3799a0aa0', ), @@ -59,4 +61,4 @@ Warning: stream_socket_client(): Failed to enable crypto in %s on line %d Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d bool(false) -resource(9) of type (stream) +resource(%d) of type (stream) diff --git a/ext/openssl/tests/peer_verification.phpt b/ext/openssl/tests/peer_verification.phpt new file mode 100644 index 0000000000..7c3347fd65 --- /dev/null +++ b/ext/openssl/tests/peer_verification.phpt @@ -0,0 +1,56 @@ +--TEST-- +Peer verification enabled for client streams +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +if (!function_exists('pcntl_fork')) die("skip no fork"); +--FILE-- +<?php +$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; +$ctx = stream_context_create(['ssl' => [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'allow_self_signed' => true +]]); +$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} else if ($pid) { + // Expected to fail -- no CA File present + var_dump(@stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT)); + + // Expected to fail -- no CA File present + $ctx = stream_context_create(['ssl' => ['verify_peer' => true]]); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // Should succeed with peer verification disabled in context + $ctx = stream_context_create(['ssl' => ['verify_peer' => false]]); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // Should succeed with CA file specified in context + $ctx = stream_context_create(['ssl' => [ + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local', + ]]); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // Should succeed with globally available CA file specified via php.ini + $cafile = __DIR__ . '/bug54992-ca.pem'; + ini_set('openssl.cafile', $cafile); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + +} else { + @pcntl_wait($status); + @stream_socket_accept($server, 3); + @stream_socket_accept($server, 3); + @stream_socket_accept($server, 3); + @stream_socket_accept($server, 3); + @stream_socket_accept($server, 3); +} +--EXPECTF-- +bool(false) +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) diff --git a/ext/openssl/tests/sni_001.phpt b/ext/openssl/tests/sni_001.phpt index 3d7798cf85..2f76a9f918 100644 --- a/ext/openssl/tests/sni_001.phpt +++ b/ext/openssl/tests/sni_001.phpt @@ -24,6 +24,7 @@ function context() { return stream_context_create(array( 'ssl' => array( 'capture_peer_cert' => true, + 'verify_peer' => false ), )); } diff --git a/ext/openssl/tests/streams_crypto_method.phpt b/ext/openssl/tests/streams_crypto_method.phpt index 97a6e9ee8b..981f56b399 100644 --- a/ext/openssl/tests/streams_crypto_method.phpt +++ b/ext/openssl/tests/streams_crypto_method.phpt @@ -10,6 +10,7 @@ if (!extension_loaded('pcntl')) die('skip, pcntl required'); function client($port, $method) { $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'crypto_method', $method); + stream_context_set_option($ctx, 'ssl', 'verify_peer', false); $fp = @fopen('https://127.0.0.1:' . $port . '/', 'r', false, $ctx); if ($fp) { diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 244f04def9..92bcf0039c 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -23,8 +23,8 @@ #include "ext/standard/url.h" #include "streams/php_streams_int.h" #include "ext/standard/php_smart_str.h" -#include "php_network.h" #include "php_openssl.h" +#include "php_openssl_structs.h" #include <openssl/ssl.h> #include <openssl/x509.h> #include <openssl/err.h> @@ -41,25 +41,6 @@ int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stre SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC); int php_openssl_get_x509_list_id(void); -/* This implementation is very closely tied to the that of the native - * sockets implemented in the core. - * Don't try this technique in other extensions! - * */ - -typedef struct _php_openssl_netstream_data_t { - php_netstream_data_t s; - SSL *ssl_handle; - SSL_CTX *ctx; - struct timeval connect_timeout; - int enable_on_connect; - int is_client; - int ssl_active; - php_stream_xport_crypt_method_t method; - char *sni; - unsigned state_set:1; - unsigned _spare:31; -} php_openssl_netstream_data_t; - php_stream_ops php_openssl_socket_ops; /* it doesn't matter that we do some hash traversal here, since it is done only @@ -285,11 +266,12 @@ static int php_openssl_sockop_close(php_stream *stream, int close_handle TSRMLS_ } } - if (sslsock->sni) { - pefree(sslsock->sni, php_stream_is_persistent(stream)); + if (sslsock->url_name) { + pefree(sslsock->url_name, php_stream_is_persistent(stream)); } + pefree(sslsock, php_stream_is_persistent(stream)); - + return 0; } @@ -425,7 +407,8 @@ static inline int php_openssl_setup_crypto(php_stream *stream, if (stream->context && SUCCESS == php_stream_context_get_option( stream->context, "ssl", "no_ticket", &val) && - zval_is_true(*val)) { + zend_is_true(*val TSRMLS_CC) + ) { SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_TICKET); } } @@ -437,7 +420,8 @@ static inline int php_openssl_setup_crypto(php_stream *stream, if (stream->context && SUCCESS == php_stream_context_get_option( stream->context, "ssl", "disable_compression", &val) && - zval_is_true(*val)) { + zend_is_true(*val TSRMLS_CC) + ) { SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_COMPRESSION); } } @@ -467,6 +451,7 @@ static inline int php_openssl_setup_crypto(php_stream *stream, return 0; } + static inline int php_openssl_enable_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam @@ -480,10 +465,22 @@ static inline int php_openssl_enable_crypto(php_stream *stream, int blocked = sslsock->s.is_blocked, has_timeout = 0; -#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) - if (sslsock->is_client && sslsock->sni) { - SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->sni); +#if OPENSSL_VERSION_NUMBER >= 0x00908070L && !defined(OPENSSL_NO_TLSEXT) + + zval **val; + + if (sslsock->is_client + && (php_stream_context_get_option(stream->context, "ssl", "SNI_enabled", &val) == FAILURE + || zend_is_true(*val TSRMLS_CC)) + ) { + if (php_stream_context_get_option(stream->context, "ssl", "SNI_server_name", &val) == SUCCESS) { + convert_to_string_ex(val); + SSL_set_tlsext_host_name(sslsock->ssl_handle, &val); + } else if (sslsock->url_name) { + SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->url_name); + } } + #endif if (!sslsock->state_set) { @@ -581,7 +578,7 @@ static inline int php_openssl_enable_crypto(php_stream *stream, if (SUCCESS == php_stream_context_get_option( stream->context, "ssl", "capture_peer_cert", &val) && - zval_is_true(*val)) { + zend_is_true(*val TSRMLS_CC)) { MAKE_STD_ZVAL(zcert); ZVAL_RESOURCE(zcert, zend_list_insert(peer_cert, php_openssl_get_x509_list_id() TSRMLS_CC)); @@ -595,7 +592,7 @@ static inline int php_openssl_enable_crypto(php_stream *stream, if (SUCCESS == php_stream_context_get_option( stream->context, "ssl", "capture_peer_cert_chain", &val) && - zval_is_true(*val)) { + zend_is_true(*val TSRMLS_CC)) { zval *arr; STACK_OF(X509) *chain; @@ -920,21 +917,9 @@ static int get_crypto_method(php_stream_context *ctx) { return STREAM_CRYPTO_METHOD_SSLv23_CLIENT; } -static char * get_sni(php_stream_context *ctx, const char *resourcename, size_t resourcenamelen, int is_persistent TSRMLS_DC) { +static char * get_url_name(const char *resourcename, size_t resourcenamelen, int is_persistent TSRMLS_DC) { php_url *url; - if (ctx) { - zval **val = NULL; - - if (php_stream_context_get_option(ctx, "ssl", "SNI_enabled", &val) == SUCCESS && !zend_is_true(*val TSRMLS_CC)) { - return NULL; - } - if (php_stream_context_get_option(ctx, "ssl", "SNI_server_name", &val) == SUCCESS) { - convert_to_string_ex(val); - return pestrdup(Z_STRVAL_PP(val), is_persistent); - } - } - if (!resourcename) { return NULL; } @@ -946,7 +931,7 @@ static char * get_sni(php_stream_context *ctx, const char *resourcename, size_t if (url->host) { const char * host = url->host; - char * sni = NULL; + char * url_name = NULL; size_t len = strlen(host); /* skip trailing dots */ @@ -955,11 +940,11 @@ static char * get_sni(php_stream_context *ctx, const char *resourcename, size_t } if (len) { - sni = pestrndup(host, len, is_persistent); + url_name = pestrndup(host, len, is_persistent); } php_url_free(url); - return sni; + return url_name; } php_url_free(url); @@ -1001,8 +986,6 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, return NULL; } - sslsock->sni = get_sni(context, resourcename, resourcenamelen, !!persistent_id TSRMLS_CC); - if (strncmp(proto, "ssl", protolen) == 0) { sslsock->enable_on_connect = 1; @@ -1042,7 +1025,9 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, return NULL; #endif } - + + sslsock->url_name = get_url_name(resourcename, resourcenamelen, !!persistent_id TSRMLS_CC); + return stream; } diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 3ede0ec20b..d17867d1f9 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -196,7 +196,7 @@ static char *dsn_from_uri(char *uri, char *buf, size_t buflen TSRMLS_DC) /* {{{ } /* }}} */ -/* {{{ proto void PDO::__construct(string dsn, string username, string passwd [, array options]) +/* {{{ proto void PDO::__construct(string dsn[, string username[, string passwd [, array options]]]) */ static PHP_METHOD(PDO, dbh_constructor) { @@ -1226,7 +1226,7 @@ static PHP_METHOD(PDO, getAvailableDrivers) /* }}} */ /* {{{ arginfo */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 3) +ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 1) ZEND_ARG_INFO(0, dsn) ZEND_ARG_INFO(0, username) ZEND_ARG_INFO(0, passwd) diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 3ffed6678f..9b083f6545 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -1155,6 +1155,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_ pdo_pgsql_db_handle *H; int ret = 0; char *conn_str, *p, *e; + char *tmp_pass; long connect_timeout = 30; H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent); @@ -1176,18 +1177,44 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_ connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC); } + if (dbh->password) { + if (dbh->password[0] != '\'' && dbh->password[strlen(dbh->password) - 1] != '\'') { + char *pwd = dbh->password; + int pos = 1; + + tmp_pass = safe_emalloc(2, strlen(dbh->password), 3); + tmp_pass[0] = '\''; + + while (*pwd != '\0') { + if (*pwd == '\\' || *pwd == '\'') { + tmp_pass[pos++] = '\\'; + } + + tmp_pass[pos++] = *pwd++; + } + + tmp_pass[pos++] = '\''; + tmp_pass[pos] = '\0'; + } else { + tmp_pass = dbh->password; + } + } + /* support both full connection string & connection string + login and/or password */ if (dbh->username && dbh->password) { - spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, dbh->password, connect_timeout); + spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, tmp_pass, connect_timeout); } else if (dbh->username) { spprintf(&conn_str, 0, "%s user=%s connect_timeout=%ld", dbh->data_source, dbh->username, connect_timeout); } else if (dbh->password) { - spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, dbh->password, connect_timeout); + spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, tmp_pass, connect_timeout); } else { spprintf(&conn_str, 0, "%s connect_timeout=%ld", (char *) dbh->data_source, connect_timeout); } H->server = PQconnectdb(conn_str); + if (dbh->password && tmp_pass != dbh->password) { + efree(tmp_pass); + } efree(conn_str); diff --git a/ext/pdo_pgsql/tests/bug62479.phpt b/ext/pdo_pgsql/tests/bug62479.phpt new file mode 100644 index 0000000000..a12bb8d1ff --- /dev/null +++ b/ext/pdo_pgsql/tests/bug62479.phpt @@ -0,0 +1,56 @@ +--TEST-- +PDO PgSQL Bug #62479 (PDO-psql cannot connect if password contains spaces) +--SKIPIF-- +<?php +if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +PDOTest::skip(); +if (!isset($conf['ENV']['PDOTEST_DSN'])) die('no dsn found in env'); +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); +$rand = rand(5, 5); + +// Assume that if we can't create a user, this test needs to be skipped +$testQuery = "CREATE USER pdo_$rand WITH PASSWORD 'testpass'"; +$db->query($testQuery); +$testQuery = "DROP USER pdo_$rand"; +$db->query($testQuery); +?> +--FILE-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$pdo = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); +$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); +$rand = rand(5, 400); +$user = "pdo_$rand"; +$template = "CREATE USER $user WITH PASSWORD '%s'"; +$dropUser = "DROP USER $user"; +$testQuery = 'SELECT 1 as verification'; + +// Create temp user with space in password +$sql = sprintf($template, 'my password'); +$pdo->query($sql); +$testConn = new PDO($conf['ENV']['PDOTEST_DSN'], $user, "my password"); +$result = $testConn->query($testQuery)->fetch(); +$check = $result[0]; +var_dump($check); + +// Remove the user +$pdo->query($dropUser); + +// Create a user with a space and single quote +$sql = sprintf($template, "my pass''word"); +$pdo->query($sql); + +$testConn = new PDO($conf['ENV']['PDOTEST_DSN'], $user, "my pass'word"); +$result = $testConn->query($testQuery)->fetch(); +$check = $result[0]; +var_dump($check); + +// Remove the user +$pdo->query($dropUser); +?> +--EXPECT-- +int(1) +int(1) + diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4 index 13837bd832..186469861f 100644 --- a/ext/pgsql/config.m4 +++ b/ext/pgsql/config.m4 @@ -94,6 +94,8 @@ if test "$PHP_PGSQL" != "no"; then AC_CHECK_LIB(pq, pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[Whether libpq is compiled with --enable-multibyte])) AC_CHECK_LIB(pq, lo_create, AC_DEFINE(HAVE_PG_LO_CREATE,1,[PostgreSQL 8.1 or later])) AC_CHECK_LIB(pq, lo_import_with_oid, AC_DEFINE(HAVE_PG_LO_IMPORT_WITH_OID,1,[PostgreSQL 8.4 or later])) + AC_CHECK_LIB(pq, lo_truncate, AC_DEFINE(HAVE_PG_LO_TRUNCATE,1,[PostgreSQL 8.3 or later])) + AC_CHECK_LIB(pq, lo_truncate64, AC_DEFINE(HAVE_PG_LO64,1,[PostgreSQL 9.3 or later])) AC_CHECK_LIB(pq, PQescapeLiteral, AC_DEFINE(HAVE_PQESCAPELITERAL,1,[PostgreSQL 9.0 or later])) LIBS=$old_LIBS LDFLAGS=$old_LDFLAGS diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index cab87cf450..95cb8f6cfc 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -19,7 +19,7 @@ | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) | +----------------------------------------------------------------------+ */ - + /* $Id$ */ #include <stdlib.h> @@ -37,6 +37,9 @@ #include "ext/standard/php_standard.h" #include "ext/standard/php_smart_str.h" #include "ext/ereg/php_regex.h" +#ifdef PHP_WIN32 +# include "win32/time.h" +#endif #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME @@ -367,6 +370,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1) ZEND_ARG_INFO(0, large_object) ZEND_END_ARG_INFO() +#if HAVE_PG_LO_TRUNCATE +ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1) + ZEND_ARG_INFO(0, large_object) + ZEND_ARG_INFO(0, size) +ZEND_END_ARG_INFO() +#endif + #if HAVE_PQSETERRORVERBOSITY ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0) ZEND_ARG_INFO(0, connection) @@ -661,6 +671,9 @@ const zend_function_entry pgsql_functions[] = { PHP_FE(pg_lo_export, arginfo_pg_lo_export) PHP_FE(pg_lo_seek, arginfo_pg_lo_seek) PHP_FE(pg_lo_tell, arginfo_pg_lo_tell) +#if HAVE_PG_LO_TRUNCATE + PHP_FE(pg_lo_truncate, arginfo_pg_lo_truncate) +#endif /* utility functions */ #if HAVE_PQESCAPE PHP_FE(pg_escape_string, arginfo_pg_escape_string) @@ -1504,7 +1517,29 @@ static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql)); #if HAVE_PQPARAMETERSTATUS if (PQprotocolVersion(pgsql) >= 3) { + /* 8.0 or grater supports protorol version 3 */ + char *tmp; add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"), 1); + tmp = (char*)PQparameterStatus(pgsql, "server_encoding"); + add_assoc_string(return_value, "server_encoding", tmp, 1); + tmp = (char*)PQparameterStatus(pgsql, "client_encoding"); + add_assoc_string(return_value, "client_encoding", tmp, 1); + tmp = (char*)PQparameterStatus(pgsql, "is_superuser"); + add_assoc_string(return_value, "is_superuser", tmp, 1); + tmp = (char*)PQparameterStatus(pgsql, "session_authorization"); + add_assoc_string(return_value, "session_authorization", tmp, 1); + tmp = (char*)PQparameterStatus(pgsql, "DateStyle"); + add_assoc_string(return_value, "DateStyle", tmp, 1); + tmp = (char*)PQparameterStatus(pgsql, "IntervalStyle"); + add_assoc_string(return_value, "IntervalStyle", tmp ? tmp : "", 1); + tmp = (char*)PQparameterStatus(pgsql, "TimeZone"); + add_assoc_string(return_value, "TimeZone", tmp ? tmp : "", 1); + tmp = (char*)PQparameterStatus(pgsql, "integer_datetimes"); + add_assoc_string(return_value, "integer_datetimes", tmp ? tmp : "", 1); + tmp = (char*)PQparameterStatus(pgsql, "standard_conforming_strings"); + add_assoc_string(return_value, "standard_conforming_strings", tmp ? tmp : "", 1); + tmp = (char*)PQparameterStatus(pgsql, "application_name"); + add_assoc_string(return_value, "application_name", tmp ? tmp : "", 1); } #endif #endif @@ -3592,7 +3627,7 @@ PHP_FUNCTION(pg_lo_export) PHP_FUNCTION(pg_lo_seek) { zval *pgsql_id = NULL; - long offset = 0, whence = SEEK_CUR; + long result, offset = 0, whence = SEEK_CUR; pgLofp *pgsql; int argc = ZEND_NUM_ARGS(); @@ -3606,7 +3641,16 @@ PHP_FUNCTION(pg_lo_seek) ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); - if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence) > -1) { +#if HAVE_PG_LO64 + if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) { + result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, whence); + } else { + result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence); + } +#else + result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence); +#endif + if (result > -1) { RETURN_TRUE; } else { RETURN_FALSE; @@ -3619,7 +3663,7 @@ PHP_FUNCTION(pg_lo_seek) PHP_FUNCTION(pg_lo_tell) { zval *pgsql_id = NULL; - int offset = 0; + long offset = 0; pgLofp *pgsql; int argc = ZEND_NUM_ARGS(); @@ -3629,11 +3673,54 @@ PHP_FUNCTION(pg_lo_tell) ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); +#if HAVE_PG_LO64 + if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) { + offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd); + } else { + offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd); + } +#else offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd); +#endif RETURN_LONG(offset); } /* }}} */ +#if HAVE_PG_LO_TRUNCATE +/* {{{ proto bool pg_lo_truncate(resource large_object, int size) + Truncate large object to size */ +PHP_FUNCTION(pg_lo_truncate) +{ + zval *pgsql_id = NULL; + size_t size; + pgLofp *pgsql; + int argc = ZEND_NUM_ARGS(); + int result; + + if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_id, &size) == FAILURE) { + return; + } + + ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); + +#if HAVE_PG_LO64 + if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) { + result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size); + } else { + result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size); + } +#else + result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size); +#endif + if (!result) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ +#endif + #if HAVE_PQSETERRORVERBOSITY /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity) Set error verbosity */ diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h index d6dab56c4c..016f3aa5a8 100644 --- a/ext/pgsql/php_pgsql.h +++ b/ext/pgsql/php_pgsql.h @@ -157,6 +157,9 @@ PHP_FUNCTION(pg_lo_import); PHP_FUNCTION(pg_lo_export); PHP_FUNCTION(pg_lo_seek); PHP_FUNCTION(pg_lo_tell); +#if HAVE_PG_LO_TRUNCATE +PHP_FUNCTION(pg_lo_truncate); +#endif /* debugging functions */ PHP_FUNCTION(pg_trace); diff --git a/ext/pgsql/tests/00version.phpt b/ext/pgsql/tests/00version.phpt index d72d9e1f21..e4e442d018 100644 --- a/ext/pgsql/tests/00version.phpt +++ b/ext/pgsql/tests/00version.phpt @@ -18,13 +18,33 @@ var_dump(serialize($_ENV)); echo "OK"; ?> --EXPECTF-- -array(3) { +array(13) { ["client"]=> string(%d) "%s" ["protocol"]=> int(%d) ["server"]=> string(%d) "%s" + ["server_encoding"]=> + string(%d) "%s" + ["client_encoding"]=> + string(%d) "%s" + ["is_superuser"]=> + string(%d) "%s" + ["session_authorization"]=> + string(%d) "%s" + ["DateStyle"]=> + string(%d) "%s" + ["IntervalStyle"]=> + string(%d) %s + ["TimeZone"]=> + string(%d) "%s" + ["integer_datetimes"]=> + string(%d) "%s" + ["standard_conforming_strings"]=> + string(%d) "%s" + ["application_name"]=> + string(%d) %s } string(%d) "%s" OK diff --git a/ext/readline/readline.c b/ext/readline/readline.c index ecd5533350..4bd9103462 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -354,6 +354,11 @@ PHP_FUNCTION(readline_clear_history) return; } +#if HAVE_LIBEDIT + /* clear_history is the only function where rl_initialize + is not call to ensure correct allocation */ + using_history(); +#endif clear_history(); RETURN_TRUE; diff --git a/ext/readline/tests/libedit_callback_handler_install_001.phpt b/ext/readline/tests/libedit_callback_handler_install_001.phpt new file mode 100644 index 0000000000..b5d921e279 --- /dev/null +++ b/ext/readline/tests/libedit_callback_handler_install_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +readline_callback_handler_install(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_install')) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +?> +--FILE-- +<?php + +function foo() { + readline_callback_handler_remove(); +} + +var_dump(readline_callback_handler_install('testing: ', 'foo')); +var_dump(readline_callback_handler_install('testing: ', 'foobar!')); +var_dump(readline_callback_handler_install('testing: ')); + +?> +--EXPECTF-- +bool(true) + +Warning: readline_callback_handler_install(): foobar! is not callable in %s on line %d +bool(false) + +Warning: readline_callback_handler_install() expects exactly 2 parameters, 1 given in %s on line %d +NULL diff --git a/ext/readline/tests/libedit_callback_handler_remove_001.phpt b/ext/readline/tests/libedit_callback_handler_remove_001.phpt new file mode 100644 index 0000000000..b7eaa2103f --- /dev/null +++ b/ext/readline/tests/libedit_callback_handler_remove_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +readline_callback_handler_remove(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_remove')) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +?> +--FILE-- +<?php + +var_dump(readline_callback_handler_remove()); +var_dump(readline_callback_handler_install('testing: ', 'foo')); + +function foo() { } +var_dump(readline_callback_handler_install('testing: ', 'foo')); +var_dump(readline_callback_handler_remove()); + +?> +--EXPECTF-- +bool(false) +bool(true) +bool(true) +bool(true) diff --git a/ext/readline/tests/libedit_info_001.phpt b/ext/readline/tests/libedit_info_001.phpt new file mode 100644 index 0000000000..1d79f4ad0c --- /dev/null +++ b/ext/readline/tests/libedit_info_001.phpt @@ -0,0 +1,43 @@ +--TEST-- +readline_info(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline")) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +?> +--FILE-- +<?php + +var_dump(readline_info()); +var_dump(readline_info(1)); +var_dump(readline_info(1,1)); +var_dump(readline_info('line_buffer')); +var_dump(readline_info('readline_name')); +var_dump(readline_info('readline_name', 1)); +var_dump(readline_info('readline_name')); +var_dump(readline_info('attempted_completion_over',1)); +var_dump(readline_info('attempted_completion_over')); + +?> +--EXPECTF-- +array(6) { + ["line_buffer"]=> + string(0) "" + ["point"]=> + int(0) + ["end"]=> + int(0) + ["library_version"]=> + string(%d) "%s" + ["readline_name"]=> + string(0) "" + ["attempted_completion_over"]=> + int(0) +} +NULL +NULL +string(0) "" +string(0) "" +string(0) "" +string(1) "1" +int(0) +int(1) diff --git a/ext/readline/tests/libedit_write_history_001.phpt b/ext/readline/tests/libedit_write_history_001.phpt new file mode 100644 index 0000000000..e9b6dbee8d --- /dev/null +++ b/ext/readline/tests/libedit_write_history_001.phpt @@ -0,0 +1,29 @@ +--TEST-- +readline_write_history(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline") || !function_exists('readline_add_history')) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +?> +--FILE-- +<?php + +$name = tempnam('/tmp', 'readline.tmp'); + +readline_add_history('foo'); +readline_add_history(''); +readline_add_history(1); +readline_add_history(NULL); +readline_write_history($name); + +var_dump(file_get_contents($name)); + +unlink($name); + +?> +--EXPECT-- +string(21) "_HiStOrY_V2_ +foo + +1 + +" diff --git a/ext/readline/tests/readline_callback_handler_install_001.phpt b/ext/readline/tests/readline_callback_handler_install_001.phpt index c88a4e86f1..cc054b0aa6 100644 --- a/ext/readline/tests/readline_callback_handler_install_001.phpt +++ b/ext/readline/tests/readline_callback_handler_install_001.phpt @@ -1,7 +1,9 @@ --TEST-- readline_callback_handler_install(): Basic test --SKIPIF-- -<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_install')) die("skip"); ?> +<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_install')) die("skip"); +if (READLINE_LIB == "libedit") die("skip readline only"); +?> --FILE-- <?php diff --git a/ext/readline/tests/readline_callback_handler_remove_001.phpt b/ext/readline/tests/readline_callback_handler_remove_001.phpt index 83b592e055..17ef220b65 100644 --- a/ext/readline/tests/readline_callback_handler_remove_001.phpt +++ b/ext/readline/tests/readline_callback_handler_remove_001.phpt @@ -1,7 +1,9 @@ --TEST-- readline_callback_handler_remove(): Basic test --SKIPIF-- -<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_remove')) die("skip"); ?> +<?php if (!extension_loaded("readline") || !function_exists('readline_callback_handler_remove')) die("skip"); +if (READLINE_LIB == "libedit") die("skip readline only"); +?> --FILE-- <?php diff --git a/ext/readline/tests/readline_info_001.phpt b/ext/readline/tests/readline_info_001.phpt index ebab3bf68b..81b7806b43 100644 --- a/ext/readline/tests/readline_info_001.phpt +++ b/ext/readline/tests/readline_info_001.phpt @@ -1,7 +1,9 @@ --TEST-- readline_info(): Basic test --SKIPIF-- -<?php if (!extension_loaded("readline")) die("skip"); ?> +<?php if (!extension_loaded("readline")) die("skip"); +if (READLINE_LIB == "libedit") die("skip readline only"); +?> --FILE-- <?php diff --git a/ext/readline/tests/readline_write_history_001.phpt b/ext/readline/tests/readline_write_history_001.phpt index fc0ae3225e..95c34e3e89 100644 --- a/ext/readline/tests/readline_write_history_001.phpt +++ b/ext/readline/tests/readline_write_history_001.phpt @@ -1,7 +1,9 @@ --TEST-- readline_write_history(): Basic test --SKIPIF-- -<?php if (!extension_loaded("readline") || !function_exists('readline_add_history')) die("skip"); ?> +<?php if (!extension_loaded("readline") || !function_exists('readline_add_history')) die("skip"); +if (READLINE_LIB == "libedit") die("skip readline only"); +?> --FILE-- <?php diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index c365760eb7..47140436e7 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -145,10 +145,12 @@ static void ps_files_open(ps_files *data, const char *key TSRMLS_DC) if (fstat(data->fd, &sbuf)) { close(data->fd); + data->fd = -1; return; } if (S_ISLNK(sbuf.st_mode) && php_check_open_basedir(buf TSRMLS_CC)) { close(data->fd); + data->fd = -1; return; } } @@ -342,6 +344,7 @@ PS_READ_FUNC(files) PS(send_cookie) = 1; } php_session_reset_id(TSRMLS_C); + PS(session_status) = php_session_active; } ps_files_open(data, PS(id) TSRMLS_CC); diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c index 41df247e74..319f1d3c79 100644 --- a/ext/session/mod_mm.c +++ b/ext/session/mod_mm.c @@ -371,6 +371,7 @@ PS_READ_FUNC(mm) PS(send_cookie) = 1; } php_session_reset_id(TSRMLS_C); + PS(session_status) = php_session_active; } sd = ps_sd_lookup(data, PS(id), 0); diff --git a/ext/session/session.c b/ext/session/session.c index 7a5254f8a9..38aee7d680 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -492,18 +492,26 @@ static void php_session_initialize(TSRMLS_D) /* {{{ */ } } - php_session_reset_id(TSRMLS_C); - PS(session_status) = php_session_active; + /* Set session ID for compatibility for older/3rd party save handlers */ + if (!PS(use_strict_mode)) { + php_session_reset_id(TSRMLS_C); + PS(session_status) = php_session_active; + } /* Read data */ php_session_track_init(TSRMLS_C); if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == FAILURE) { /* Some broken save handler implementation returns FAILURE for non-existent session ID */ - /* It's better to rase error for this, but disabled error for better compatibility */ + /* It's better to raise error for this, but disabled error for better compatibility */ /* php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to read session data: %s (path: %s)", PS(mod)->s_name, PS(save_path)); */ } + /* Set session ID if session read didn't activated session */ + if (PS(use_strict_mode) && PS(session_status) != php_session_active) { + php_session_reset_id(TSRMLS_C); + PS(session_status) = php_session_active; + } if (val) { PHP_MD5_CTX context; @@ -682,11 +690,10 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */ static PHP_INI_MH(OnUpdateName) /* {{{ */ { /* Numeric session.name won't work at all */ - if (PG(modules_activated) && - (!new_value_length || is_numeric_string(new_value, new_value_length, NULL, NULL, 0))) { + if ((!new_value_length || is_numeric_string(new_value, new_value_length, NULL, NULL, 0))) { int err_type; - if (stage == ZEND_INI_STAGE_RUNTIME) { + if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) { err_type = E_WARNING; } else { err_type = E_ERROR; @@ -1290,6 +1297,49 @@ static int php_session_cache_limiter(TSRMLS_D) /* {{{ */ #define COOKIE_SECURE "; secure" #define COOKIE_HTTPONLY "; HttpOnly" +/* + * Remove already sent session ID cookie. + * It must be directly removed from SG(sapi_header) because sapi_add_header_ex() + * removes all of matching cookie. i.e. It deletes all of Set-Cookie headers. + */ +static void php_session_remove_cookie(TSRMLS_D) { + sapi_header_struct *header; + zend_llist *l = &SG(sapi_headers).headers; + zend_llist_element *next; + zend_llist_element *current; + char *session_cookie, *e_session_name; + int session_cookie_len, len = sizeof("Set-Cookie")-1; + + e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)), NULL); + spprintf(&session_cookie, 0, "Set-Cookie: %s=", e_session_name); + efree(e_session_name); + + session_cookie_len = strlen(session_cookie); + current = l->head; + while (current) { + header = (sapi_header_struct *)(current->data); + next = current->next; + if (header->header_len > len && header->header[len] == ':' + && !strncmp(header->header, session_cookie, session_cookie_len)) { + if (current->prev) { + current->prev->next = next; + } else { + l->head = next; + } + if (next) { + next->prev = current->prev; + } else { + l->tail = current->prev; + } + sapi_free_header(header); + efree(current); + --l->count; + } + current = next; + } + efree(session_cookie); +} + static void php_session_send_cookie(TSRMLS_D) /* {{{ */ { smart_str ncookie = {0}; @@ -1358,8 +1408,7 @@ static void php_session_send_cookie(TSRMLS_D) /* {{{ */ smart_str_0(&ncookie); - /* 'replace' must be 0 here, else a previous Set-Cookie - header, probably sent with setcookie() will be replaced! */ + php_session_remove_cookie(TSRMLS_C); /* remove already sent session ID cookie */ sapi_add_header_ex(ncookie.c, ncookie.len, 0, 0 TSRMLS_CC); } /* }}} */ diff --git a/ext/session/tests/bug60634.phpt b/ext/session/tests/bug60634.phpt index e2dfd15b37..86dcb11526 100644 --- a/ext/session/tests/bug60634.phpt +++ b/ext/session/tests/bug60634.phpt @@ -43,3 +43,4 @@ echo "um, hi\n"; --EXPECTF-- write: goodbye cruel world close: goodbye cruel world + diff --git a/ext/session/tests/bug60634_error_4.phpt b/ext/session/tests/bug60634_error_4.phpt index f21d077b54..d0b5786af9 100644 --- a/ext/session/tests/bug60634_error_4.phpt +++ b/ext/session/tests/bug60634_error_4.phpt @@ -49,3 +49,4 @@ Stack trace: #1 {main} thrown in %s on line %d close: goodbye cruel world + diff --git a/ext/session/tests/bug66481-win32.phpt b/ext/session/tests/bug66481-win32.phpt new file mode 100644 index 0000000000..cf06cb6b95 --- /dev/null +++ b/ext/session/tests/bug66481-win32.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #66481: Calls to session_name() segfault when session.name is null, Windows. +--INI-- +session.name= +--SKIPIF-- +<?php include('skipif.inc'); ?> +<?php if(substr(PHP_OS, 0, 3) != "WIN") die("skip Windows only"); ?> +--FILE-- +<?php + +var_dump(session_name("foo")); +var_dump(session_name("bar")); +--EXPECTF-- +Warning: PHP Startup: session.name cannot be a numeric or empty '' in Unknown on line 0 +string(9) "PHPSESSID" +string(3) "foo" +PHP Warning: PHP Startup: session.name cannot be a numeric or empty '' in Unknown on line 0 diff --git a/ext/session/tests/bug66481.phpt b/ext/session/tests/bug66481.phpt new file mode 100644 index 0000000000..5525ae8a38 --- /dev/null +++ b/ext/session/tests/bug66481.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #66481: Calls to session_name() segfault when session.name is null. +--INI-- +session.name= +--SKIPIF-- +<?php include('skipif.inc'); ?> +<?php if(substr(PHP_OS, 0, 3) == "WIN") die("skip Not for Windows"); ?> +--FILE-- +<?php + +var_dump(session_name("foo")); +var_dump(session_name("bar")); +--EXPECTF-- +PHP Warning: PHP Startup: session.name cannot be a numeric or empty '' in Unknown on line 0 + +Warning: PHP Startup: session.name cannot be a numeric or empty '' in Unknown on line 0 +string(9) "PHPSESSID" +string(3) "foo" diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 4604f60adb..6409ff37d8 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1216,7 +1216,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_fstat, 0) ZEND_ARG_INFO(0, fp) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_copy, 0) +ZEND_BEGIN_ARG_INFO_EX(arginfo_copy, 0, 0, 2) ZEND_ARG_INFO(0, source_file) ZEND_ARG_INFO(0, destination_file) ZEND_ARG_INFO(0, context) diff --git a/ext/standard/credits_ext.h b/ext/standard/credits_ext.h index efefa98ee8..f77bbdf157 100644 --- a/ext/standard/credits_ext.h +++ b/ext/standard/credits_ext.h @@ -17,8 +17,8 @@ CREDIT_LINE("COM and .Net", "Wez Furlong"); CREDIT_LINE("ctype", "Hartmut Holzgraefe"); CREDIT_LINE("cURL", "Sterling Hughes"); CREDIT_LINE("Date/Time Support", "Derick Rethans"); -CREDIT_LINE("DBA", "Sascha Schumann, Marcus Boerger"); CREDIT_LINE("DB-LIB (MS SQL, Sybase)", "Wez Furlong, Frank M. Kromann"); +CREDIT_LINE("DBA", "Sascha Schumann, Marcus Boerger"); CREDIT_LINE("DOM", "Christian Stocker, Rob Richards, Marcus Boerger"); CREDIT_LINE("enchant", "Pierre-Alain Joye, Ilia Alshanetsky"); CREDIT_LINE("ereg", "Rasmus Lerdorf, Jim Winstead, Jaakko Hyvätti"); @@ -41,9 +41,9 @@ CREDIT_LINE("mcrypt", "Sascha Schumann, Derick Rethans"); CREDIT_LINE("MS SQL", "Frank M. Kromann"); CREDIT_LINE("Multibyte String Functions", "Tsukada Takuya, Rui Hirokawa"); CREDIT_LINE("MySQL driver for PDO", "George Schlossnagle, Wez Furlong, Ilia Alshanetsky, Johannes Schlueter"); -CREDIT_LINE("MySQLi", "Zak Greant, Georg Richter, Andrey Hristov, Ulf Wendel"); -CREDIT_LINE("MySQLnd", "Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlüter"); CREDIT_LINE("MySQL", "Zeev Suraski, Zak Greant, Georg Richter, Andrey Hristov"); +CREDIT_LINE("MySQLi", "Zak Greant, Georg Richter, Andrey Hristov, Ulf Wendel"); +CREDIT_LINE("MySQLnd", "Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlüter"); CREDIT_LINE("OCI8", "Stig Bakken, Thies C. Arntzen, Andy Sautins, David Benson, Maxim Maletsky, Harald Radi, Antony Dovgal, Andi Gutmans, Wez Furlong, Christopher Jones, Oracle Corporation"); CREDIT_LINE("ODBC driver for PDO", "Wez Furlong"); CREDIT_LINE("ODBC", "Stig Bakken, Andreas Karajannis, Frank M. Kromann, Daniel R. Kalowsky"); @@ -68,8 +68,8 @@ CREDIT_LINE("SNMP", "Rasmus Lerdorf, Harrie Hazewinkel, Mike Jackson, Steven Law CREDIT_LINE("SOAP", "Brad Lafountain, Shane Caraveo, Dmitry Stogov"); CREDIT_LINE("Sockets", "Chris Vandomelen, Sterling Hughes, Daniel Beulshausen, Jason Greene"); CREDIT_LINE("SPL", "Marcus Boerger, Etienne Kneuss"); -CREDIT_LINE("SQLite3", "Scott MacVicar, Ilia Alshanetsky, Brad Dewar"); CREDIT_LINE("SQLite 3.x driver for PDO", "Wez Furlong"); +CREDIT_LINE("SQLite3", "Scott MacVicar, Ilia Alshanetsky, Brad Dewar"); CREDIT_LINE("Sybase-CT", "Zeev Suraski, Tom May, Timm Friebe"); CREDIT_LINE("System V Message based IPC", "Wez Furlong"); CREDIT_LINE("System V Semaphores", "Tom May"); @@ -77,9 +77,9 @@ CREDIT_LINE("System V Shared Memory", "Christian Cartus"); CREDIT_LINE("tidy", "John Coggeshall, Ilia Alshanetsky"); CREDIT_LINE("tokenizer", "Andrei Zmievski, Johannes Schlueter"); CREDIT_LINE("WDDX", "Andrei Zmievski"); +CREDIT_LINE("XML", "Stig Bakken, Thies C. Arntzen, Sterling Hughes"); CREDIT_LINE("XMLReader", "Rob Richards"); CREDIT_LINE("xmlrpc", "Dan Libby"); -CREDIT_LINE("XML", "Stig Bakken, Thies C. Arntzen, Sterling Hughes"); CREDIT_LINE("XMLWriter", "Rob Richards, Pierre-Alain Joye"); CREDIT_LINE("XSL", "Christian Stocker, Rob Richards"); CREDIT_LINE("Zip", "Pierre-Alain Joye, Remi Collet"); diff --git a/ext/standard/tests/file/bug66509.phpt b/ext/standard/tests/file/bug66509.phpt new file mode 100644 index 0000000000..0e414f2321 --- /dev/null +++ b/ext/standard/tests/file/bug66509.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #66509 (copy() showing $context parameter as required) +--FILE-- +<?php + +$r = new \ReflectionFunction('copy'); + +foreach($r->getParameters() as $p) { + var_dump($p->isOptional()); +} +?> +--EXPECT-- +bool(false) +bool(false) +bool(true) diff --git a/ext/standard/tests/math/tan_basiclong_64bit.phpt b/ext/standard/tests/math/tan_basiclong_64bit.phpt index 8ab083d500..3c8abe9d27 100644 --- a/ext/standard/tests/math/tan_basiclong_64bit.phpt +++ b/ext/standard/tests/math/tan_basiclong_64bit.phpt @@ -1,5 +1,7 @@ --TEST-- Test tan function : 64bit long tests +--INI-- +precision=5 --SKIPIF-- <?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); @@ -28,33 +30,34 @@ foreach ($longVals as $longVal) { ===DONE=== --EXPECT-- --- testing: 9223372036854775807 --- -float(84.739312968756) +float(84.739) --- testing: -9223372036854775808 --- -float(-84.739312968756) +float(-84.739) --- testing: 2147483647 --- -float(1.0523779637351) +float(1.0524) --- testing: -2147483648 --- -float(4.0842894552986) +float(4.0843) --- testing: 9223372034707292160 --- -float(-0.25738520049439) +float(-0.25739) --- testing: -9223372034707292160 --- -float(0.25738520049439) +float(0.25739) --- testing: 2147483648 --- -float(-4.0842894552986) +float(-4.0843) --- testing: -2147483649 --- -float(0.34328416030117) +float(0.34328) --- testing: 4294967294 --- -float(-19.579238091943) +float(-19.579) --- testing: 4294967295 --- -float(-0.57225137018055) +float(-0.57225) --- testing: 4294967293 --- -float(0.71667000824652) +float(0.71667) --- testing: 9223372036854775806 --- -float(84.739312968756) ---- testing: 9.2233720368548E+18 --- -float(84.739312968756) +float(84.739) +--- testing: 9.2234E+18 --- +float(84.739) --- testing: -9223372036854775807 --- -float(-84.739312968756) ---- testing: -9.2233720368548E+18 --- -float(-84.739312968756) +float(-84.739) +--- testing: -9.2234E+18 --- +float(-84.739) ===DONE=== + diff --git a/ext/zip/lib/zipconf.h b/ext/zip/lib/zipconf.h index 1cb5c0467a..955d85b4ef 100644 --- a/ext/zip/lib/zipconf.h +++ b/ext/zip/lib/zipconf.h @@ -7,7 +7,7 @@ This file was generated automatically by CMake
based on ../cmake-zipconf.h.in.
*/
-#define LIBZIP_VERSION "0.11.1"
+#define LIBZIP_VERSION "0.11.2"
/* #undef HAVE_INTTYPES_H_LIBZIP */
#if defined(_WIN32)
diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 591b907aa8..ffe4530415 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -38,7 +38,7 @@ extern zend_module_entry zip_module_entry; #define ZIP_OVERWRITE ZIP_TRUNCATE #endif -#define PHP_ZIP_VERSION "1.12.4-dev" +#define PHP_ZIP_VERSION "1.12.4" #if ((PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 2) || PHP_MAJOR_VERSION >= 6) # define PHP_ZIP_USE_OO 1 diff --git a/main/php_ini.c b/main/php_ini.c index 3bcb249f84..f7f4686e84 100644 --- a/main/php_ini.c +++ b/main/php_ini.c @@ -630,63 +630,81 @@ int php_init_config(TSRMLS_D) zend_llist scanned_ini_list; zend_llist_element *element; int l, total_l = 0; + char *bufpath, *debpath, *endpath; + int lenpath; - if ((ndir = php_scandir(php_ini_scanned_path, &namelist, 0, php_alphasort)) > 0) { - zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1); - memset(&fh2, 0, sizeof(fh2)); + zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1); + memset(&fh2, 0, sizeof(fh2)); - for (i = 0; i < ndir; i++) { + bufpath = estrdup(php_ini_scanned_path); + for (debpath = bufpath ; debpath ; debpath=endpath) { + endpath = strchr(debpath, DEFAULT_DIR_SEPARATOR); + if (endpath) { + *(endpath++) = 0; + } + if (!debpath[0]) { + /* empty string means default builtin value + to allow "/foo/phd.d:" or ":/foo/php.d" */ + debpath = PHP_CONFIG_FILE_SCAN_DIR; + } + lenpath = strlen(debpath); - /* check for any file with .ini extension */ - if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) { - free(namelist[i]); - continue; - } - /* Reset active ini section */ - RESET_ACTIVE_INI_HASH(); + if (lenpath > 0 && (ndir = php_scandir(debpath, &namelist, 0, php_alphasort)) > 0) { - if (IS_SLASH(php_ini_scanned_path[php_ini_scanned_path_len - 1])) { - snprintf(ini_file, MAXPATHLEN, "%s%s", php_ini_scanned_path, namelist[i]->d_name); - } else { - snprintf(ini_file, MAXPATHLEN, "%s%c%s", php_ini_scanned_path, DEFAULT_SLASH, namelist[i]->d_name); - } - if (VCWD_STAT(ini_file, &sb) == 0) { - if (S_ISREG(sb.st_mode)) { - if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) { - fh2.filename = ini_file; - fh2.type = ZEND_HANDLE_FP; - - if (zend_parse_ini_file(&fh2, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC) == SUCCESS) { - /* Here, add it to the list of ini files read */ - l = strlen(ini_file); - total_l += l + 2; - p = estrndup(ini_file, l); - zend_llist_add_element(&scanned_ini_list, &p); + for (i = 0; i < ndir; i++) { + + /* check for any file with .ini extension */ + if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) { + free(namelist[i]); + continue; + } + /* Reset active ini section */ + RESET_ACTIVE_INI_HASH(); + + if (IS_SLASH(debpath[lenpath - 1])) { + snprintf(ini_file, MAXPATHLEN, "%s%s", debpath, namelist[i]->d_name); + } else { + snprintf(ini_file, MAXPATHLEN, "%s%c%s", debpath, DEFAULT_SLASH, namelist[i]->d_name); + } + if (VCWD_STAT(ini_file, &sb) == 0) { + if (S_ISREG(sb.st_mode)) { + if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) { + fh2.filename = ini_file; + fh2.type = ZEND_HANDLE_FP; + + if (zend_parse_ini_file(&fh2, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC) == SUCCESS) { + /* Here, add it to the list of ini files read */ + l = strlen(ini_file); + total_l += l + 2; + p = estrndup(ini_file, l); + zend_llist_add_element(&scanned_ini_list, &p); + } } } } + free(namelist[i]); } - free(namelist[i]); + free(namelist); } - free(namelist); + } + efree(bufpath); - if (total_l) { - int php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0; - php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1); - if (!php_ini_scanned_files_len) { - *php_ini_scanned_files = '\0'; - } - total_l += php_ini_scanned_files_len; - for (element = scanned_ini_list.head; element; element = element->next) { - if (php_ini_scanned_files_len) { - strlcat(php_ini_scanned_files, ",\n", total_l); - } - strlcat(php_ini_scanned_files, *(char **)element->data, total_l); - strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l); + if (total_l) { + int php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0; + php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1); + if (!php_ini_scanned_files_len) { + *php_ini_scanned_files = '\0'; + } + total_l += php_ini_scanned_files_len; + for (element = scanned_ini_list.head; element; element = element->next) { + if (php_ini_scanned_files_len) { + strlcat(php_ini_scanned_files, ",\n", total_l); } + strlcat(php_ini_scanned_files, *(char **)element->data, total_l); + strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l); } - zend_llist_destroy(&scanned_ini_list); } + zend_llist_destroy(&scanned_ini_list); } else { /* Make sure an empty php_ini_scanned_path ends up as NULL */ php_ini_scanned_path = NULL; @@ -35,7 +35,7 @@ if test "${1}" = "1" -a "${2}" -lt "28"; then fi IFS="$old_IFS" -if test "$PHPROOTx" == "x"; then +if test "x$PHPROOT" == "x"; then PHPROOT=git@git.php.net:php-src.git; fi diff --git a/php.ini-development b/php.ini-development index df39e42140..137574bdee 100644 --- a/php.ini-development +++ b/php.ini-development @@ -138,16 +138,6 @@ ; Development Value: "GP" ; Production Value: "GP" -; session.bug_compat_42 -; Default Value: On -; Development Value: On -; Production Value: Off - -; session.bug_compat_warn -; Default Value: On -; Development Value: On -; Production Value: Off - ; session.gc_divisor ; Default Value: 100 ; Development Value: 1000 @@ -1481,31 +1471,6 @@ session.gc_maxlifetime = 1440 ; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): ; find /path/to/sessions -cmin +24 -type f | xargs rm -; PHP 4.2 and less have an undocumented feature/bug that allows you to -; to initialize a session variable in the global scope. -; PHP 4.3 and later will warn you if this feature is used. -; You can disable the feature and the warning separately. At this time, -; the warning is only displayed, if bug_compat_42 is enabled. This feature -; introduces some serious security problems if not handled correctly. We -; recommend you not use this feature on production servers. You -; should enable this on development servers and enable the warning as well. If you -; do not enable the feature on development servers, you won't be warned when it's -; used, so debugging errors caused by this can be difficult to track down. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-42 -session.bug_compat_42 = On - -; This setting controls whether or not you are warned by PHP when initializing a -; session value into the global space. session.bug_compat_42 must be enabled before -; these warnings can be issued by PHP. See the directive above for more information. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-warn -session.bug_compat_warn = On - ; Check HTTP Referer to invalidate externally stored URLs containing ids. ; HTTP_REFERER has to contain this substring for the session to be ; considered as valid. diff --git a/php.ini-production b/php.ini-production index cff1a3bc00..3fa1788a00 100644 --- a/php.ini-production +++ b/php.ini-production @@ -138,16 +138,6 @@ ; Development Value: "GP" ; Production Value: "GP" -; session.bug_compat_42 -; Default Value: On -; Development Value: On -; Production Value: Off - -; session.bug_compat_warn -; Default Value: On -; Development Value: On -; Production Value: Off - ; session.gc_divisor ; Default Value: 100 ; Development Value: 1000 @@ -1481,31 +1471,6 @@ session.gc_maxlifetime = 1440 ; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): ; find /path/to/sessions -cmin +24 -type f | xargs rm -; PHP 4.2 and less have an undocumented feature/bug that allows you to -; to initialize a session variable in the global scope. -; PHP 4.3 and later will warn you if this feature is used. -; You can disable the feature and the warning separately. At this time, -; the warning is only displayed, if bug_compat_42 is enabled. This feature -; introduces some serious security problems if not handled correctly. We -; recommend you not use this feature on production servers. You -; should enable this on development servers and enable the warning as well. If you -; do not enable the feature on development servers, you won't be warned when it's -; used, so debugging errors caused by this can be difficult to track down. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-42 -session.bug_compat_42 = Off - -; This setting controls whether or not you are warned by PHP when initializing a -; session value into the global space. session.bug_compat_42 must be enabled before -; these warnings can be issued by PHP. See the directive above for more information. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-warn -session.bug_compat_warn = Off - ; Check HTTP Referer to invalidate externally stored URLs containing ids. ; HTTP_REFERER has to contain this substring for the session to be ; considered as valid. diff --git a/run-tests.php b/run-tests.php index 45ea29de51..cd6038e9b1 100755 --- a/run-tests.php +++ b/run-tests.php @@ -850,7 +850,7 @@ $exts_skipped = 0; $ignored_by_ext = 0; sort($exts_to_test); $test_dirs = array(); -$optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi'); +$optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi', 'sapi/fpm'); foreach($optionals as $dir) { if (@filetype($dir) == 'dir') { diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index bd6d64930b..40cd69c719 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -536,6 +536,22 @@ AC_DEFUN([AC_FPM_SELECT], ]) dnl }}} +AC_DEFUN([AC_FPM_APPARMOR], +[ + AC_MSG_CHECKING([for apparmor]) + + SAVED_LIBS="$LIBS" + LIBS="$LIBS -lapparmor" + + AC_TRY_LINK([ #include <sys/apparmor.h> ], [change_hat("test", 0);], [ + AC_DEFINE([HAVE_APPARMOR], 1, [do we have apparmor support?]) + AC_MSG_RESULT([yes]) + ], [ + LIBS="$SAVED_LIBS" + AC_MSG_RESULT([no]) + ]) +]) + AC_MSG_CHECKING(for FPM build) if test "$PHP_FPM" != "no"; then @@ -547,14 +563,15 @@ if test "$PHP_FPM" != "no"; then AC_FPM_TRACE AC_FPM_BUILTIN_ATOMIC AC_FPM_LQ - AC_FPM_SYSCONF - AC_FPM_TIMES - AC_FPM_KQUEUE - AC_FPM_PORT - AC_FPM_DEVPOLL - AC_FPM_EPOLL - AC_FPM_POLL - AC_FPM_SELECT + AC_FPM_SYSCONF + AC_FPM_TIMES + AC_FPM_KQUEUE + AC_FPM_PORT + AC_FPM_DEVPOLL + AC_FPM_EPOLL + AC_FPM_POLL + AC_FPM_SELECT + AC_FPM_APPARMOR PHP_ARG_WITH(fpm-user,, [ --with-fpm-user[=USER] Set the user for php-fpm to run as. (default: nobody)], nobody, no) diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index b866f37f2d..96a29c5f10 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -39,10 +39,11 @@ struct fpm_globals_s fpm_globals = { .test_successful = 0, .heartbeat = 0, .run_as_root = 0, + .force_stderr = 0, .send_config_pipe = {0, 0}, }; -int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon) /* {{{ */ +int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr) /* {{{ */ { fpm_globals.argc = argc; fpm_globals.argv = argv; @@ -52,6 +53,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t fpm_globals.prefix = prefix; fpm_globals.pid = pid; fpm_globals.run_as_root = run_as_root; + fpm_globals.force_stderr = force_stderr; if (0 > fpm_php_init_main() || 0 > fpm_stdio_init_main() || diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h index 65d0e0d691..4916140e17 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -37,7 +37,7 @@ int fpm_run(int *max_requests); -int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon); +int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr); struct fpm_globals_s { pid_t parent_pid; @@ -55,6 +55,7 @@ struct fpm_globals_s { int test_successful; int heartbeat; int run_as_root; + int force_stderr; int send_config_pipe[2]; }; diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index cd5fc34d0f..20adf91df4 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -149,6 +149,9 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = { { "chdir", &fpm_conf_set_string, WPO(chdir) }, { "catch_workers_output", &fpm_conf_set_boolean, WPO(catch_workers_output) }, { "security.limit_extensions", &fpm_conf_set_string, WPO(security_limit_extensions) }, +#ifdef HAVE_APPARMOR + { "apparmor_hat", &fpm_conf_set_string, WPO(apparmor_hat) }, +#endif { 0, 0, 0 } }; @@ -644,6 +647,9 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */ free(wpc->chroot); free(wpc->chdir); free(wpc->security_limit_extensions); +#ifdef HAVE_APPARMOR + free(wpc->apparmor_hat); +#endif for (kv = wpc->php_values; kv; kv = kv_next) { kv_next = kv->next; diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index efd65dc6d9..4b29749042 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -87,6 +87,9 @@ struct fpm_worker_pool_config_s { struct key_value_s *env; struct key_value_s *php_admin_values; struct key_value_s *php_values; +#ifdef HAVE_APPARMOR + char *apparmor_hat; +#endif }; struct ini_value_parser_s { diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index fb22a6840e..807ea8bb5d 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -157,6 +157,7 @@ static const opt_struct OPTIONS[] = { {'R', 0, "allow-to-run-as-root"}, {'D', 0, "daemonize"}, {'F', 0, "nodaemonize"}, + {'O', 0, "force-stderr"}, {'-', 0, NULL} /* end of args */ }; @@ -921,7 +922,7 @@ static void php_cgi_usage(char *argv0) prog = "php"; } - php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F]\n" + php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F [-O]]\n" " -c <path>|<file> Look for php.ini file in this directory\n" " -n No php.ini file will be used\n" " -d foo[=bar] Define INI entry foo with value 'bar'\n" @@ -940,6 +941,8 @@ static void php_cgi_usage(char *argv0) " -D, --daemonize force to run in background, and ignore daemonize option from config file\n" " -F, --nodaemonize\n" " force to stay in foreground, and ignore daemonize option from config file\n" + " -O, --force-stderr\n" + " force output to stderr in nodaemonize even if stderr is not a TTY\n" " -R, --allow-to-run-as-root\n" " Allow pool to run as root (disabled by default)\n", prog, PHP_PREFIX); @@ -1572,6 +1575,7 @@ int main(int argc, char *argv[]) char *fpm_pid = NULL; int test_conf = 0; int force_daemon = -1; + int force_stderr = 0; int php_information = 0; int php_allow_to_run_as_root = 0; @@ -1700,6 +1704,10 @@ int main(int argc, char *argv[]) force_daemon = 0; break; + case 'O': /* force stderr even on non tty */ + force_stderr = 1; + break; + default: case 'h': case '?': @@ -1827,7 +1835,7 @@ consult the installation file that came with this distribution, or visit \n\ } } - if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon)) { + if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) { if (fpm_globals.send_config_pipe[1]) { int writeval = 0; diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index d81e10150d..33b0e01c87 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -292,7 +292,7 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ } else { fpm_globals.error_log_fd = fd; #if HAVE_UNISTD_H - if (fpm_global_config.daemonize || !isatty(STDERR_FILENO)) { + if (fpm_global_config.daemonize || (!isatty(STDERR_FILENO) && !fpm_globals.force_stderr)) { #else if (fpm_global_config.daemonize) { #endif diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index 48249e8a49..b32213fa74 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -17,6 +17,10 @@ #include <sys/prctl.h> #endif +#ifdef HAVE_APPARMOR +#include <sys/apparmor.h> +#endif + #include "fpm.h" #include "fpm_conf.h" #include "fpm_cleanup.h" @@ -222,6 +226,37 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ if (0 > fpm_clock_init()) { return -1; } + +#ifdef HAVE_APPARMOR + if (wp->config->apparmor_hat) { + char *con, *new_con; + + if (aa_getcon(&con, NULL) == -1) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to query apparmor confinement. Please check if \"/proc/*/attr/current\" is read and writeable.", wp->config->name); + return -1; + } + + new_con = malloc(strlen(con) + strlen(wp->config->apparmor_hat) + 3); // // + 0 Byte + if (!new_con) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to allocate memory for apparmor hat change.", wp->config->name); + return -1; + } + + if (0 > sprintf(new_con, "%s//%s", con, wp->config->apparmor_hat)) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to construct apparmor confinement.", wp->config->name); + return -1; + } + + if (0 > aa_change_profile(new_con)) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to change to new confinement (%s). Please check if \"/proc/*/attr/current\" is read and writeable and \"change_profile -> %s//*\" is allowed.", wp->config->name, new_con, con); + return -1; + } + + free(con); + free(new_con); + } +#endif + return 0; } /* }}} */ diff --git a/sapi/fpm/tests/001.phpt b/sapi/fpm/tests/001.phpt new file mode 100644 index 0000000000..b721bfa925 --- /dev/null +++ b/sapi/fpm/tests/001.phpt @@ -0,0 +1,21 @@ +--TEST-- +FPM: version string +--SKIPIF-- +<?php include "skipif.inc"; ?> +--FILE-- +<?php + +include "include.inc"; + +$php = get_fpm_path(); + +var_dump(`$php -n -v`); + +echo "Done\n"; +?> +--EXPECTF-- +string(%d) "PHP %s (fpm%s (built: %s +Copyright (c) 1997-20%s The PHP Group +Zend Engine v%s, Copyright (c) 1998-20%s Zend Technologies +" +Done diff --git a/sapi/fpm/tests/002.phpt b/sapi/fpm/tests/002.phpt new file mode 100644 index 0000000000..2ef6cedc38 --- /dev/null +++ b/sapi/fpm/tests/002.phpt @@ -0,0 +1,53 @@ +--TEST-- +FPM: Startup and connect +--SKIPIF-- +<?php include "skipif.inc"; ?> +--FILE-- +<?php + +include "include.inc"; + +$logfile = dirname(__FILE__).'/php-fpm.log.tmp'; + +$cfg = <<<EOT +[global] +error_log = $logfile +[unconfined] +listen = 127.0.0.1:9000 +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +EOT; + +$fpm = run_fpm($cfg, $tail); +if (is_resource($fpm)) { + var_dump(fgets($tail)); + var_dump(fgets($tail)); + $i = 0; + while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', 9000))) { + usleep(10000); + } + if ($fp) { + echo "Done\n"; + fclose($fp); + } + proc_terminate($fpm); + stream_get_contents($tail); + fclose($tail); + proc_close($fpm); +} + +?> +--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-- +<?php + $logfile = dirname(__FILE__).'/php-fpm.log.tmp'; + @unlink($logfile); +?> diff --git a/sapi/fpm/tests/apparmor.phpt b/sapi/fpm/tests/apparmor.phpt new file mode 100644 index 0000000000..cf9bd71118 --- /dev/null +++ b/sapi/fpm/tests/apparmor.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: Apparmor Test +--DESCRIPTION-- +This test tries to launches a pool which tries to change to non existing +apparmor hat a. Test succeeds if apparmor is not running or hat is non +existant. +--SKIPIF-- +<?php +include "skipif.inc"; +include "skipapparmor.inc"; + +?> +--FILE-- +<?php + +include "include.inc"; + +$logfile = dirname(__FILE__).'/php-fpm.log.tmp'; + +$cfg = <<<EOT +[global] +error_log = $logfile +[a] +listen = 127.0.0.1:9001 +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +apparmor_hat = a +EOT; + +/* libapparmor has a bug which can cause SIGSEGV till Version 2.8.0-0ubuntu28 + See https://bugs.launchpad.net/apparmor/+bug/1196880 + Possible outcomes: + + - SIGSEGV|failed to query apparmor confinement + apparmor not running + - failed to change to new confinement + something in apparmor went wrong + - exited with code 70 + Change to successful; Hat not existant (Process gets killed by apparmor) + */ +var_dump(run_fpm_till('/(SIGSEGV|failed to query apparmor confinement|failed to change to new confinement|exited with code 70)/', $cfg)); + +?> +--EXPECTF-- +string(%d) "%s +" +--CLEAN-- +<?php + $logfile = dirname(__FILE__).'/php-fpm.log.tmp'; + @unlink($logfile); +?> diff --git a/sapi/fpm/tests/include.inc b/sapi/fpm/tests/include.inc new file mode 100644 index 0000000000..983cbd3454 --- /dev/null +++ b/sapi/fpm/tests/include.inc @@ -0,0 +1,79 @@ +<?php + +function get_fpm_path() /* {{{ */ +{ + $php_path = getenv("TEST_PHP_EXECUTABLE"); + + for ($i = 0; $i < 2; $i++) { + $slash_pos = strrpos($php_path, "/"); + if ($slash_pos) { + $php_path = substr($php_path, 0, $slash_pos); + } else { + return false; + } + } + + if ($php_path && is_dir($php_path) && file_exists($php_path."/fpm/php-fpm") && is_executable($php_path."/fpm/php-fpm")) { + /* gotcha */ + return $php_path."/fpm/php-fpm"; + } + return false; +} +/* }}} */ + +function run_fpm($config, &$out = false, $extra_args = '') /* {{{ */ +{ + $cfg = dirname(__FILE__).'/test-fpm-config.tmp'; + file_put_contents($cfg, $config); + $desc = []; + if ($out !== false) { + $desc = [1 => array('pipe', 'w')]; + } + /* Since it's not possible to spawn a process under linux without using a + * shell in php (why?!?) we need a little shell trickery, so that we can + * actually kill php-fpm */ + $fpm = proc_open('killit () { kill $child; }; trap killit TERM; '.get_fpm_path().' -F -O -y '.$cfg.' '.$extra_args.' 2>&1 & child=$!; wait', $desc, $pipes); + register_shutdown_function( + function($fpm) use($cfg) { + @unlink($cfg); + if (is_resource($fpm)) { + @proc_terminate($fpm); + while (proc_get_status($fpm)['running']) { + usleep(10000); + } + } + }, + $fpm + ); + if ($out !== false) { + $out = $pipes[1]; + } + return $fpm; +} +/* }}} */ + +function run_fpm_till($needle, $config, $max = 10) /* {{{ */ +{ + $i = 0; + $fpm = run_fpm($config, $tail); + if (is_resource($fpm)) { + while($i < $max) { + $i++; + $line = fgets($tail); + if(preg_match($needle, $line) === 1) { + break; + } + } + if ($i >= $max) { + $line = false; + } + proc_terminate($fpm); + stream_get_contents($tail); + fclose($tail); + proc_close($fpm); + } + return $line; +} +/* }}} */ + +?> diff --git a/sapi/fpm/tests/skipapparmor.inc b/sapi/fpm/tests/skipapparmor.inc new file mode 100644 index 0000000000..b286d0361d --- /dev/null +++ b/sapi/fpm/tests/skipapparmor.inc @@ -0,0 +1,30 @@ +<?php + +$logfile = dirname(__FILE__).'/php-fpm.log.tmp'; +$cfg = <<<EOT +[global] +error_log = $logfile +[a] +listen = 127.0.0.1:9001 +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +apparmor_hat = a +EOT; + +$fpm = run_fpm($cfg, $out, '-t'); +$ok = false; +if (is_resource($fpm)) { + if (strpos(stream_get_contents($out), "test is successful") !== FALSE) { + $ok = true; + } + fclose($out); + proc_close($fpm); +} +if (!$ok) { + die("skip No apparmor support built in"); +} + +?> diff --git a/sapi/fpm/tests/skipif.inc b/sapi/fpm/tests/skipif.inc new file mode 100644 index 0000000000..8c569daafd --- /dev/null +++ b/sapi/fpm/tests/skipif.inc @@ -0,0 +1,13 @@ +<?php + +if (substr(PHP_OS, 0, 3) == 'WIN') { + die ("skip not for Windows"); +} + +include dirname(__FILE__)."/include.inc"; + +if (!get_fpm_path()) { + die("skip FPM not found"); +} + +?> diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index deb7be6e2b..e7f841c0bc 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -653,8 +653,11 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; } } else { - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; - zend_bailout(); + /* we quit remote consoles on recv SIGINT */ + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + zend_bailout(); + } } } /* }}} */ @@ -1198,17 +1201,17 @@ phpdbg_main: } zend_end_try(); /* initialize from file */ + PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { - PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); - PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; - } zend_catch { - PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { - goto phpdbg_out; - } } zend_end_try(); + PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; + + /* quit if init says so */ + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + goto phpdbg_out; + } /* step from here, not through init */ if (step) { @@ -1235,39 +1238,46 @@ phpdbg_interact: phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); fclose(bp_tmp_fp); cleaning = 1; - goto phpdbg_out; } else { cleaning = 0; } -#ifndef _WIN32 - /* remote client disconnected */ - if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { - /* renegociate connections */ - phpdbg_open_sockets( - address, listen, &server, &socket, streams); +#ifndef _WIN32 + if (!cleaning) { + /* remote client disconnected */ + if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { - /* set streams */ - if (streams[0] && streams[1]) { - PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + /* renegociate connections */ + phpdbg_open_sockets( + address, listen, &server, &socket, streams); + + /* set streams */ + if (streams[0] && streams[1]) { + PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; + } + + /* this must be forced */ + CG(unclean_shutdown) = 0; + } else { + /* local consoles cannot disconnect, ignore EOF */ + PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; + } } - - /* this must be forced */ - CG(unclean_shutdown) = 0; } #endif - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { - goto phpdbg_out; - } } zend_end_try(); - } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); /* this must be forced */ CG(unclean_shutdown) = 0; + /* this is just helpful */ + PG(report_memleaks) = 0; + phpdbg_out: #ifndef _WIN32 - if (PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED) { + if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; goto phpdbg_interact; } @@ -1316,7 +1326,7 @@ phpdbg_out: if (cleaning || remote) { goto phpdbg_main; } - + #ifdef ZTS /* bugggy */ /* tsrm_shutdown(); */ diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 66b4f69957..6b7afb2370 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -149,7 +149,7 @@ #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ #define PHPDBG_URL "http://phpdbg.com" #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.3.0" +#define PHPDBG_VERSION "0.3.1" #define PHPDBG_INIT_FILENAME ".phpdbginit" /* }}} */ diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index 36a9d26dc2..c700851243 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -459,6 +459,9 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { phpdbg_input_t *buffer = NULL; char *cmd = NULL; +#ifndef HAVE_LIBREADLINE + char buf[PHPDBG_MAX_CMD]; +#endif if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && @@ -467,32 +470,42 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ } if (buffered == NULL) { -#ifndef HAVE_LIBREADLINE - char buf[PHPDBG_MAX_CMD]; - if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) || - !fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - /* the user has gone away */ - phpdbg_error("Failed to read console!"); +disconnect: + if (0) { PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); zend_bailout(); return NULL; } +#ifndef HAVE_LIBREADLINE + if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) { + goto disconnect; + } + } + + /* note: EOF is ignored */ +readline: + if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { + /* the user has gone away */ + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + goto disconnect; + } else goto readline; + } + cmd = buf; #else + /* note: EOF makes readline write prompt again in local console mode */ +readline: if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { char buf[PHPDBG_MAX_CMD]; if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { cmd = buf; - } else cmd = NULL; + } else goto disconnect; } else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); if (!cmd) { - /* the user has gone away */ - phpdbg_error("Failed to read console!"); - PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); - zend_bailout(); - return NULL; + goto readline; } if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c index 7e64d16d92..50073eb22b 100644 --- a/sapi/phpdbg/phpdbg_opcode.c +++ b/sapi/phpdbg/phpdbg_opcode.c @@ -52,13 +52,15 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint case IS_VAR: case IS_TMP_VAR: { zend_ulong id = 0, *pid = NULL; - if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { - id = zend_hash_num_elements(vars); - zend_hash_index_update( - vars, (zend_ulong) ops->vars - op->var, - (void**) &id, - sizeof(zend_ulong), NULL); - } else id = *pid; + if (vars != NULL) { + if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { + id = zend_hash_num_elements(vars); + zend_hash_index_update( + vars, (zend_ulong) ops->vars - op->var, + (void**) &id, + sizeof(zend_ulong), NULL); + } else id = *pid; + } asprintf(&decode, "@%lu", id); } break; diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index bb26556f5c..cb46407957 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -551,7 +551,8 @@ PHPDBG_COMMAND(run) /* {{{ */ zend_op **orig_opline = EG(opline_ptr); zend_op_array *orig_op_array = EG(active_op_array); zval **orig_retval_ptr = EG(return_value_ptr_ptr); - + zend_bool restore = 1; + if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec)); @@ -586,18 +587,19 @@ PHPDBG_COMMAND(run) /* {{{ */ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { phpdbg_error("Caught exit/error from VM"); - goto out; + restore = 0; } } zend_end_try(); - if (EG(exception)) { - phpdbg_handle_exception(TSRMLS_C); - } - - EG(active_op_array) = orig_op_array; - EG(opline_ptr) = orig_opline; - EG(return_value_ptr_ptr) = orig_retval_ptr; + if (restore) { + if (EG(exception)) { + phpdbg_handle_exception(TSRMLS_C); + } + EG(active_op_array) = orig_op_array; + EG(opline_ptr) = orig_opline; + EG(return_value_ptr_ptr) = orig_retval_ptr; + } } else { phpdbg_error("Nothing to execute!"); } diff --git a/tests/lang/operators/bitwiseShiftLeft_variationStr.phpt b/tests/lang/operators/bitwiseShiftLeft_variationStr.phpt index b1bc437b0f..e13fc3bc1b 100644 --- a/tests/lang/operators/bitwiseShiftLeft_variationStr.phpt +++ b/tests/lang/operators/bitwiseShiftLeft_variationStr.phpt @@ -1,421 +1,421 @@ ---TEST--
-Test << operator : various numbers as strings
---SKIPIF--
-<?php
-if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
-?>
---FILE--
-<?php
-
-$strVals = array(
- "0","65","-44", "1.2", "-7.7", "abc", "123abc", "123e5", "123e5xyz", " 123abc", "123 abc", "123abc ", "3.4a",
- "a5.9"
-);
-
-error_reporting(E_ERROR);
-
-foreach ($strVals as $strVal) {
- foreach($strVals as $otherVal) {
- echo "--- testing: '$strVal' << '$otherVal' ---\n";
- var_dump(bin2hex($strVal<<$otherVal));
- }
-}
-
-
-?>
-===DONE===
---EXPECT--
---- testing: '0' << '0' ---
-string(2) "30"
---- testing: '0' << '65' ---
-string(2) "30"
---- testing: '0' << '-44' ---
-string(2) "30"
---- testing: '0' << '1.2' ---
-string(2) "30"
---- testing: '0' << '-7.7' ---
-string(2) "30"
---- testing: '0' << 'abc' ---
-string(2) "30"
---- testing: '0' << '123abc' ---
-string(2) "30"
---- testing: '0' << '123e5' ---
-string(2) "30"
---- testing: '0' << '123e5xyz' ---
-string(2) "30"
---- testing: '0' << ' 123abc' ---
-string(2) "30"
---- testing: '0' << '123 abc' ---
-string(2) "30"
---- testing: '0' << '123abc ' ---
-string(2) "30"
---- testing: '0' << '3.4a' ---
-string(2) "30"
---- testing: '0' << 'a5.9' ---
-string(2) "30"
---- testing: '65' << '0' ---
-string(4) "3635"
---- testing: '65' << '65' ---
-string(6) "313330"
---- testing: '65' << '-44' ---
-string(16) "3638313537343430"
---- testing: '65' << '1.2' ---
-string(6) "313330"
---- testing: '65' << '-7.7' ---
-string(22) "2d32313133393239323136"
---- testing: '65' << 'abc' ---
-string(4) "3635"
---- testing: '65' << '123abc' ---
-string(18) "313334323137373238"
---- testing: '65' << '123e5' ---
-string(18) "313334323137373238"
---- testing: '65' << '123e5xyz' ---
-string(18) "313334323137373238"
---- testing: '65' << ' 123abc' ---
-string(18) "313334323137373238"
---- testing: '65' << '123 abc' ---
-string(18) "313334323137373238"
---- testing: '65' << '123abc ' ---
-string(18) "313334323137373238"
---- testing: '65' << '3.4a' ---
-string(6) "353230"
---- testing: '65' << 'a5.9' ---
-string(4) "3635"
---- testing: '-44' << '0' ---
-string(6) "2d3434"
---- testing: '-44' << '65' ---
-string(6) "2d3838"
---- testing: '-44' << '-44' ---
-string(18) "2d3436313337333434"
---- testing: '-44' << '1.2' ---
-string(6) "2d3838"
---- testing: '-44' << '-7.7' ---
-string(22) "2d31343736333935303038"
---- testing: '-44' << 'abc' ---
-string(6) "2d3434"
---- testing: '-44' << '123abc' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << '123e5' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << '123e5xyz' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << ' 123abc' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << '123 abc' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << '123abc ' ---
-string(22) "2d31363130363132373336"
---- testing: '-44' << '3.4a' ---
-string(8) "2d333532"
---- testing: '-44' << 'a5.9' ---
-string(6) "2d3434"
---- testing: '1.2' << '0' ---
-string(2) "31"
---- testing: '1.2' << '65' ---
-string(2) "32"
---- testing: '1.2' << '-44' ---
-string(14) "31303438353736"
---- testing: '1.2' << '1.2' ---
-string(2) "32"
---- testing: '1.2' << '-7.7' ---
-string(16) "3333353534343332"
---- testing: '1.2' << 'abc' ---
-string(2) "31"
---- testing: '1.2' << '123abc' ---
-string(18) "313334323137373238"
---- testing: '1.2' << '123e5' ---
-string(18) "313334323137373238"
---- testing: '1.2' << '123e5xyz' ---
-string(18) "313334323137373238"
---- testing: '1.2' << ' 123abc' ---
-string(18) "313334323137373238"
---- testing: '1.2' << '123 abc' ---
-string(18) "313334323137373238"
---- testing: '1.2' << '123abc ' ---
-string(18) "313334323137373238"
---- testing: '1.2' << '3.4a' ---
-string(2) "38"
---- testing: '1.2' << 'a5.9' ---
-string(2) "31"
---- testing: '-7.7' << '0' ---
-string(4) "2d37"
---- testing: '-7.7' << '65' ---
-string(6) "2d3134"
---- testing: '-7.7' << '-44' ---
-string(16) "2d37333430303332"
---- testing: '-7.7' << '1.2' ---
-string(6) "2d3134"
---- testing: '-7.7' << '-7.7' ---
-string(20) "2d323334383831303234"
---- testing: '-7.7' << 'abc' ---
-string(4) "2d37"
---- testing: '-7.7' << '123abc' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << '123e5' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << '123e5xyz' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << ' 123abc' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << '123 abc' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << '123abc ' ---
-string(20) "2d393339353234303936"
---- testing: '-7.7' << '3.4a' ---
-string(6) "2d3536"
---- testing: '-7.7' << 'a5.9' ---
-string(4) "2d37"
---- testing: 'abc' << '0' ---
-string(2) "30"
---- testing: 'abc' << '65' ---
-string(2) "30"
---- testing: 'abc' << '-44' ---
-string(2) "30"
---- testing: 'abc' << '1.2' ---
-string(2) "30"
---- testing: 'abc' << '-7.7' ---
-string(2) "30"
---- testing: 'abc' << 'abc' ---
-string(2) "30"
---- testing: 'abc' << '123abc' ---
-string(2) "30"
---- testing: 'abc' << '123e5' ---
-string(2) "30"
---- testing: 'abc' << '123e5xyz' ---
-string(2) "30"
---- testing: 'abc' << ' 123abc' ---
-string(2) "30"
---- testing: 'abc' << '123 abc' ---
-string(2) "30"
---- testing: 'abc' << '123abc ' ---
-string(2) "30"
---- testing: 'abc' << '3.4a' ---
-string(2) "30"
---- testing: 'abc' << 'a5.9' ---
-string(2) "30"
---- testing: '123abc' << '0' ---
-string(6) "313233"
---- testing: '123abc' << '65' ---
-string(6) "323436"
---- testing: '123abc' << '-44' ---
-string(18) "313238393734383438"
---- testing: '123abc' << '1.2' ---
-string(6) "323436"
---- testing: '123abc' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: '123abc' << 'abc' ---
-string(6) "313233"
---- testing: '123abc' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: '123abc' << '3.4a' ---
-string(6) "393834"
---- testing: '123abc' << 'a5.9' ---
-string(6) "313233"
---- testing: '123e5' << '0' ---
-string(6) "313233"
---- testing: '123e5' << '65' ---
-string(6) "323436"
---- testing: '123e5' << '-44' ---
-string(18) "313238393734383438"
---- testing: '123e5' << '1.2' ---
-string(6) "323436"
---- testing: '123e5' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: '123e5' << 'abc' ---
-string(6) "313233"
---- testing: '123e5' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: '123e5' << '3.4a' ---
-string(6) "393834"
---- testing: '123e5' << 'a5.9' ---
-string(6) "313233"
---- testing: '123e5xyz' << '0' ---
-string(6) "313233"
---- testing: '123e5xyz' << '65' ---
-string(6) "323436"
---- testing: '123e5xyz' << '-44' ---
-string(18) "313238393734383438"
---- testing: '123e5xyz' << '1.2' ---
-string(6) "323436"
---- testing: '123e5xyz' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: '123e5xyz' << 'abc' ---
-string(6) "313233"
---- testing: '123e5xyz' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: '123e5xyz' << '3.4a' ---
-string(6) "393834"
---- testing: '123e5xyz' << 'a5.9' ---
-string(6) "313233"
---- testing: ' 123abc' << '0' ---
-string(6) "313233"
---- testing: ' 123abc' << '65' ---
-string(6) "323436"
---- testing: ' 123abc' << '-44' ---
-string(18) "313238393734383438"
---- testing: ' 123abc' << '1.2' ---
-string(6) "323436"
---- testing: ' 123abc' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: ' 123abc' << 'abc' ---
-string(6) "313233"
---- testing: ' 123abc' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: ' 123abc' << '3.4a' ---
-string(6) "393834"
---- testing: ' 123abc' << 'a5.9' ---
-string(6) "313233"
---- testing: '123 abc' << '0' ---
-string(6) "313233"
---- testing: '123 abc' << '65' ---
-string(6) "323436"
---- testing: '123 abc' << '-44' ---
-string(18) "313238393734383438"
---- testing: '123 abc' << '1.2' ---
-string(6) "323436"
---- testing: '123 abc' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: '123 abc' << 'abc' ---
-string(6) "313233"
---- testing: '123 abc' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: '123 abc' << '3.4a' ---
-string(6) "393834"
---- testing: '123 abc' << 'a5.9' ---
-string(6) "313233"
---- testing: '123abc ' << '0' ---
-string(6) "313233"
---- testing: '123abc ' << '65' ---
-string(6) "323436"
---- testing: '123abc ' << '-44' ---
-string(18) "313238393734383438"
---- testing: '123abc ' << '1.2' ---
-string(6) "323436"
---- testing: '123abc ' << '-7.7' ---
-string(20) "2d313637373732313630"
---- testing: '123abc ' << 'abc' ---
-string(6) "313233"
---- testing: '123abc ' << '123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << '123e5' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << '123e5xyz' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << ' 123abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << '123 abc' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << '123abc ' ---
-string(20) "2d363731303838363430"
---- testing: '123abc ' << '3.4a' ---
-string(6) "393834"
---- testing: '123abc ' << 'a5.9' ---
-string(6) "313233"
---- testing: '3.4a' << '0' ---
-string(2) "33"
---- testing: '3.4a' << '65' ---
-string(2) "36"
---- testing: '3.4a' << '-44' ---
-string(14) "33313435373238"
---- testing: '3.4a' << '1.2' ---
-string(2) "36"
---- testing: '3.4a' << '-7.7' ---
-string(18) "313030363633323936"
---- testing: '3.4a' << 'abc' ---
-string(2) "33"
---- testing: '3.4a' << '123abc' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << '123e5' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << '123e5xyz' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << ' 123abc' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << '123 abc' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << '123abc ' ---
-string(18) "343032363533313834"
---- testing: '3.4a' << '3.4a' ---
-string(4) "3234"
---- testing: '3.4a' << 'a5.9' ---
-string(2) "33"
---- testing: 'a5.9' << '0' ---
-string(2) "30"
---- testing: 'a5.9' << '65' ---
-string(2) "30"
---- testing: 'a5.9' << '-44' ---
-string(2) "30"
---- testing: 'a5.9' << '1.2' ---
-string(2) "30"
---- testing: 'a5.9' << '-7.7' ---
-string(2) "30"
---- testing: 'a5.9' << 'abc' ---
-string(2) "30"
---- testing: 'a5.9' << '123abc' ---
-string(2) "30"
---- testing: 'a5.9' << '123e5' ---
-string(2) "30"
---- testing: 'a5.9' << '123e5xyz' ---
-string(2) "30"
---- testing: 'a5.9' << ' 123abc' ---
-string(2) "30"
---- testing: 'a5.9' << '123 abc' ---
-string(2) "30"
---- testing: 'a5.9' << '123abc ' ---
-string(2) "30"
---- testing: 'a5.9' << '3.4a' ---
-string(2) "30"
---- testing: 'a5.9' << 'a5.9' ---
-string(2) "30"
-===DONE===
-
+--TEST-- +Test << operator : various numbers as strings +--SKIPIF-- +<?php +if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); +if ((65<<65)==0) die("skip this test is for Intel only"); +?> +--FILE-- +<?php + +$strVals = array( + "0","65","-44", "1.2", "-7.7", "abc", "123abc", "123e5", "123e5xyz", " 123abc", "123 abc", "123abc ", "3.4a", + "a5.9" +); + +error_reporting(E_ERROR); + +foreach ($strVals as $strVal) { + foreach($strVals as $otherVal) { + echo "--- testing: '$strVal' << '$otherVal' ---\n"; + var_dump(bin2hex($strVal<<$otherVal)); + } +} + +?> +===DONE=== +--EXPECT-- +--- testing: '0' << '0' --- +string(2) "30" +--- testing: '0' << '65' --- +string(2) "30" +--- testing: '0' << '-44' --- +string(2) "30" +--- testing: '0' << '1.2' --- +string(2) "30" +--- testing: '0' << '-7.7' --- +string(2) "30" +--- testing: '0' << 'abc' --- +string(2) "30" +--- testing: '0' << '123abc' --- +string(2) "30" +--- testing: '0' << '123e5' --- +string(2) "30" +--- testing: '0' << '123e5xyz' --- +string(2) "30" +--- testing: '0' << ' 123abc' --- +string(2) "30" +--- testing: '0' << '123 abc' --- +string(2) "30" +--- testing: '0' << '123abc ' --- +string(2) "30" +--- testing: '0' << '3.4a' --- +string(2) "30" +--- testing: '0' << 'a5.9' --- +string(2) "30" +--- testing: '65' << '0' --- +string(4) "3635" +--- testing: '65' << '65' --- +string(6) "313330" +--- testing: '65' << '-44' --- +string(16) "3638313537343430" +--- testing: '65' << '1.2' --- +string(6) "313330" +--- testing: '65' << '-7.7' --- +string(22) "2d32313133393239323136" +--- testing: '65' << 'abc' --- +string(4) "3635" +--- testing: '65' << '123abc' --- +string(18) "313334323137373238" +--- testing: '65' << '123e5' --- +string(18) "313334323137373238" +--- testing: '65' << '123e5xyz' --- +string(18) "313334323137373238" +--- testing: '65' << ' 123abc' --- +string(18) "313334323137373238" +--- testing: '65' << '123 abc' --- +string(18) "313334323137373238" +--- testing: '65' << '123abc ' --- +string(18) "313334323137373238" +--- testing: '65' << '3.4a' --- +string(6) "353230" +--- testing: '65' << 'a5.9' --- +string(4) "3635" +--- testing: '-44' << '0' --- +string(6) "2d3434" +--- testing: '-44' << '65' --- +string(6) "2d3838" +--- testing: '-44' << '-44' --- +string(18) "2d3436313337333434" +--- testing: '-44' << '1.2' --- +string(6) "2d3838" +--- testing: '-44' << '-7.7' --- +string(22) "2d31343736333935303038" +--- testing: '-44' << 'abc' --- +string(6) "2d3434" +--- testing: '-44' << '123abc' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << '123e5' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << '123e5xyz' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << ' 123abc' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << '123 abc' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << '123abc ' --- +string(22) "2d31363130363132373336" +--- testing: '-44' << '3.4a' --- +string(8) "2d333532" +--- testing: '-44' << 'a5.9' --- +string(6) "2d3434" +--- testing: '1.2' << '0' --- +string(2) "31" +--- testing: '1.2' << '65' --- +string(2) "32" +--- testing: '1.2' << '-44' --- +string(14) "31303438353736" +--- testing: '1.2' << '1.2' --- +string(2) "32" +--- testing: '1.2' << '-7.7' --- +string(16) "3333353534343332" +--- testing: '1.2' << 'abc' --- +string(2) "31" +--- testing: '1.2' << '123abc' --- +string(18) "313334323137373238" +--- testing: '1.2' << '123e5' --- +string(18) "313334323137373238" +--- testing: '1.2' << '123e5xyz' --- +string(18) "313334323137373238" +--- testing: '1.2' << ' 123abc' --- +string(18) "313334323137373238" +--- testing: '1.2' << '123 abc' --- +string(18) "313334323137373238" +--- testing: '1.2' << '123abc ' --- +string(18) "313334323137373238" +--- testing: '1.2' << '3.4a' --- +string(2) "38" +--- testing: '1.2' << 'a5.9' --- +string(2) "31" +--- testing: '-7.7' << '0' --- +string(4) "2d37" +--- testing: '-7.7' << '65' --- +string(6) "2d3134" +--- testing: '-7.7' << '-44' --- +string(16) "2d37333430303332" +--- testing: '-7.7' << '1.2' --- +string(6) "2d3134" +--- testing: '-7.7' << '-7.7' --- +string(20) "2d323334383831303234" +--- testing: '-7.7' << 'abc' --- +string(4) "2d37" +--- testing: '-7.7' << '123abc' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << '123e5' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << '123e5xyz' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << ' 123abc' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << '123 abc' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << '123abc ' --- +string(20) "2d393339353234303936" +--- testing: '-7.7' << '3.4a' --- +string(6) "2d3536" +--- testing: '-7.7' << 'a5.9' --- +string(4) "2d37" +--- testing: 'abc' << '0' --- +string(2) "30" +--- testing: 'abc' << '65' --- +string(2) "30" +--- testing: 'abc' << '-44' --- +string(2) "30" +--- testing: 'abc' << '1.2' --- +string(2) "30" +--- testing: 'abc' << '-7.7' --- +string(2) "30" +--- testing: 'abc' << 'abc' --- +string(2) "30" +--- testing: 'abc' << '123abc' --- +string(2) "30" +--- testing: 'abc' << '123e5' --- +string(2) "30" +--- testing: 'abc' << '123e5xyz' --- +string(2) "30" +--- testing: 'abc' << ' 123abc' --- +string(2) "30" +--- testing: 'abc' << '123 abc' --- +string(2) "30" +--- testing: 'abc' << '123abc ' --- +string(2) "30" +--- testing: 'abc' << '3.4a' --- +string(2) "30" +--- testing: 'abc' << 'a5.9' --- +string(2) "30" +--- testing: '123abc' << '0' --- +string(6) "313233" +--- testing: '123abc' << '65' --- +string(6) "323436" +--- testing: '123abc' << '-44' --- +string(18) "313238393734383438" +--- testing: '123abc' << '1.2' --- +string(6) "323436" +--- testing: '123abc' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: '123abc' << 'abc' --- +string(6) "313233" +--- testing: '123abc' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: '123abc' << '3.4a' --- +string(6) "393834" +--- testing: '123abc' << 'a5.9' --- +string(6) "313233" +--- testing: '123e5' << '0' --- +string(6) "313233" +--- testing: '123e5' << '65' --- +string(6) "323436" +--- testing: '123e5' << '-44' --- +string(18) "313238393734383438" +--- testing: '123e5' << '1.2' --- +string(6) "323436" +--- testing: '123e5' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: '123e5' << 'abc' --- +string(6) "313233" +--- testing: '123e5' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: '123e5' << '3.4a' --- +string(6) "393834" +--- testing: '123e5' << 'a5.9' --- +string(6) "313233" +--- testing: '123e5xyz' << '0' --- +string(6) "313233" +--- testing: '123e5xyz' << '65' --- +string(6) "323436" +--- testing: '123e5xyz' << '-44' --- +string(18) "313238393734383438" +--- testing: '123e5xyz' << '1.2' --- +string(6) "323436" +--- testing: '123e5xyz' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: '123e5xyz' << 'abc' --- +string(6) "313233" +--- testing: '123e5xyz' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: '123e5xyz' << '3.4a' --- +string(6) "393834" +--- testing: '123e5xyz' << 'a5.9' --- +string(6) "313233" +--- testing: ' 123abc' << '0' --- +string(6) "313233" +--- testing: ' 123abc' << '65' --- +string(6) "323436" +--- testing: ' 123abc' << '-44' --- +string(18) "313238393734383438" +--- testing: ' 123abc' << '1.2' --- +string(6) "323436" +--- testing: ' 123abc' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: ' 123abc' << 'abc' --- +string(6) "313233" +--- testing: ' 123abc' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: ' 123abc' << '3.4a' --- +string(6) "393834" +--- testing: ' 123abc' << 'a5.9' --- +string(6) "313233" +--- testing: '123 abc' << '0' --- +string(6) "313233" +--- testing: '123 abc' << '65' --- +string(6) "323436" +--- testing: '123 abc' << '-44' --- +string(18) "313238393734383438" +--- testing: '123 abc' << '1.2' --- +string(6) "323436" +--- testing: '123 abc' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: '123 abc' << 'abc' --- +string(6) "313233" +--- testing: '123 abc' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: '123 abc' << '3.4a' --- +string(6) "393834" +--- testing: '123 abc' << 'a5.9' --- +string(6) "313233" +--- testing: '123abc ' << '0' --- +string(6) "313233" +--- testing: '123abc ' << '65' --- +string(6) "323436" +--- testing: '123abc ' << '-44' --- +string(18) "313238393734383438" +--- testing: '123abc ' << '1.2' --- +string(6) "323436" +--- testing: '123abc ' << '-7.7' --- +string(20) "2d313637373732313630" +--- testing: '123abc ' << 'abc' --- +string(6) "313233" +--- testing: '123abc ' << '123abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << '123e5' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << '123e5xyz' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << ' 123abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << '123 abc' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << '123abc ' --- +string(20) "2d363731303838363430" +--- testing: '123abc ' << '3.4a' --- +string(6) "393834" +--- testing: '123abc ' << 'a5.9' --- +string(6) "313233" +--- testing: '3.4a' << '0' --- +string(2) "33" +--- testing: '3.4a' << '65' --- +string(2) "36" +--- testing: '3.4a' << '-44' --- +string(14) "33313435373238" +--- testing: '3.4a' << '1.2' --- +string(2) "36" +--- testing: '3.4a' << '-7.7' --- +string(18) "313030363633323936" +--- testing: '3.4a' << 'abc' --- +string(2) "33" +--- testing: '3.4a' << '123abc' --- +string(18) "343032363533313834" +--- testing: '3.4a' << '123e5' --- +string(18) "343032363533313834" +--- testing: '3.4a' << '123e5xyz' --- +string(18) "343032363533313834" +--- testing: '3.4a' << ' 123abc' --- +string(18) "343032363533313834" +--- testing: '3.4a' << '123 abc' --- +string(18) "343032363533313834" +--- testing: '3.4a' << '123abc ' --- +string(18) "343032363533313834" +--- testing: '3.4a' << '3.4a' --- +string(4) "3234" +--- testing: '3.4a' << 'a5.9' --- +string(2) "33" +--- testing: 'a5.9' << '0' --- +string(2) "30" +--- testing: 'a5.9' << '65' --- +string(2) "30" +--- testing: 'a5.9' << '-44' --- +string(2) "30" +--- testing: 'a5.9' << '1.2' --- +string(2) "30" +--- testing: 'a5.9' << '-7.7' --- +string(2) "30" +--- testing: 'a5.9' << 'abc' --- +string(2) "30" +--- testing: 'a5.9' << '123abc' --- +string(2) "30" +--- testing: 'a5.9' << '123e5' --- +string(2) "30" +--- testing: 'a5.9' << '123e5xyz' --- +string(2) "30" +--- testing: 'a5.9' << ' 123abc' --- +string(2) "30" +--- testing: 'a5.9' << '123 abc' --- +string(2) "30" +--- testing: 'a5.9' << '123abc ' --- +string(2) "30" +--- testing: 'a5.9' << '3.4a' --- +string(2) "30" +--- testing: 'a5.9' << 'a5.9' --- +string(2) "30" +===DONE=== + diff --git a/tests/lang/operators/bitwiseShiftLeft_variationStr2.phpt b/tests/lang/operators/bitwiseShiftLeft_variationStr2.phpt new file mode 100644 index 0000000000..09949c56b0 --- /dev/null +++ b/tests/lang/operators/bitwiseShiftLeft_variationStr2.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test << operator : numbers as strings, simple +--FILE-- +<?php + +error_reporting(E_ERROR); + +var_dump("12" << "0"); +var_dump("34" << "1"); +var_dump("56" << "2"); + +?> +===DONE=== +--EXPECT-- +int(12) +int(68) +int(224) +===DONE=== diff --git a/tests/lang/operators/bitwiseShiftRight_variationStr.phpt b/tests/lang/operators/bitwiseShiftRight_variationStr.phpt index 9518d42cdc..ad53fea9d1 100644 --- a/tests/lang/operators/bitwiseShiftRight_variationStr.phpt +++ b/tests/lang/operators/bitwiseShiftRight_variationStr.phpt @@ -1,26 +1,30 @@ ---TEST--
-Test >> operator : various numbers as strings
---FILE--
-<?php
-
-$strVals = array(
- "0","65","-44", "1.2", "-7.7", "abc", "123abc", "123e5", "123e5xyz", " 123abc", "123 abc", "123abc ", "3.4a",
- "a5.9"
-);
-
-error_reporting(E_ERROR);
-
-foreach ($strVals as $strVal) {
- foreach($strVals as $otherVal) {
- echo "--- testing: '$strVal' >> '$otherVal' ---\n";
- var_dump(bin2hex($strVal>>$otherVal));
- }
-}
-
-
-?>
-===DONE===
---EXPECT--
+--TEST-- +Test >> operator : various numbers as strings +--SKIPIF-- +<?php +if ((65<<65)==0) die("skip this test is for Intel only"); +?> +--FILE-- +<?php + +$strVals = array( + "0","65","-44", "1.2", "-7.7", "abc", "123abc", "123e5", "123e5xyz", " 123abc", "123 abc", "123abc ", "3.4a", + "a5.9" +); + +error_reporting(E_ERROR); + +foreach ($strVals as $strVal) { + foreach($strVals as $otherVal) { + echo "--- testing: '$strVal' >> '$otherVal' ---\n"; + var_dump(bin2hex($strVal>>$otherVal)); + } +} + + +?> +===DONE=== +--EXPECT-- --- testing: '0' >> '0' --- string(2) "30" --- testing: '0' >> '65' --- @@ -412,5 +416,5 @@ string(2) "30" --- testing: 'a5.9' >> '3.4a' --- string(2) "30" --- testing: 'a5.9' >> 'a5.9' --- -string(2) "30"
-===DONE===
+string(2) "30" +===DONE=== diff --git a/tests/lang/operators/bitwiseShiftRight_variationStr2.phpt b/tests/lang/operators/bitwiseShiftRight_variationStr2.phpt new file mode 100644 index 0000000000..db90e1b338 --- /dev/null +++ b/tests/lang/operators/bitwiseShiftRight_variationStr2.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test >> operator : numbers as strings, simple +--FILE-- +<?php + +error_reporting(E_ERROR); + +var_dump("12" >> "0"); +var_dump("34" >> "1"); +var_dump("56" >> "2"); + +?> +===DONE=== +--EXPECT-- +int(12) +int(17) +int(14) +===DONE=== diff --git a/tests/security/open_basedir_linkinfo.phpt b/tests/security/open_basedir_linkinfo.phpt index f8be45305e..55cf2c2f4b 100644 --- a/tests/security/open_basedir_linkinfo.phpt +++ b/tests/security/open_basedir_linkinfo.phpt @@ -41,6 +41,7 @@ test_open_basedir_after("linkinfo"); ?> --CLEAN-- <?php +chdir(__DIR__); require_once "open_basedir.inc"; delete_directories(); ?> diff --git a/tests/security/open_basedir_readlink.phpt b/tests/security/open_basedir_readlink.phpt index b102ee9d9c..33720bbf1b 100644 --- a/tests/security/open_basedir_readlink.phpt +++ b/tests/security/open_basedir_readlink.phpt @@ -37,6 +37,7 @@ test_open_basedir_after("readlink"); ?> --CLEAN-- <?php +chdir(__DIR__); require_once "open_basedir.inc"; delete_directories(); ?> diff --git a/win32/build/confutils.js b/win32/build/confutils.js index d9a0c1b5f1..e0df4f621b 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -47,6 +47,7 @@ VC_VERSIONS[1400] = 'MSVC8 (Visual C++ 2005)'; VC_VERSIONS[1500] = 'MSVC9 (Visual C++ 2008)';
VC_VERSIONS[1600] = 'MSVC10 (Visual C++ 2010)';
VC_VERSIONS[1700] = 'MSVC11 (Visual C++ 2012)';
+VC_VERSIONS[1800] = 'MSVC12 (Visual C++ 2013)';
var VC_VERSIONS_SHORT = new Array();
VC_VERSIONS_SHORT[1200] = 'VC6';
@@ -56,6 +57,7 @@ VC_VERSIONS_SHORT[1400] = 'VC8'; VC_VERSIONS_SHORT[1500] = 'VC9';
VC_VERSIONS_SHORT[1600] = 'VC10';
VC_VERSIONS_SHORT[1700] = 'VC11';
+VC_VERSIONS_SHORT[1800] = 'VC12';
if (PROGRAM_FILES == null) {
PROGRAM_FILES = "C:\\Program Files";
diff --git a/win32/glob.c b/win32/glob.c index 1aeac78fda..8111daba1c 100644 --- a/win32/glob.c +++ b/win32/glob.c @@ -61,9 +61,16 @@ * Number of matches in the current invocation of glob. */ #ifdef PHP_WIN32 -#define _POSIX_ -#include <limits.h> -#undef _POSIX_ +#if _MSC_VER < 1800 +# define _POSIX_ +# include <limits.h> +# undef _POSIX_ +#else +/* Visual Studio 2013 removed all the _POSIX_ defines, but we depend on some */ +# ifndef ARG_MAX +# define ARG_MAX 14500 +# endif +#endif #ifndef S_ISDIR #define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR) #endif |