diff options
author | Jakub Zelenka <bukka@php.net> | 2016-02-29 19:28:40 +0000 |
---|---|---|
committer | Jakub Zelenka <bukka@php.net> | 2016-02-29 19:28:40 +0000 |
commit | 80015ba741fc857074050086db6c7b2a4716d6d5 (patch) | |
tree | 9e0b85868c092ae83a0df2bd4f33f79ba773aab2 | |
parent | 4ea2a0fd60cdf75d746909198ea69f1e3e4ba193 (diff) | |
parent | 31dc08a904f2a91b582396b6ba118abfd12cf246 (diff) | |
download | php-git-80015ba741fc857074050086db6c7b2a4716d6d5.tar.gz |
Merge branch 'PHP-7.0' into openssl_error_store
164 files changed, 2876 insertions, 1073 deletions
diff --git a/CODING_STANDARDS b/CODING_STANDARDS index 0cfcff18f6..a3b9d2b7d3 100644 --- a/CODING_STANDARDS +++ b/CODING_STANDARDS @@ -178,7 +178,7 @@ Internal Function Naming Convensions Unexposed module function should be static and should not be defined in 'php_modulename.h'. - static int php_session_destroy(TSRMLS_D) + static int php_session_destroy() 2. Main module source file must be named 'modulename.c'. diff --git a/Makefile.global b/Makefile.global index c571f3455d..9b29d5112b 100644 --- a/Makefile.global +++ b/Makefile.global @@ -53,7 +53,7 @@ install-headers: paths="$$paths $(INSTALL_ROOT)$(phpincludedir)/$$i"; \ done; \ $(mkinstalldirs) $$paths && \ - echo "Installing header files: $(INSTALL_ROOT)$(phpincludedir)/" && \ + echo "Installing header files: $(INSTALL_ROOT)$(phpincludedir)/" && \ for i in `echo $(INSTALL_HEADERS)`; do \ if test "$(PHP_PECL_EXTENSION)"; then \ src=`echo $$i | $(SED) -e "s#ext/$(PHP_PECL_EXTENSION)/##g"`; \ @@ -1,9 +1,51 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? 2016 PHP 7.0.4 +?? ??? 2016 PHP 7.0.5 - Core: - . Fixed bug #71485 (Return typehint on interanal func causes Fatal error + . Fixed bug #71629 (Out-of-bounds access in php_url_decode in context + php_stream_url_wrap_rfc2397). (mt at debian dot org) + . Fixed bug #71622 (Strings used in pass-as-reference cannot be used to + invoke C::$callable()). (Bob) + . Fixed bug #71596 (Segmentation fault on ZTS with date function + (setlocale)). (Anatol) + . Fixed bug #71535 (Integer overflow in zend_mm_alloc_heap()). (Dmitry) + . Fixed bug #71470 (Leaked 1 hashtable iterators). (Nikita) + +- libxml: + . Fixed bug #71536 (Access Violation crashes php-cgi.exe). (Anatol) + +- ODBC: + . Fixed bug #47803, #69526 (Executing prepared statements is succesfull only + for the first two statements). (einavitamar at gmail dot com, Anatol) + +- PDO_DBlib: + . Bug #54648 (PDO::MSSQL forces format of datetime fields). + (steven dot lambeth at gmx dot de, Anatol) + +- Phar: + . Fixed bug #71625 (Crash in php7.dll with bad phar filename). + (Anatol) + +- phpdbg: + . Fixed crash when advancing (except step) inside an internal function. (Bob) + +- SPL: + . Fixed bug #71617 (private properties lost when unserializing ArrayObject). + (Nikita) + +- Standard: + . Fixed bug #71660 (array_column behaves incorrectly after foreach by + reference). (Laruence) + +- Zip: + . Update bundled libzip to 1.1.2. (Remi, Anatol) + +?? Mar 2016 PHP 7.0.4 + +- Core: + . Fixed bug (Low probability segfault in zend_arena). (Laruence) + . Fixed bug #71485 (Return typehint on internal func causes Fatal error when it throws exception). (Laruence) . Fixed bug #71474 (Crash because of VM stack corruption on Magento2). (Dmitry) @@ -14,23 +56,58 @@ PHP NEWS . Fixed bug #71442 (forward_static_call crash). (Laruence) . Fixed bug #71441 (Typehinted Generator with return in try/finally crashes). (Bob) + . Fixed bug #71529 (Variable references on array elements don't work when + using count). (Nikita) + . Fixed bug #71601 (finally block not executed after yield from). (Bob) + +- CLI server: + . Fixed bug #71559 (Built-in HTTP server, we can download file in web by bug). + (Johannes, Anatol) + +- CURL: + . Fixed bug #71523 (Copied handle with new option CURLOPT_HTTPHEADER crashes + while curl_multi_exec). (Laruence) + . Fixed memory leak in curl_getinfo(). (Leigh) + +- Date: + . Fixed bug #71525 (Calls to date_modify will mutate timelib_rel_time, + causing date_date_set issues). (Sean DuBois) - Fileinfo: . Fixed bug #71434 (finfo throws notice for specific python file). (Laruence) - FPM: - . Fixed bug #62172 (FPM not working with Apache httpd 2.4 balancer/fcgi setup). - (Matt Haught, Remi) + . Fixed bug #62172 (FPM not working with Apache httpd 2.4 balancer/fcgi + setup). (Matt Haught, Remi) + . Fixed bug #71269 (php-fpm dumped core). (Mickaël) + +- Opcache: + . Fixed bug #71584 (Possible use-after-free of ZCG(cwd) in Zend Opcache). + (Yussuf Khalil) + +- PCRE: + . Fixed bug #71537 (PCRE segfault from Opcache). (Laruence) + +- phpdbg: + . Fixed inherited functions from unspecified files being included in + phpdbg_get_executable(). (Bob) - Standard: + . Fixed bug #71603 (compact() maintains references in php7). (Laruence) . Fixed bug #70720 (strip_tags improper php code parsing). (Julien) +- XMLRPC: + . Fixed bug #71501 (xmlrpc_encode_request ignores encoding option). (Hieu Le) + +- Zip: + . Fixed bug #71561 (NULL pointer dereference in Zip::ExtractTo). (Laruence) + 04 Feb 2016 PHP 7.0.3 - Core: . Added support for new HTTP 451 code. (Julien) - . Fixed bug #71039 (exec functions ignore length but look for NULL termination). - (Anatol) + . Fixed bug #71039 (exec functions ignore length but look for NULL + termination). (Anatol) . Fixed bug #71089 (No check to duplicate zend_extension). (Remi) . Fixed bug #71201 (round() segfault on 64-bit builds). (Anatol) . Fixed bug #71221 (Null pointer deref (segfault) in get_defined_vars via @@ -57,6 +134,9 @@ PHP NEWS . Fixed bug #71225 (curl_setopt() fails to set CURLOPT_POSTFIELDS with reference to CURLFile). (Laruence) +- GD: + . Improved fix for bug #70976. (Remi) + - Interbase: . Fixed Bug #71305 (Crash when optional resource is omitted). (Laruence, Anatol) @@ -71,6 +151,9 @@ PHP NEWS - OpenSSL: . Fixed bug #71475 (openssl_seal() uninitialized memory usage). (Stas) +- PCRE: + . Upgraded pcrelib to 8.38. + - Phar: . Fixed bug #71354 (Heap corruption in tar/zip/phar parser). (Stas) . Fixed bug #71391 (NULL Pointer Dereference in phar_tar_setupmetadata()). @@ -142,10 +225,6 @@ PHP NEWS - Filter: . Fixed bug #71063 (filter_input(INPUT_ENV, ..) does not work). (Reeze Xia) -- GD: - . Fixed bug #70976 (Memory Read via gdImageRotateInterpolated Array Index - Out of Bounds). (emmanuel dot law at gmail dot com). - - FPM: . Fixed bug #70755 (fpm_log.c memory leak and buffer overflow). (Stas) @@ -153,6 +232,10 @@ PHP NEWS . Implemented FR #55651 (Option to ignore the returned FTP PASV address). (abrender at elitehosts dot com) +- GD: + . Fixed bug #70976 (Memory Read via gdImageRotateInterpolated Array Index + Out of Bounds). (emmanuel dot law at gmail dot com) + - Mbstring: . Fixed bug #71066 (mb_send_mail: Program terminated with signal SIGSEGV, Segmentation fault). (Laruence) @@ -182,12 +265,12 @@ PHP NEWS (emmanuel dot law at gmail dot com) - WDDX: - . Fixed bug #70661 (Use After Free Vulnerability in WDDX Packet Deserialization). - (taoguangchen at icloud dot com) + . Fixed bug #70661 (Use After Free Vulnerability in WDDX Packet + Deserialization). (taoguangchen at icloud dot com) . Fixed bug #70741 (Session WDDX Packet Deserialization Type Confusion Vulnerability). (taoguangchen at icloud dot com) -- XMLRPC +- XMLRPC: . Fixed bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker). (Julien) diff --git a/README.EXT_SKEL b/README.EXT_SKEL index fdf7ad0e90..5ac48ec4fa 100644 --- a/README.EXT_SKEL +++ b/README.EXT_SKEL @@ -172,7 +172,7 @@ PHP_FUNCTION(module_name_drawtext) zval *image = NULL; zval *font = NULL; - if (zend_parse_parameters(argc TSRMLS_CC, "rsrll|l", &image, &text, &text_len, &font, &x, &y, &color) == FAILURE) + if (zend_parse_parameters(argc, "rsrll|l", &image, &text, &text_len, &font, &x, &y, &color) == FAILURE) return; if (image) { diff --git a/README.NEW-OUTPUT-API b/README.NEW-OUTPUT-API index c43649a837..fa4ace05a9 100644 --- a/README.NEW-OUTPUT-API +++ b/README.NEW-OUTPUT-API @@ -8,98 +8,98 @@ API adjustment to the old output control code: Checking output control layers status: // Using OG() - php_output_get_status(TSRMLS_C); + php_output_get_status(); Starting the default output handler: - // php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC); - php_output_start_default(TSRMLS_C); + // php_start_ob_buffer(NULL, 0, 1); + php_output_start_default(); Starting an user handler by zval: - // php_start_ob_buffer(zhandler, chunk_size, erase TSRMLS_CC); - php_output_start_user(zhandler, chunk_size, flags TSRMLS_CC); + // php_start_ob_buffer(zhandler, chunk_size, erase); + php_output_start_user(zhandler, chunk_size, flags); Starting an internal handler whithout context: - // php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase TSRMLS_CC); - php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags TSRMLS_CC); + // php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase); + php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags); Starting an internal handler with context: // not possible with old API php_output_handler *h; - h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags TSRMLS_CC); + h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags); php_output_handler_set_context(h, my_context, my_context_dtor); - php_output_handler_start(h TSRMLS_CC); + php_output_handler_start(h); Testing whether a certain output handler has already been started: - // php_ob_handler_used("output handler name" TSRMLS_CC); - php_output_handler_started(handler_name, handler_name_len TSRMLS_CC); + // php_ob_handler_used("output handler name"); + php_output_handler_started(handler_name, handler_name_len); Flushing one output buffer: - // php_end_ob_buffer(1, 1 TSRMLS_CC); - php_output_flush(TSRMLS_C); + // php_end_ob_buffer(1, 1); + php_output_flush(); Flushing all output buffers: // not possible with old API - php_output_flush_all(TSRMLS_C); + php_output_flush_all(); Cleaning one output buffer: - // php_ob_end_buffer(0, 1 TSRMLS_CC); - php_output_clean(TSRMLS_C); + // php_ob_end_buffer(0, 1); + php_output_clean(); Cleaning all output buffers: // not possible with old API - php_output_clean_all(TSRMLS_C); + php_output_clean_all(); Discarding one output buffer: - // php_ob_end_buffer(0, 0 TSRMLS_CC); - php_output_discard(TSRMLS_C); + // php_ob_end_buffer(0, 0); + php_output_discard(); Discarding all output buffers: - // php_ob_end_buffers(0 TSRMLS_CC); - php_output_discard_all(TSRMLS_C); + // php_ob_end_buffers(0); + php_output_discard_all(); Stopping (and dropping) one output buffer: - // php_ob_end_buffer(1, 0 TSRMLS_CC) - php_output_end(TSRMLS_C); + // php_ob_end_buffer(1, 0) + php_output_end(); Stopping (and dropping) all output buffers: - // php_ob_end_buffers(1, 0 TSRMLS_CC); - php_output_end_all(TSRMLS_C); + // php_ob_end_buffers(1, 0); + php_output_end_all(); Retrieving output buffers contents: - // php_ob_get_buffer(zstring TSRMLS_CC); - php_output_get_contents(zstring TSRMLS_CC); + // php_ob_get_buffer(zstring); + php_output_get_contents(zstring); Retrieving output buffers length: - // php_ob_get_length(zlength TSRMLS_CC); - php_output_get_length(zlength TSRMLS_CC); + // php_ob_get_length(zlength); + php_output_get_length(zlength); Retrieving output buffering level: // OG(nesting_level); - php_output_get_level(TSRMLS_C); + php_output_get_level(); Issue a warning because of an output handler conflict: - // php_ob_init_conflict("to be started handler name", "to be tested if already started handler name" TSRMLS_CC); - php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len TSRMLS_CC); + // php_ob_init_conflict("to be started handler name", "to be tested if already started handler name"); + php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len); Registering a conflict checking function, which will be checked prior starting the handler: // not possible with old API, unless hardcoding into output.c - php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t TSRMLS_CC); + php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t); Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler: // not possible with old API - php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t TSRMLS_CC); + php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t); Facilitating a context from within an output handler callable with ob_start(): // not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr TSRMLS_CC); + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr); Disabling of the output handler by itself: //not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL TSRMLS_CC); + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL); Marking an output handler immutable by itself because of irreversibility of its operation: // not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC); + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL); Restarting the output handler because of a CLEAN operation: // not possible with old API diff --git a/README.PARAMETER_PARSING_API b/README.PARAMETER_PARSING_API index 097b4978a5..c344817b37 100644 --- a/README.PARAMETER_PARSING_API +++ b/README.PARAMETER_PARSING_API @@ -13,8 +13,8 @@ meaningful error messages. Prototypes ---------- /* Implemented. */ -int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...); -int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...); +int zend_parse_parameters(int num_args, char *type_spec, ...); +int zend_parse_parameters_ex(int flags, int num_args, char *type_spec, ...); The zend_parse_parameters() function takes the number of parameters passed to the extension function, the type specifier string, and the @@ -30,7 +30,7 @@ resources cannot be auto-converted. PHP 5.5 includes a new function: -int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...); +int zend_parse_parameter(int flags, int arg_num, zval **arg, const char *spec, ...); This function behaves like zend_parse_parameters_ex() except that instead of reading the arguments from the stack, it receives a single zval to convert @@ -97,11 +97,11 @@ Both mistakes might cause memory corruptions and segfaults: 1) char *str; long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */ - zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) + zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) 2) int num; /* XXX THIS IS WRONG!! Use zend_long instead. */ - zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &num) + zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num) If you're in doubt, use check_parameters.php script to the parameters and their types (it can be found in ./scripts/dev/ directory of PHP sources): @@ -116,7 +116,7 @@ zend_long l; char *s; size_t s_len; zval *param; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz", +if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsz", &l, &s, &s_len, ¶m) == FAILURE) { return; } @@ -126,7 +126,7 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz", zval *obj; double d = 0.5; zend_class_entry *my_ce; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d", +if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|d", &obj, my_ce, &d) == FAILURE) { return; } @@ -136,7 +136,7 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d", If null is passed for object, obj will be set to NULL. */ zval *obj; zval *arr; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a", +if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", &obj, &arr) == FAILURE) { return; } @@ -144,7 +144,7 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a", /* Gets a separated array which can also be null. */ zval *arr; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", +if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", &arr) == FAILURE) { return; } @@ -161,10 +161,10 @@ char *s; */ size_t length; -if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, +if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "lll", &l1, &l2, &l3) == SUCCESS) { /* manipulate longs */ -} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, +} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s", &s, &length) == SUCCESS) { /* manipulate string */ } else { @@ -180,7 +180,7 @@ int i, num_varargs; zval *varargs = NULL; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &varargs, &num_varargs) == FAILURE) { +if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &varargs, &num_varargs) == FAILURE) { return; } @@ -200,7 +200,7 @@ size_t str_len; int i, num_varargs; zval *varargs = NULL; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) { +if (zend_parse_parameters(ZEND_NUM_ARGS(), "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) { return; } @@ -214,7 +214,7 @@ zval *array; int i, num_varargs; zval *varargs = NULL; -if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) { +if (zend_parse_parameters(ZEND_NUM_ARGS(), "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) { return; } diff --git a/README.REDIST.BINS b/README.REDIST.BINS index 968c3ec0c8..9779827534 100644 --- a/README.REDIST.BINS +++ b/README.REDIST.BINS @@ -5,17 +5,16 @@ 5. ext/standard crypt 6. ext/standard crypt's blowfish implementation 7. Sqlite/Sqlite3 ext/sqlite3 ext/sqlite -8. ext/json/json_parser -9. ext/standard/rand -10. ext/standard/scanf -11. ext/standard/strnatcmp.c -12. ext/standard/uuencode -13. libxmlrpc ext/xmlrpc -14. libzip ext/zip -15. main/snprintf.c -16. main/strlcat -17. main/strlcpy -18. libgd see ext/gd/libgd/COPYING +8. ext/standard/rand +9. ext/standard/scanf +10. ext/standard/strnatcmp.c +11. ext/standard/uuencode +12. libxmlrpc ext/xmlrpc +13. libzip ext/zip +14. main/snprintf.c +15. main/strlcat +16. main/strlcpy +17. libgd see ext/gd/libgd/COPYING 5. ext/standard crypt @@ -104,31 +103,7 @@ a legal notice, here is a blessing: May you share freely, never taking more than you give. -8. ext/json/json_parser -Copyright (c) 2005 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -9. ext/standard/rand +8. ext/standard/rand The following php_mt_...() functions are based on a C++ class MTRand by Richard J. Wagner. For more information see the web page at http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html @@ -181,7 +156,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -10. ext/standard/scanf +9. ext/standard/scanf scanf.c -- This file contains the base code which implements sscanf and by extension @@ -227,7 +202,7 @@ authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. -11. ext/standard/strnatcmp.c +10. ext/standard/strnatcmp.c strnatcmp.c -- Perform 'natural order' comparisons of strings in C. Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au> @@ -248,7 +223,7 @@ freely, subject to the following restrictions: misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. -12. ext/standard/uuencode +11. ext/standard/uuencode Portions of this code are based on Berkeley's uuencode/uudecode implementation. @@ -284,7 +259,7 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -13. libxmlrpc ext/xmlrpc +12. libxmlrpc ext/xmlrpc Copyright 2000 Epinions, Inc. @@ -308,7 +283,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. -14. libzip ext/zip +13. libzip ext/zip zip.h -- exported declarations. Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner @@ -340,7 +315,7 @@ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -15. main/snprintf.c +14. main/snprintf.c Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com> Permission to use, copy, modify, and distribute this software for any @@ -413,8 +388,8 @@ This code is based on, and used with the permission of, the SIO stdio-replacement strx_* functions by Panos Tsirigotis <panos@alumni.cs.colorado.edu> for xinetd. -16. main/strlcat -17. main/strlcpy +15. main/strlcat +16. main/strlcpy Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> All rights reserved. diff --git a/README.STREAMS b/README.STREAMS index 0046e6a754..e95950bde0 100644 --- a/README.STREAMS +++ b/README.STREAMS @@ -28,7 +28,7 @@ The main functions are: PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count); PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t count); -PHPAPI size_t php_stream_printf(php_stream * stream TSRMLS_DC, +PHPAPI size_t php_stream_printf(php_stream * stream, const char * fmt, ...); PHPAPI int php_stream_eof(php_stream * stream); PHPAPI int php_stream_getc(php_stream * stream); @@ -47,7 +47,7 @@ Opening Streams In most cases, you should use this API: PHPAPI php_stream *php_stream_open_wrapper(const char *path, const char *mode, - int options, char **opened_path TSRMLS_DC); + int options, char **opened_path); Where: path is the file or resource to open. @@ -80,7 +80,7 @@ PHPAPI php_stream *php_stream_fopen_tmpfile(void); Open a FILE * with tmpfile() and convert into a stream. PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir, - const char *pfx, char **opened_path TSRMLS_DC); + const char *pfx, char **opened_path); Generate a temporary file name and open it. There are some network enabled relatives in php_network.h: diff --git a/README.input_filter b/README.input_filter index 78e2edd2ec..be260013ac 100644 --- a/README.input_filter +++ b/README.input_filter @@ -138,7 +138,7 @@ SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) strcpy(raw_var, "RAW_"); strlcat(raw_var,var,var_len+5); - php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); + php_register_variable_ex(raw_var, &new_var, array_ptr); php_strip_tags(*val, val_len, NULL, NULL, 0); @@ -154,7 +154,7 @@ PHP_FUNCTION(my_get_raw) zval **tmp; zval *array_ptr = NULL; - if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { + if(zend_parse_parameters(2, "ls", &arg, &var, &var_len) == FAILURE) { return; } diff --git a/Zend/tests/bug69989_1.phpt b/Zend/tests/bug69989_1.phpt new file mode 100644 index 0000000000..816c55410e --- /dev/null +++ b/Zend/tests/bug69989_1.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #69989: Cycle collection for yielded values +--FILE-- +<?php + +function gen() { + yield yield; +} +$gen = gen(); +$gen->send($gen); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/bug71470.phpt b/Zend/tests/bug71470.phpt new file mode 100644 index 0000000000..6f8b4f0103 --- /dev/null +++ b/Zend/tests/bug71470.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #71470: Leaked 1 hashtable iterators +--FILE-- +<?php + +$array = [1, 2, 3]; +foreach ($array as &$v) { + die("foo\n"); +} + +?> +--EXPECT-- +foo diff --git a/Zend/tests/bug71529.phpt b/Zend/tests/bug71529.phpt new file mode 100644 index 0000000000..5a5e323414 --- /dev/null +++ b/Zend/tests/bug71529.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #71529: Variable references on array elements don't work when using count +--FILE-- +<?php + +$a = [1]; +$a[] = &$a[out(count($a) - 1)]; +var_dump($a); + +function out($what) { + var_dump($what); + return $what; +} + +?> +--EXPECT-- +int(0) +array(2) { + [0]=> + &int(1) + [1]=> + &int(1) +} diff --git a/Zend/tests/bug71622.phpt b/Zend/tests/bug71622.phpt new file mode 100644 index 0000000000..3ef0ba80e1 --- /dev/null +++ b/Zend/tests/bug71622.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #71622 (Strings used in pass-as-reference cannot be used to invoke C::$callable()) +--FILE-- +<?php + +function getMethodName(&$methodName) { + $methodName = Abc::METHOD_NAME; +} + +class Abc { + const METHOD_NAME = "goal"; + + private static function goal() { + echo "success\n"; + } + + public static function run() { + $method = "foobar"; + getMethodName($method); + var_dump(is_callable("self::$method")); + self::$method(); + } +} + +Abc::run(); + +?> +--EXPECT-- +bool(true) +success diff --git a/Zend/tests/foreach_017.phpt b/Zend/tests/foreach_017.phpt index 55eeeb0891..e27b04c934 100644 --- a/Zend/tests/foreach_017.phpt +++ b/Zend/tests/foreach_017.phpt @@ -45,7 +45,7 @@ $done = 0; $a = [0,1,2,3,4]; foreach($a as &$v) { echo "$v\n"; - if ($done && $v == 3) { + if (!$done && $v == 3) { $done = 1; array_splice($a, 1, 2, $replacement); } diff --git a/Zend/tests/generators/bug71601.phpt b/Zend/tests/generators/bug71601.phpt new file mode 100644 index 0000000000..e3f21692e7 --- /dev/null +++ b/Zend/tests/generators/bug71601.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #71601 (finally block not executed after yield from) +--FILE-- +<?php + +function gen1() { + try { + yield 1; + yield 2; + return true; + } finally { + echo "Inner finally\n"; + } +} + +function gen2() { + try { + echo "Entered try/catch\n"; + var_dump(yield from gen1()); + } finally { + echo "Finally\n"; + } +} + +$generator = gen2(); + +var_dump($generator->current()); + +unset($generator); + +echo "Done\n"; + +?> +--EXPECT-- +Entered try/catch +int(1) +Inner finally +Finally +Done + diff --git a/Zend/tests/generators/dangling_send_target.phpt b/Zend/tests/generators/dangling_send_target.phpt new file mode 100644 index 0000000000..c62c24a2f5 --- /dev/null +++ b/Zend/tests/generators/dangling_send_target.phpt @@ -0,0 +1,22 @@ +--TEST-- +Yield from does not leave a dangling send target +--FILE-- +<?php +function gen1() { + yield from [yield]; +} + +$gen = gen1(); +$gen->send(new stdClass); + +function gen2() { + $x = yield; + yield from [1, 2, 3]; +} +$gen = gen2(); +$gen->send(new stdClass); +$gen->send(new stdClass); +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/generators/yield_from_by_reference.phpt b/Zend/tests/generators/yield_from_by_reference.phpt new file mode 100644 index 0000000000..8412a32af5 --- /dev/null +++ b/Zend/tests/generators/yield_from_by_reference.phpt @@ -0,0 +1,12 @@ +--TEST-- +Yield from by reference is not supported +--FILE-- +<?php + +function &gen() { + yield from []; +} + +?> +--EXPECTF-- +Fatal error: Cannot use "yield from" inside a by-reference generator in %s on line %d diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 91fb09161e..a7d19f9892 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1226,8 +1226,15 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) size_t prop_name_len; if (zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len) == SUCCESS) { zend_string *pname = zend_string_init(prop_name, prop_name_len, 0); + zend_class_entry *prev_scope = EG(scope); + if (class_name && class_name[0] != '*') { + zend_string *cname = zend_string_init(class_name, strlen(class_name), 0); + EG(scope) = zend_lookup_class(cname); + zend_string_release(cname); + } property_info = zend_get_property_info(object->ce, pname, 1); zend_string_release(pname); + EG(scope) = prev_scope; } else { property_info = ZEND_WRONG_PROPERTY_INFO; } @@ -1638,7 +1645,7 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ result = zend_symtable_update(ht, ZSTR_EMPTY_ALLOC(), value); break; case IS_RESOURCE: - zend_error(E_NOTICE, "Resource ID#" ZEND_LONG_FMT " used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key)); + zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key)); result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value); break; case IS_FALSE: diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index cfc277f136..2e0de26378 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -1353,6 +1353,10 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si /* special handling for zero-size allocation */ size = MAX(size, 1); size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { + zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } #endif if (size <= ZEND_MM_MAX_SMALL_SIZE) { ptr = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); diff --git a/Zend/zend_arena.h b/Zend/zend_arena.h index 7456610b65..e89e06b1b0 100644 --- a/Zend/zend_arena.h +++ b/Zend/zend_arena.h @@ -103,11 +103,12 @@ static zend_always_inline void zend_arena_release(zend_arena **arena_ptr, void * zend_arena *arena = *arena_ptr; while (UNEXPECTED((char*)checkpoint > arena->end) || - UNEXPECTED((char*)checkpoint < (char*)arena)) { + UNEXPECTED((char*)checkpoint <= (char*)arena)) { zend_arena *prev = arena->prev; efree(arena); *arena_ptr = arena = prev; } + ZEND_ASSERT((char*)checkpoint > (char*)arena && (char*)checkpoint <= arena->end); arena->ptr = (char*)checkpoint; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 1c30b98a9f..56da2962bd 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2589,14 +2589,17 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */ znode target_node, source_node; zend_op *opline; + uint32_t offset; if (is_this_fetch(target_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); } zend_ensure_writable_variable(target_ast); - zend_compile_var(&target_node, target_ast, BP_VAR_W); - zend_compile_var(&source_node, source_ast, BP_VAR_REF); + offset = zend_delayed_compile_begin(); + zend_delayed_compile_var(&target_node, target_ast, BP_VAR_W); + zend_delayed_compile_var(&source_node, source_ast, BP_VAR_REF); + zend_delayed_compile_end(offset); if (source_node.op_type != IS_VAR && zend_is_call(source_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context"); @@ -6291,6 +6294,11 @@ void zend_compile_yield_from(znode *result, zend_ast *ast) /* {{{ */ zend_mark_function_as_generator(); + if (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use \"yield from\" inside a by-reference generator"); + } + zend_compile_expr(&expr_node, expr_ast); zend_emit_op_tmp(result, ZEND_YIELD_FROM, &expr_node, NULL); } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 0c6f0377da..56ad4366ff 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -398,7 +398,7 @@ void shutdown_executor(void) /* {{{ */ zend_shutdown_fpu(); #ifdef ZEND_DEBUG - if (EG(ht_iterators_used)) { + if (EG(ht_iterators_used) && !CG(unclean_shutdown)) { zend_error(E_WARNING, "Leaked %" PRIu32 " hashtable iterators", EG(ht_iterators_used)); } #endif diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 4861e45919..646e46b676 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -35,11 +35,6 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato { zend_execute_data *execute_data = generator->execute_data; - if (generator->send_target) { - Z_TRY_DELREF_P(generator->send_target); - generator->send_target = NULL; - } - if (execute_data->opline != execute_data->func->op_array.opcodes) { /* -1 required because we want the last run opcode, not the next to-be-run one. */ uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1; @@ -65,11 +60,6 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution) /* {{{ */ { - if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) { - zval_ptr_dtor(&generator->values); - ZVAL_UNDEF(&generator->values); - } - if (EXPECTED(generator->execute_data)) { zend_execute_data *execute_data = generator->execute_data; @@ -109,6 +99,8 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished } /* }}} */ +static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf); + static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ { zend_generator *generator = (zend_generator*) object; @@ -116,6 +108,22 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ uint32_t op_num, finally_op_num, finally_op_end; int i; + /* leave yield from mode to properly allow finally execution */ + if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) { + zval_ptr_dtor(&generator->values); + ZVAL_UNDEF(&generator->values); + } + + if (EXPECTED(generator->node.children == 0)) { + zend_generator *root = generator->node.ptr.root, *next; + while (UNEXPECTED(root != generator)) { + next = zend_generator_get_child(&root->node, generator); + OBJ_RELEASE(&root->std); + root = next; + } + generator->node.parent = NULL; + } + if (EXPECTED(!ex) || EXPECTED(!(ex->func->op_array.fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK))) { return; } @@ -156,8 +164,6 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ } /* }}} */ -static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf); - static void zend_generator_free_storage(zend_object *object) /* {{{ */ { zend_generator *generator = (zend_generator*) object; @@ -181,15 +187,15 @@ static void zend_generator_free_storage(zend_object *object) /* {{{ */ if (generator->iterator) { zend_iterator_dtor(generator->iterator); } +} +/* }}} */ - if (EXPECTED(generator->node.children == 0)) { - zend_generator *root = generator->node.ptr.root, *next; - while (UNEXPECTED(root != generator)) { - next = zend_generator_get_child(&root->node, generator); - OBJ_RELEASE(&root->std); - root = next; - } - } +static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {{{ */ +{ + zend_generator *generator = (zend_generator*) Z_OBJ_P(object); + *table = &generator->value; + *n = 3; + return NULL; } /* }}} */ @@ -873,7 +879,6 @@ ZEND_METHOD(Generator, send) root = zend_generator_get_current(generator); /* Put sent value in the target VAR slot, if it is used */ if (root->send_target) { - Z_TRY_DELREF_P(root->send_target); ZVAL_COPY(root->send_target, value); } @@ -1128,6 +1133,7 @@ void zend_register_generator_ce(void) /* {{{ */ memcpy(&zend_generator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); zend_generator_handlers.free_obj = zend_generator_free_storage; zend_generator_handlers.dtor_obj = zend_generator_dtor_storage; + zend_generator_handlers.get_gc = zend_generator_get_gc; zend_generator_handlers.clone_obj = NULL; zend_generator_handlers.get_constructor = zend_generator_get_constructor; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 11cd2416bf..23aa3f3afd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2944,7 +2944,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR } } if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP2(); HANDLE_EXCEPTION(); @@ -3053,15 +3053,22 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE function_name = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP2_TYPE != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (OP2_TYPE & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); - FREE_OP2(); - HANDLE_EXCEPTION(); + zend_throw_error(NULL, "Function name must be a string"); + FREE_OP2(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -7316,7 +7323,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE value = GET_OP1_ZVAL_PTR(BP_VAR_R); ZVAL_COPY_VALUE(&generator->value, value); - if (OP1_TYPE != IS_CONST) { + if (OP1_TYPE == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -7503,6 +7510,9 @@ ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY) ZVAL_NULL(EX_VAR(opline->result.var)); } + /* This generator has no send target (though the generator we delegate to might have one) */ + generator->send_target = NULL; + /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ ZEND_VM_INC_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6f4406967c..e181246ede 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4183,6 +4183,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER( ZVAL_NULL(EX_VAR(opline->result.var)); } + /* This generator has no send target (though the generator we delegate to might have one) */ + generator->send_target = NULL; + /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ ZEND_VM_INC_OPCODE(); @@ -5537,7 +5540,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CO } } if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -5644,15 +5647,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C function_name = EX_CONSTANT(opline->op2); if (IS_CONST != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_CONST & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -6529,7 +6539,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER value = EX_CONSTANT(opline->op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CONST != IS_CONST) { + if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -6706,7 +6716,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(Z value = EX_CONSTANT(opline->op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CONST != IS_CONST) { + if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -7248,7 +7258,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(Z value = EX_CONSTANT(opline->op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CONST != IS_CONST) { + if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -7625,15 +7635,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C function_name = NULL; if (IS_UNUSED != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_UNUSED & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -8139,7 +8156,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLE value = EX_CONSTANT(opline->op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CONST != IS_CONST) { + if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -9261,7 +9278,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV } } if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -9368,15 +9385,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C function_name = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); if (IS_CV != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_CV & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -9980,7 +10004,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZE value = EX_CONSTANT(opline->op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CONST != IS_CONST) { + if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -11068,7 +11092,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TM } } if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); @@ -11176,15 +11200,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); - zval_ptr_dtor_nogc(free_op2); - HANDLE_EXCEPTION(); + zend_throw_error(NULL, "Function name must be a string"); + zval_ptr_dtor_nogc(free_op2); + HANDLE_EXCEPTION(); + } while (0); } } @@ -12517,6 +12548,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_TMP_HANDLER(ZE ZVAL_NULL(EX_VAR(opline->result.var)); } + /* This generator has no send target (though the generator we delegate to might have one) */ + generator->send_target = NULL; + /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ ZEND_VM_INC_OPCODE(); @@ -13006,7 +13040,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(Z value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_TMP_VAR != IS_CONST) { + if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -13183,7 +13217,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEN value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_TMP_VAR != IS_CONST) { + if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -13360,7 +13394,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEN value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_TMP_VAR != IS_CONST) { + if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -13730,7 +13764,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER( value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_TMP_VAR != IS_CONST) { + if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -14279,7 +14313,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_TMP_VAR != IS_CONST) { + if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -16335,6 +16369,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_VAR_HANDLER(ZE ZVAL_NULL(EX_VAR(opline->result.var)); } + /* This generator has no send target (though the generator we delegate to might have one) */ + generator->send_target = NULL; + /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ ZEND_VM_INC_OPCODE(); @@ -17507,15 +17544,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V function_name = EX_CONSTANT(opline->op2); if (IS_CONST != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_CONST & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -18010,7 +18054,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(Z value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_VAR != IS_CONST) { + if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -18216,7 +18260,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEN value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_VAR != IS_CONST) { + if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -18482,7 +18526,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEN value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_VAR != IS_CONST) { + if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -19135,15 +19179,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V function_name = NULL; if (IS_UNUSED != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_UNUSED & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -19464,7 +19515,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER( value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_VAR != IS_CONST) { + if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -20756,15 +20807,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V function_name = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); if (IS_CV != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if (IS_CV & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); + zend_throw_error(NULL, "Function name must be a string"); - HANDLE_EXCEPTION(); + HANDLE_EXCEPTION(); + } while (0); } } @@ -21152,7 +21210,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_VAR != IS_CONST) { + if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -22326,15 +22384,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { - GET_OP2_UNDEF_CV(function_name, BP_VAR_R); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + do { + if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV) && Z_ISREF_P(function_name)) { + function_name = Z_REFVAL_P(function_name); + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + break; + } + } else if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(function_name) == IS_UNDEF)) { + GET_OP2_UNDEF_CV(function_name, BP_VAR_R); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } } - } - zend_throw_error(NULL, "Function name must be a string"); - zval_ptr_dtor_nogc(free_op2); - HANDLE_EXCEPTION(); + zend_throw_error(NULL, "Function name must be a string"); + zval_ptr_dtor_nogc(free_op2); + HANDLE_EXCEPTION(); + } while (0); } } @@ -23727,7 +23792,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C } } if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -24287,7 +24352,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLE value = NULL; ZVAL_COPY_VALUE(&generator->value, value); - if (IS_UNUSED != IS_CONST) { + if (IS_UNUSED == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -24428,7 +24493,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER( value = NULL; ZVAL_COPY_VALUE(&generator->value, value); - if (IS_UNUSED != IS_CONST) { + if (IS_UNUSED == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -24569,7 +24634,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER( value = NULL; ZVAL_COPY_VALUE(&generator->value, value); - if (IS_UNUSED != IS_CONST) { + if (IS_UNUSED == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -25108,7 +25173,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDL value = NULL; ZVAL_COPY_VALUE(&generator->value, value); - if (IS_UNUSED != IS_CONST) { + if (IS_UNUSED == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -26142,7 +26207,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C } } if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -26595,7 +26660,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(Z value = NULL; ZVAL_COPY_VALUE(&generator->value, value); - if (IS_UNUSED != IS_CONST) { + if (IS_UNUSED == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -27634,7 +27699,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T } } if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); @@ -29665,6 +29730,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CV_HANDLER(ZEN ZVAL_NULL(EX_VAR(opline->result.var)); } + /* This generator has no send target (though the generator we delegate to might have one) */ + generator->send_target = NULL; + /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ ZEND_VM_INC_OPCODE(); @@ -31889,7 +31957,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST } } if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -32731,7 +32799,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZE value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CV != IS_CONST) { + if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -33027,7 +33095,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CV != IS_CONST) { + if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -33700,7 +33768,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CV != IS_CONST) { + if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -34895,7 +34963,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(Z value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CV != IS_CONST) { + if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -36965,7 +37033,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA } } if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -37583,7 +37651,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_ value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); ZVAL_COPY_VALUE(&generator->value, value); - if (IS_CV != IS_CONST) { + if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) { zval_copy_ctor_func(&generator->value); } @@ -39537,7 +39605,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA } } if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); @@ -41764,7 +41832,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C } } if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -43904,7 +43972,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C } } if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); @@ -45042,7 +45110,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T } } if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(object, BP_VAR_R); + object = GET_OP1_UNDEF_CV(object, BP_VAR_R); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); diff --git a/configure.in b/configure.in index 906534f224..11dca36755 100644 --- a/configure.in +++ b/configure.in @@ -119,7 +119,7 @@ int zend_sprintf(char *buffer, const char *format, ...); PHP_MAJOR_VERSION=7 PHP_MINOR_VERSION=0 -PHP_RELEASE_VERSION=4 +PHP_RELEASE_VERSION=5 PHP_EXTRA_VERSION="-dev" PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION" PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION` diff --git a/ext/curl/interface.c b/ext/curl/interface.c index bd611ce42f..564d9fcb1c 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -157,7 +157,8 @@ static void _php_curl_close(zend_resource *rsrc); #define CAAL(s, v) add_assoc_long_ex(return_value, s, sizeof(s) - 1, (zend_long) v); #define CAAD(s, v) add_assoc_double_ex(return_value, s, sizeof(s) - 1, (double) v); #define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s) - 1, (char *) (v ? v : "")); -#define CAASTR(s, v) add_assoc_str_ex(return_value, s, sizeof(s) - 1, v ? v : ZSTR_EMPTY_ALLOC()); +#define CAASTR(s, v) add_assoc_str_ex(return_value, s, sizeof(s) - 1, \ + v ? zend_string_copy(v) : ZSTR_EMPTY_ALLOC()); #define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s) -1 , (zval *) v); #if defined(PHP_WIN32) || defined(__GNUC__) @@ -2188,7 +2189,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ #endif # if defined(ZTS) if (option == CURLOPT_DNS_USE_GLOBAL_CACHE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "CURLOPT_DNS_USE_GLOBAL_CACHE cannot be activated when thread safety is enabled"); + php_error_docref(NULL, E_WARNING, "CURLOPT_DNS_USE_GLOBAL_CACHE cannot be activated when thread safety is enabled"); return 1; } # endif @@ -2475,7 +2476,11 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ } } ZEND_HASH_FOREACH_END(); - zend_hash_index_update_ptr(ch->to_free->slist, option, slist); + if ((*ch->clone) == 1) { + zend_hash_index_update_ptr(ch->to_free->slist, option, slist); + } else { + zend_hash_next_index_insert_ptr(ch->to_free->slist, slist); + } error = curl_easy_setopt(ch->cp, option, slist); @@ -3032,7 +3037,7 @@ PHP_FUNCTION(curl_getinfo) } #endif if (ch->header.str) { - CAASTR("request_header", zend_string_copy(ch->header.str)); + CAASTR("request_header", ch->header.str); } } else { switch (option) { diff --git a/ext/curl/tests/bug71523.phpt b/ext/curl/tests/bug71523.phpt new file mode 100644 index 0000000000..24aa83c620 --- /dev/null +++ b/ext/curl/tests/bug71523.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #71523 (Copied handle with new option CURLOPT_HTTPHEADER crashes while curl_multi_exec) +--SKIPIF-- +<?php +if (!extension_loaded("curl")) { + exit("skip curl extension not loaded"); +} +if (getenv("SKIP_ONLINE_TESTS")) { + die("skip online test"); +} +?> +--FILE-- +<?php + +$base = curl_init('http://www.google.com/'); +curl_setopt($base, CURLOPT_RETURNTRANSFER, true); +$mh = curl_multi_init(); + +for ($i = 0; $i < 2; ++$i) { + $ch = curl_copy_handle($base); + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Foo: Bar']); + curl_multi_add_handle($mh, $ch); +} + +do { + curl_multi_exec($mh, $active); +} while ($active); +?> +okey +--EXPECTF-- +okey diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 2c548ae6f4..2fe78a0e69 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -3054,6 +3054,7 @@ static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{ timelib_update_ts(dateobj->time, NULL); timelib_update_from_sse(dateobj->time); dateobj->time->have_relative = 0; + memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative)); return 1; } /* }}} */ diff --git a/ext/date/tests/bug71525.phpt b/ext/date/tests/bug71525.phpt new file mode 100644 index 0000000000..d0c99e4f84 --- /dev/null +++ b/ext/date/tests/bug71525.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #71525 (Calls to date_modify will mutate timelib_rel_time, causing date_date_set issues) +--INI-- +date.timezone=UTC +--FILE-- +<?php +$date = new DateTime('2011-12-25 00:00:00'); +$date->modify('first day of next month'); +$date->setDate('2012', '1', '29'); +var_dump($date); + +--EXPECTF-- +object(DateTime)#%d (3) { + ["date"]=> + string(26) "2012-01-29 00:00:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" +} diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index 309258b4c7..4dd6784209 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -424,9 +424,9 @@ static int php_iconv_output_handler(void **nothing, php_output_context *output_c char *p = strstr(get_output_encoding(), "//"); if (p) { - len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (size_t) strlen(mimetype), mimetype, (size_t)(p - get_output_encoding()), get_output_encoding()); + len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int) (p - get_output_encoding()), get_output_encoding()); } else { - len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (size_t) strlen(mimetype), mimetype, get_output_encoding()); + len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, get_output_encoding()); } if (content_type && SUCCESS == sapi_add_header(content_type, (uint)len, 0)) { SG(sapi_headers).send_default_content_type = 0; diff --git a/ext/intl/ERROR.CONVENTIONS b/ext/intl/ERROR.CONVENTIONS index 41cd14ec06..e053c8fbc7 100644 --- a/ext/intl/ERROR.CONVENTIONS +++ b/ext/intl/ERROR.CONVENTIONS @@ -21,9 +21,9 @@ intl.use_exceptions you get more fine-grained information about where the error occurred). The internal PHP code can set the global last error with: -void intl_error_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC); -void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC); -void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC); +void intl_error_set_code(intl_error* err, UErrorCode err_code); +void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg); +void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg); and by passing NULL as the first parameter. The last function is a combination of the first two. If the message is not a static buffer, copyMsg should be 1. @@ -44,9 +44,9 @@ typedef struct { The global error and the object error can be SIMULTANEOUSLY set with these functions: -void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC); -void intl_errors_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC); -void intl_errors_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC); +void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg); +void intl_errors_set_code(intl_error* err, UErrorCode err_code); +void intl_errors_set(intl_error* err, UErrorCode code, char* msg, int copyMsg); by passing a pointer to the object's intl_error structed as the first parameter. Node the extra 's' in the functions' names ('errors', not 'error'). @@ -79,8 +79,8 @@ Errors should be lost after a function call. This is different from the way ICU operates, where functions return immediately if an error is set. Error resetting can be done with: -void intl_error_reset(NULL TSRMLS_DC); /* reset global error */ -void intl_errors_reset(intl_error* err TSRMLS_DC ); /* reset global and object error */ +void intl_error_reset(NULL); /* reset global error */ +void intl_errors_reset(intl_error* err ); /* reset global and object error */ In practice, intl_errors_reset() is not used because most classes have also plain functions mapped to the same internal functions as their instance methods. @@ -97,10 +97,10 @@ U_CFUNC PHP_FUNCTION(breakiter_set_text) BREAKITER_METHOD_INIT_VARS; /* macro also resets global error */ object = getThis(); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &text, &text_len) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, - "breakiter_set_text: bad arguments", 0 TSRMLS_CC); + "breakiter_set_text: bad arguments", 0); RETURN_FALSE; } diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 5b7aca91d8..24812449ee 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -383,6 +383,9 @@ static int php_libxml_streams_IO_read(void *context, char *buffer, int len) static int php_libxml_streams_IO_write(void *context, const char *buffer, int len) { + if (CG(unclean_shutdown)) { + return -1; + } return php_stream_write((php_stream*)context, buffer, len); } diff --git a/ext/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c index 536edde425..456c40ae71 100644 --- a/ext/mcrypt/mcrypt.c +++ b/ext/mcrypt/mcrypt.c @@ -564,7 +564,7 @@ PHP_FUNCTION(mcrypt_generic_init) memset(iv_s, 0, iv_size + 1); if (key_len > max_key_size) { - php_error_docref(NULL, E_WARNING, "Key size too large; supplied length: %d, max: %d", key_len, max_key_size); + php_error_docref(NULL, E_WARNING, "Key size too large; supplied length: %zd, max: %d", key_len, max_key_size); key_size = max_key_size; } else { key_size = (int)key_len; @@ -572,7 +572,7 @@ PHP_FUNCTION(mcrypt_generic_init) memcpy(key_s, key, key_len); if (iv_len != iv_size) { - php_error_docref(NULL, E_WARNING, "Iv size incorrect; supplied length: %d, needed: %d", iv_len, iv_size); + php_error_docref(NULL, E_WARNING, "Iv size incorrect; supplied length: %zd, needed: %d", iv_len, iv_size); if (iv_len > iv_size) { iv_len = iv_size; } diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index a91d7b783d..d835dfb9a0 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -445,6 +445,9 @@ static void _free_odbc_result(zend_resource *rsrc) * zend_list_delete(res->conn_ptr->id); */ } + if (res->param_info) { + efree(res->param_info); + } efree(res); } } @@ -1184,6 +1187,7 @@ PHP_FUNCTION(odbc_prepare) odbc_result *result = NULL; odbc_connection *conn; RETCODE rc; + int i; #ifdef HAVE_SQL_EXTENDED_FETCH SQLUINTEGER scrollopts; #endif @@ -1199,6 +1203,7 @@ PHP_FUNCTION(odbc_prepare) result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); result->numparams = 0; + result->param_info = NULL; rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { @@ -1255,6 +1260,20 @@ PHP_FUNCTION(odbc_prepare) Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; + + result->param_info = (odbc_param_info *) safe_emalloc(sizeof(odbc_param_info), result->numparams, 0); + for (i=0;i<result->numparams;i++) { + rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)(i+1), &result->param_info[i].sqltype, &result->param_info[i].precision, + &result->param_info[i].scale, &result->param_info[i].nullable); + if (rc == SQL_ERROR) { + odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter"); + SQLFreeStmt(result->stmt, SQL_RESET_PARAMS); + efree(result->param_info); + efree(result); + RETURN_FALSE; + } + } + RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -1275,9 +1294,7 @@ PHP_FUNCTION(odbc_execute) params_t *params = NULL; char *filename; unsigned char otype; - SQLSMALLINT sqltype, ctype, scale; - SQLSMALLINT nullable; - SQLULEN precision; + SQLSMALLINT ctype; odbc_result *result; int numArgs, i, ne; RETCODE rc; @@ -1337,22 +1354,10 @@ PHP_FUNCTION(odbc_execute) RETURN_FALSE; } - rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)i, &sqltype, &precision, &scale, &nullable); params[i-1].vallen = Z_STRLEN_P(tmp); params[i-1].fp = -1; - if (rc == SQL_ERROR) { - odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParam"); - SQLFreeStmt(result->stmt, SQL_RESET_PARAMS); - for (i = 0; i < result->numparams; i++) { - if (params[i].fp != -1) { - close(params[i].fp); - } - } - efree(params); - RETURN_FALSE; - } - if (IS_SQL_BINARY(sqltype)) { + if (IS_SQL_BINARY(result->param_info[i-1].sqltype)) { ctype = SQL_C_BINARY; } else { ctype = SQL_C_CHAR; @@ -1399,7 +1404,7 @@ PHP_FUNCTION(odbc_execute) params[i-1].vallen = SQL_LEN_DATA_AT_EXEC(0); rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT, - ctype, sqltype, precision, scale, + ctype, result->param_info[i-1].sqltype, result->param_info[i-1].precision, result->param_info[i-1].scale, (void *)(intptr_t)params[i-1].fp, 0, ¶ms[i-1].vallen); } else { @@ -1411,7 +1416,7 @@ PHP_FUNCTION(odbc_execute) } rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT, - ctype, sqltype, precision, scale, + ctype, result->param_info[i-1].sqltype, result->param_info[i-1].precision, result->param_info[i-1].scale, Z_STRVAL_P(tmp), 0, ¶ms[i-1].vallen); } diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index dad7ff1c95..fa525ed4ad 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -233,6 +233,13 @@ typedef struct odbc_result_value { SQLLEN coltype; } odbc_result_value; +typedef struct odbc_param_info { + SQLSMALLINT sqltype; + SQLSMALLINT scale; + SQLSMALLINT nullable; + SQLULEN precision; +} odbc_param_info; + typedef struct odbc_result { ODBC_SQL_STMT_T stmt; odbc_result_value *values; @@ -244,6 +251,7 @@ typedef struct odbc_result { zend_long longreadlen; int binmode; int fetched; + odbc_param_info * param_info; odbc_connection *conn_ptr; } odbc_result; diff --git a/ext/odbc/tests/bug47803.phpt b/ext/odbc/tests/bug47803.phpt new file mode 100644 index 0000000000..9a2600dd18 --- /dev/null +++ b/ext/odbc/tests/bug47803.phpt @@ -0,0 +1,185 @@ +--TEST-- +Bug #47803 Executing prepared statements is succesfull only for the first two statements +--SKIPIF-- +<?php include 'skipif.inc'; ?> +--FILE-- +<?php + +include dirname(__FILE__) . "/config.inc"; + +$create_table = "CREATE TABLE FOO( + [PAR_ID] [int] NOT NULL, + [PAR_INT] [int] NULL, + [PAR_CHR] [varchar](500) NULL +)"; + +$inserts = "INSERT INTO FOO + ([PAR_ID] + ,[PAR_INT] + ,[PAR_CHR]) + VALUES + (1,14,''), + (2,30,''), + (3,7,''), + (4,7,''), + (5,0,''), + (6,0,''), + (7,20130901,''), + (8,20140201,''), + (9,20140201,''), + (10,20140620,''), + (11,221,'')"; + + +date_default_timezone_set('Europe/Warsaw'); + +$link = odbc_connect($dsn, $user, $pass); + +odbc_exec($link, 'CREATE DATABASE odbcTEST'); +odbc_exec($link, $create_table); +odbc_exec($link, $inserts); + +$upd_params = array( + array('id'=>1, 'name'=>'test 1'), + array('id'=>2, 'name'=>'test 2'), + array('id'=>3, 'name'=>'test 3'), + array('id'=>4, 'name'=>'test 4'), + array('id'=>5, 'name'=>'test 5'), + array('id'=>10, 'name'=>'test 10'), + array('id'=>9, 'name'=>'test 9'), + array('id'=>8, 'name'=>'test 8'), + array('id'=>7, 'name'=>'test 7'), + array('id'=>6, 'name'=>'test 6'), +); +$sql = "UPDATE FOO + SET [PAR_CHR] = ? + WHERE [PAR_ID] = ?"; +$result = odbc_prepare($link, $sql); +if (!$result) { + print ('[sql] prep: '.$sql); + goto out; +} +foreach ($upd_params as &$k) { + if(!odbc_execute($result, array($k['name'], $k['id']))) { + print ('[sql] exec: '."array({$k['name']}, {$k['id']})"); + goto out; + } +} +odbc_free_result($result); + +$sql = "SELECT * FROM FOO WHERE [PAR_ID] = ?"; +$result = odbc_prepare($link, $sql); +if (!$result) { + print ('[sql] prep: '.$sql); + goto out; +} +foreach ($upd_params as $k) { + if(!odbc_execute($result, array($k['id']))) { + print ('[sql] exec: '."array({$k['id']})"); + goto out; + } + while (($r = odbc_fetch_array($result)) !== false) { + var_dump($r); + } +} + +out: +if ($result) odbc_free_result($result); +odbc_close($link); + +?> +==DONE== +--EXPECT-- +array(3) { + ["PAR_ID"]=> + string(1) "1" + ["PAR_INT"]=> + string(2) "14" + ["PAR_CHR"]=> + string(6) "test 1" +} +array(3) { + ["PAR_ID"]=> + string(1) "2" + ["PAR_INT"]=> + string(2) "30" + ["PAR_CHR"]=> + string(6) "test 2" +} +array(3) { + ["PAR_ID"]=> + string(1) "3" + ["PAR_INT"]=> + string(1) "7" + ["PAR_CHR"]=> + string(6) "test 3" +} +array(3) { + ["PAR_ID"]=> + string(1) "4" + ["PAR_INT"]=> + string(1) "7" + ["PAR_CHR"]=> + string(6) "test 4" +} +array(3) { + ["PAR_ID"]=> + string(1) "5" + ["PAR_INT"]=> + string(1) "0" + ["PAR_CHR"]=> + string(6) "test 5" +} +array(3) { + ["PAR_ID"]=> + string(2) "10" + ["PAR_INT"]=> + string(8) "20140620" + ["PAR_CHR"]=> + string(7) "test 10" +} +array(3) { + ["PAR_ID"]=> + string(1) "9" + ["PAR_INT"]=> + string(8) "20140201" + ["PAR_CHR"]=> + string(6) "test 9" +} +array(3) { + ["PAR_ID"]=> + string(1) "8" + ["PAR_INT"]=> + string(8) "20140201" + ["PAR_CHR"]=> + string(6) "test 8" +} +array(3) { + ["PAR_ID"]=> + string(1) "7" + ["PAR_INT"]=> + string(8) "20130901" + ["PAR_CHR"]=> + string(6) "test 7" +} +array(3) { + ["PAR_ID"]=> + string(1) "7" + ["PAR_INT"]=> + string(8) "20130901" + ["PAR_CHR"]=> + string(6) "test 7" +} +==DONE== +--CLEAN-- +<?php +include 'config.inc'; + +$conn = odbc_connect($dsn, $user, $pass); + +odbc_exec($conn, 'DROP TABLE FOO'); +odbc_exec($conn, 'DROP DATABASE odbcTEST'); + +odbc_close($conn); + +?> diff --git a/ext/odbc/tests/bug71171.phpt b/ext/odbc/tests/bug71171.phpt new file mode 100644 index 0000000000..94cfb4d0e8 --- /dev/null +++ b/ext/odbc/tests/bug71171.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #71171 odbc_fetch_array generates SIGFAULT, variant 0 +--SKIPIF-- +<?php include 'skipif.inc'; ?> +--FILE-- +<?php + +include 'config.inc'; + +$conn = odbc_connect($dsn, $user, $pass); + +@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); + +odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL NVARCHAR(40))'); + +odbc_exec($conn, "INSERT INTO FOO(ID, VARCHAR_COL) VALUES (1, '" . chr(0x81) . "')"); + +$res = odbc_exec($conn,"SELECT ID FROM FOO WHERE VARCHAR_COL = '" . chr(0x81) . "'"); +if ($res) { + while($record = odbc_fetch_array($res)) var_dump($record); +} + +odbc_close($conn); +?> +==DONE== +--EXPECT-- +array(1) { + ["ID"]=> + string(1) "1" +} +==DONE== +--CLEAN-- +<?php +include 'config.inc'; + +$conn = odbc_connect($dsn, $user, $pass); + +odbc_exec($conn, 'DROP TABLE FOO'); +odbc_exec($conn, 'DROP DATABASE odbcTEST'); + +odbc_close($conn); + +?> diff --git a/ext/odbc/tests/config.inc b/ext/odbc/tests/config.inc index a88eea4ed0..dcc4cbb3bf 100644 --- a/ext/odbc/tests/config.inc +++ b/ext/odbc/tests/config.inc @@ -3,6 +3,17 @@ putenv('ODBCINI=/etc/odbc.ini'); putenv('ODBCSYSINI=/etc'); -$dsn = 'myodbc3'; -$user = 'root'; -$pass = ''; +$dsn = getenv("ODBC_TEST_DSN"); +$user = getenv("ODBC_TEST_USER"); +$pass = getenv("ODBC_TEST_PASS"); + +if (false === $dsn) { + $dsn = 'myodbc3'; +} +if (false === $user) { + $user = 'root'; +} +if (false == $pass) { + $pass = ''; +} + diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index f4d65a0256..15e6511a76 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -925,10 +925,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline))); Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0'; zval_dtor(&ZEND_OP1_LITERAL(opline)); - Z_STR(ZEND_OP1_LITERAL(opline)) = zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))); - if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(opline))) { - Z_TYPE_FLAGS(ZEND_OP1_LITERAL(opline)) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - } + ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op)))); ZVAL_NULL(&ZEND_OP1_LITERAL(last_op)); MAKE_NOP(last_op); } else if ((opline->opcode == ZEND_CONCAT) && @@ -965,10 +962,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline))); Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0'; zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline))); - Z_STR(ZEND_OP2_LITERAL(opline)) = zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))); - if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(opline))) { - Z_TYPE_FLAGS(ZEND_OP2_LITERAL(opline)) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - } + ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src)))); ZVAL_NULL(&ZEND_OP2_LITERAL(src)); MAKE_NOP(src); } else if ((opline->opcode == ZEND_ADD || diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 2440a56582..48b8d6a682 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -220,6 +220,104 @@ static ZEND_INI_MH(accel_include_path_on_modify) return ret; } +static inline void accel_restart_enter(void) +{ +#ifdef ZEND_WIN32 + INCREMENT(restart_in); +#else + static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1); + + if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno); + } +#endif + ZCSG(restart_in_progress) = 1; +} + +static inline void accel_restart_leave(void) +{ +#ifdef ZEND_WIN32 + ZCSG(restart_in_progress) = 0; + DECREMENT(restart_in); +#else + static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1); + + ZCSG(restart_in_progress) = 0; + if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno); + } +#endif +} + +static inline int accel_restart_is_active(void) +{ + if (ZCSG(restart_in_progress)) { +#ifndef ZEND_WIN32 + FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1); + + if (fcntl(lock_file, F_GETLK, &restart_check) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno); + return FAILURE; + } + if (restart_check.l_type == F_UNLCK) { + ZCSG(restart_in_progress) = 0; + return 0; + } else { + return 1; + } +#else + return LOCKVAL(restart_in) != 0; +#endif + } + return 0; +} + +/* Creates a read lock for SHM access */ +static inline int accel_activate_add(void) +{ +#ifdef ZEND_WIN32 + INCREMENT(mem_usage); +#else + static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1); + + if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno); + return FAILURE; + } +#endif + return SUCCESS; +} + +/* Releases a lock for SHM access */ +static inline void accel_deactivate_sub(void) +{ +#ifdef ZEND_WIN32 + if (ZCG(counted)) { + DECREMENT(mem_usage); + ZCG(counted) = 0; + } +#else + static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1); + + if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno); + } +#endif +} + +static inline void accel_unlock_all(void) +{ +#ifdef ZEND_WIN32 + accel_deactivate_sub(); +#else + static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0); + + if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) { + zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno); + } +#endif +} + /* Interned strings support */ static zend_string *(*orig_new_interned_string)(zend_string *str); static void (*orig_interned_strings_snapshot)(void); @@ -291,6 +389,12 @@ static zend_string *accel_find_interned_string(zend_string *str) /* this is already an interned string */ return str; } + if (!ZCG(counted)) { + if (accel_activate_add() == FAILURE) { + return str; + } + ZCG(counted) = 1; + } h = zend_string_hash_val(str); nIndex = h | ZCSG(interned_strings).nTableMask; @@ -492,102 +596,6 @@ static void accel_use_shm_interned_strings(void) } #endif -static inline void accel_restart_enter(void) -{ -#ifdef ZEND_WIN32 - INCREMENT(restart_in); -#else - static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1); - - if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno); - } -#endif - ZCSG(restart_in_progress) = 1; -} - -static inline void accel_restart_leave(void) -{ -#ifdef ZEND_WIN32 - ZCSG(restart_in_progress) = 0; - DECREMENT(restart_in); -#else - static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1); - - ZCSG(restart_in_progress) = 0; - if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno); - } -#endif -} - -static inline int accel_restart_is_active(void) -{ - if (ZCSG(restart_in_progress)) { -#ifndef ZEND_WIN32 - FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1); - - if (fcntl(lock_file, F_GETLK, &restart_check) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno); - return FAILURE; - } - if (restart_check.l_type == F_UNLCK) { - ZCSG(restart_in_progress) = 0; - return 0; - } else { - return 1; - } -#else - return LOCKVAL(restart_in) != 0; -#endif - } - return 0; -} - -/* Creates a read lock for SHM access */ -static inline void accel_activate_add(void) -{ -#ifdef ZEND_WIN32 - INCREMENT(mem_usage); -#else - static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1); - - if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno); - } -#endif -} - -/* Releases a lock for SHM access */ -static inline void accel_deactivate_sub(void) -{ -#ifdef ZEND_WIN32 - if (ZCG(counted)) { - DECREMENT(mem_usage); - ZCG(counted) = 0; - } -#else - static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1); - - if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno); - } -#endif -} - -static inline void accel_unlock_all(void) -{ -#ifdef ZEND_WIN32 - accel_deactivate_sub(); -#else - static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0); - - if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) { - zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno); - } -#endif -} - #ifndef ZEND_WIN32 static inline void kill_all_lockers(struct flock *mem_usage_check) { @@ -962,6 +970,7 @@ char *accel_make_persistent_key(const char *path, int path_length, int *key_len) zend_shared_alloc_lock(); str = accel_new_interned_string(zend_string_copy(cwd_str)); if (str == cwd_str) { + zend_string_release(str); str = NULL; } zend_shared_alloc_unlock(); @@ -1562,7 +1571,9 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type) } } + SHM_UNPROTECT(); persistent_script = zend_file_cache_script_load(file_handle); + SHM_PROTECT(); if (persistent_script) { /* see bug #15471 (old BTS) */ if (persistent_script->full_path) { @@ -1588,8 +1599,6 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type) } zend_file_handle_dtor(file_handle); - persistent_script->dynamic_members.last_used = ZCG(request_time); - if (persistent_script->ping_auto_globals_mask) { zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask); } @@ -1708,8 +1717,15 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) * each execution) */ if (!ZCG(counted)) { + if (accel_activate_add() == FAILURE) { +#ifdef HAVE_OPCACHE_FILE_CACHE + if (ZCG(accel_directives).file_cache) { + return file_cache_compile_file(file_handle, type); + } +#endif + return accelerator_orig_compile_file(file_handle, type); + } ZCG(counted) = 1; - accel_activate_add(); } SHM_UNPROTECT(); @@ -1976,7 +1992,7 @@ static void accel_reset_pcre_cache(void) ZEND_HASH_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) { /* Remove PCRE cache entries with inconsistent keys */ - if (ZSTR_IS_INTERNED(p->key)) { + if (zend_accel_in_shm(p->key)) { p->key = NULL; zend_hash_del_bucket(&PCRE_G(pcre_cache), p); } @@ -2277,6 +2293,19 @@ static void zend_accel_fast_shutdown(void) } #endif +int accel_post_deactivate(void) +{ + if (!ZCG(enabled) || !accel_startup_ok) { + return SUCCESS; + } + + zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */ + accel_unlock_all(); + ZCG(counted) = 0; + + return SUCCESS; +} + static void accel_deactivate(void) { /* ensure that we restore function_table and class_table @@ -2284,25 +2313,20 @@ static void accel_deactivate(void) * the script is aborted abnormally, they may become messed up. */ + if (ZCG(cwd)) { + zend_string_release(ZCG(cwd)); + ZCG(cwd) = NULL; + } + if (!ZCG(enabled) || !accel_startup_ok) { return; } - zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */ - accel_unlock_all(); - ZCG(counted) = 0; - #if !ZEND_DEBUG if (ZCG(accel_directives).fast_shutdown && is_zend_mm()) { zend_accel_fast_shutdown(); } #endif - - if (ZCG(cwd)) { - zend_string_release(ZCG(cwd)); - ZCG(cwd) = NULL; - } - } static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2) @@ -2865,13 +2889,16 @@ int accelerator_shm_read_lock(void) } else { /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled or is in progress now */ - accel_activate_add(); /* acquire usage lock */ + if (accel_activate_add() == FAILURE) { /* acquire usage lock */ + return FAILURE; + } /* Now if we weren't inside restart, restart would not begin until we remove usage lock */ if (ZCSG(restart_in_progress)) { /* we already were inside restart this means it's not safe to touch shm */ accel_deactivate_now(); /* drop usage lock */ return FAILURE; } + ZCG(counted) = 1; } return SUCCESS; } diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index ca2b9f64f1..89664a2a23 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -318,6 +318,7 @@ extern zend_accel_globals accel_globals; extern char *zps_api_failure_reason; void accel_shutdown(void); +int accel_post_deactivate(void); void zend_accel_schedule_restart(zend_accel_restart_reason reason); void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason); accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size); diff --git a/ext/opcache/tests/bug66338.phpt b/ext/opcache/tests/bug66338.phpt index ed7f8ab475..6553f83f29 100644 --- a/ext/opcache/tests/bug66338.phpt +++ b/ext/opcache/tests/bug66338.phpt @@ -15,13 +15,13 @@ file_put_contents( "$root-Officials.inc", '<?php file_put_contents( "$root-clientUS.php", '<?php class LocalTerms { const GOV_LEADER = "Barack Hussein Obama II"; } - require "'.$root.'-Officials.inc"; + require \''.$root.'-Officials.inc\'; printf( "The President of the USA is %s\n", Officials::getLeader() ); ' ); file_put_contents( "$root-clientUK.php", '<?php class LocalTerms { const GOV_LEADER = "David William Donald Cameron"; } - require "'.$root.'-Officials.inc"; + require \''.$root.'-Officials.inc\'; printf( "The Prime Minister of the UK is %s\n", Officials::getLeader() ); ' ); diff --git a/ext/opcache/tests/bug67215.phpt b/ext/opcache/tests/bug67215.phpt index 24842b4e04..4a9ac7c711 100644 --- a/ext/opcache/tests/bug67215.phpt +++ b/ext/opcache/tests/bug67215.phpt @@ -11,7 +11,7 @@ opcache.file_update_protection=0 $file_c = __DIR__ . "/bug67215.c.php"; $file_p = __DIR__ . "/bug67215.p.php"; -file_put_contents($file_c, "<?php require \"$file_p\"; class c extends p {} ?>"); +file_put_contents($file_c, "<?php require '$file_p'; class c extends p {} ?>"); file_put_contents($file_p, '<?php class p { protected $var = ""; } ?>'); require $file_c; $a = new c(); diff --git a/ext/opcache/tests/revalidate_path_01.phpt b/ext/opcache/tests/revalidate_path_01.phpt index cf2ac0d829..8261633334 100644 --- a/ext/opcache/tests/revalidate_path_01.phpt +++ b/ext/opcache/tests/revalidate_path_01.phpt @@ -25,16 +25,30 @@ while (filemtime($file1) != filemtime($file2)) { touch($file1); touch($file2); } -@unlink($link); -@symlink($dir1, $link); +if (substr(PHP_OS, 0, 3) == 'WIN') { + @rmdir($link); + $ln = str_replace('/', '\\', $link); + $d1 = realpath($dir1); + `mklink /j $ln $d1`; +} else { + @unlink($link); + @symlink($dir1, $link); +} include "php_cli_server.inc"; //php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.revalidate_path=1'); php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.revalidate_path=1 -d opcache.file_update_protection=0 -d realpath_cache_size=0'); echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php'); echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php'); -@unlink($link); -@symlink($dir2, $link); +if (substr(PHP_OS, 0, 3) == 'WIN') { + @rmdir($link); + $ln = str_replace('/', '\\', $link); + $d2 = realpath($dir2); + `mklink /j $ln $d2`; +} else { + @unlink($link); + @symlink($dir2, $link); +} echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php'); echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php'); ?> @@ -48,7 +62,11 @@ $file1 = "$dir1/index.php"; $file2 = "$dir2/index.php"; $main = "$dir/main.php"; @unlink($main); -@unlink($link); +if (substr(PHP_OS, 0, 3) == 'WIN') { + @rmdir($link); +} else { + @unlink($link); +} @unlink($file1); @unlink($file2); @rmdir($dir1); diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 894ea08ac8..2fabc8cb3c 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -516,7 +516,9 @@ static zend_module_entry accel_module_entry = { NULL, zend_accel_info, ACCELERATOR_VERSION "FE", - STANDARD_MODULE_PROPERTIES + NO_MODULE_GLOBALS, + accel_post_deactivate, + STANDARD_MODULE_PROPERTIES_EX }; int start_accel_module(void) diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 410921f800..3187412423 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -224,15 +224,16 @@ static void *zend_file_cache_unserialize_interned(zend_string *str, int in_shm) zend_string *ret; str = (zend_string*)((char*)ZCG(mem) + ((size_t)(str) & ~Z_UL(1))); - ret = accel_new_interned_string(str); - if (ret == str) { - /* String wasn't interned but we will use it as interned anyway */ - if (in_shm) { + if (in_shm) { + ret = accel_new_interned_string(str); + if (ret == str) { + /* String wasn't interned but we will use it as interned anyway */ GC_FLAGS(ret) |= IS_STR_INTERNED | IS_STR_PERMANENT; - } else { - GC_FLAGS(ret) |= IS_STR_INTERNED; - GC_FLAGS(ret) &= ~IS_STR_PERMANENT; } + } else { + ret = str; + GC_FLAGS(ret) |= IS_STR_INTERNED; + GC_FLAGS(ret) &= ~IS_STR_PERMANENT; } return ret; } @@ -1303,7 +1304,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl return NULL; } - if (!ZCG(accel_directives).file_cache_only) { + if (!ZCG(accel_directives).file_cache_only && + !ZCSG(restart_in_progress) && + accelerator_shm_read_lock() == SUCCESS) { /* exclusive lock */ zend_shared_alloc_lock(); @@ -1357,6 +1360,7 @@ use_process_mem: if (cache_it) { script->dynamic_members.checksum = zend_accel_script_checksum(script); + script->dynamic_members.last_used = ZCG(request_time); zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(script->full_path), ZSTR_LEN(script->full_path), 0, script); diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 6c721196a4..25ba69bee8 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -34,7 +34,9 @@ # define ADD_STRING(str) ADD_DUP_SIZE((str), _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))) # define ADD_INTERNED_STRING(str, do_free) do { \ - if (!IS_ACCEL_INTERNED(str)) { \ + if (ZCG(current_persistent_script)->corrupted) { \ + ADD_STRING(str); \ + } else if (!IS_ACCEL_INTERNED(str)) { \ zend_string *tmp = accel_new_interned_string(str); \ if (tmp != (str)) { \ if (do_free) { \ @@ -126,7 +128,7 @@ static void zend_persist_zval_calc(zval *z) case IS_CONSTANT: flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); ADD_INTERNED_STRING(Z_STR_P(z), 0); - if (!Z_REFCOUNTED_P(z)) { + if (ZSTR_IS_INTERNED(Z_STR_P(z))) { Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); } Z_GC_FLAGS_P(z) |= flags; @@ -385,11 +387,15 @@ uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_scrip new_persistent_script->size = 0; new_persistent_script->arena_mem = NULL; new_persistent_script->arena_size = 0; + new_persistent_script->corrupted = 0; ZCG(current_persistent_script) = new_persistent_script; ADD_DUP_SIZE(new_persistent_script, sizeof(zend_persistent_script)); if (key) { ADD_DUP_SIZE(key, key_length + 1); + } else { + /* script is not going to be saved in SHM */ + new_persistent_script->corrupted = 1; } ADD_STRING(new_persistent_script->full_path); @@ -408,6 +414,7 @@ uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_scrip #endif new_persistent_script->size += new_persistent_script->arena_size; + new_persistent_script->corrupted = 0; ZCG(current_persistent_script) = NULL; diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index d616c7d62f..deae886991 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -507,3 +507,20 @@ void zend_accel_shared_protect(int mode) } #endif } + +int zend_accel_in_shm(void *ptr) +{ + int i; + + if (!smm_shared_globals) { + return 0; + } + + for (i = 0; i < ZSMMG(shared_segments_count); i++) { + if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p && + (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->size) { + return 1; + } + } + return 0; +} diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h index 3993b0689e..03b82d16ac 100644 --- a/ext/opcache/zend_shared_alloc.h +++ b/ext/opcache/zend_shared_alloc.h @@ -128,6 +128,8 @@ void *zend_shared_alloc(size_t size); void *_zend_shared_memdup(void *p, size_t size, zend_bool free_source); int zend_shared_memdup_size(void *p, size_t size); +int zend_accel_in_shm(void *ptr); + typedef union _align_test { void *ptr; double dbl; diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 26eb120253..3298efc6f7 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -5241,7 +5241,7 @@ PHP_FUNCTION(openssl_seal) iv_len = EVP_CIPHER_iv_length(cipher); if (!iv && iv_len > 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Cipher algorithm requires an IV to be supplied as a sixth parameter"); RETURN_FALSE; } @@ -5523,14 +5523,14 @@ static zend_bool php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_ } if (*piv_len < iv_required_len) { - php_error_docref(NULL, E_WARNING, "IV passed is only %d bytes long, cipher expects an IV of precisely %d bytes, padding with \\0", *piv_len, iv_required_len); + php_error_docref(NULL, E_WARNING, "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0", *piv_len, iv_required_len); memcpy(iv_new, *piv, *piv_len); *piv_len = iv_required_len; *piv = iv_new; return 1; } - php_error_docref(NULL, E_WARNING, "IV passed is %d bytes long which is longer than the %d expected by selected cipher, truncating", *piv_len, iv_required_len); + php_error_docref(NULL, E_WARNING, "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating", *piv_len, iv_required_len); memcpy(iv_new, *piv, iv_required_len); *piv_len = iv_required_len; *piv = iv_new; diff --git a/ext/openssl/tests/openssl_csr_new_basic.phpt b/ext/openssl/tests/openssl_csr_new_basic.phpt index a3a4746b39..e0f52d739f 100644 --- a/ext/openssl/tests/openssl_csr_new_basic.phpt +++ b/ext/openssl/tests/openssl_csr_new_basic.phpt @@ -9,16 +9,18 @@ $a = 1; var_dump(openssl_csr_new(1,$a)); var_dump(openssl_csr_new(1,$a,1,1)); $a = array(); -var_dump(openssl_csr_new(array(), $a, array('config' => __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf'), array())); + +$conf = array('config' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'openssl.cnf'); +var_dump(openssl_csr_new(array(), $a, $conf, array())); // this leaks $a = array(1,2); $b = array(1,2); -var_dump(openssl_csr_new($a, $b, array('config' => __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf'))); +var_dump(openssl_csr_new($a, $b, $conf)); // options type check -$x = openssl_pkey_new(); -var_dump(openssl_csr_new(["countryName" => "DE"], $x, ["x509_extensions" => 0xDEADBEEF])); +$x = openssl_pkey_new($conf); +var_dump(openssl_csr_new(["countryName" => "DE"], $x, $conf + ["x509_extensions" => 0xDEADBEEF])); echo "Done\n"; diff --git a/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt b/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt index df18322453..b4842aae18 100644 --- a/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt +++ b/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt @@ -5,11 +5,11 @@ openssl_x509_check_private_key() tests --FILE-- <?php $fp = fopen(dirname(__FILE__) . "/cert.crt","r"); -$a = fread($fp,8192); +$a = fread($fp, 8192); fclose($fp); $fp = fopen(dirname(__FILE__) . "/private_rsa_1024.key","r"); -$b = fread($fp,8192); +$b = fread($fp, 8192); fclose($fp); $cert = "file://" . dirname(__FILE__) . "/cert.crt"; diff --git a/ext/openssl/tests/openssl_x509_export_basic.phpt b/ext/openssl/tests/openssl_x509_export_basic.phpt index 712fe4ca80..4177bd7798 100644 --- a/ext/openssl/tests/openssl_x509_export_basic.phpt +++ b/ext/openssl/tests/openssl_x509_export_basic.phpt @@ -1,43 +1,22 @@ --TEST-- -openssl_x509_export() and openssl_x509_export_to_file() tests +openssl_x509_export() tests --SKIPIF-- <?php if (!extension_loaded("openssl")) print "skip"; ?> --FILE-- <?php -$fp = fopen(dirname(__FILE__) . "/cert.crt","r"); -$a = fread($fp,8192); -fclose($fp); +$cert_file = dirname(__FILE__) . "/cert.crt"; -$b = "file://" . dirname(__FILE__) . "/cert.crt"; +$a = file_get_contents($cert_file); +$b = "file://" . $cert_file; $c = "invalid cert"; $d = openssl_x509_read($a); $e = array(); -var_dump(openssl_x509_export($a, $output)); // read cert as a binary string -var_dump(openssl_x509_export($b, $output2)); // read cert from a filename string -var_dump(openssl_x509_export($c, $output3)); // read an invalid cert, fails -var_dump(openssl_x509_export($d, $output4)); // read cert from a resource -var_dump(openssl_x509_export($e, $output5)); // read an array, fails - -$outfilename = tempnam("/tmp", "ssl"); -if ($outfilename === false) { - die("failed to get a temporary filename!"); -} - -echo "---\n"; - -var_dump(openssl_x509_export_to_file($a, $outfilename)); // read cert as a binary string -var_dump(openssl_x509_export_to_file($b, $outfilename)); // read cert from a filename string -var_dump(openssl_x509_export_to_file($c, $outfilename)); // read an invalid cert, fails -var_dump(openssl_x509_export_to_file($d, $outfilename)); // read cert from a resource -var_dump(openssl_x509_export_to_file($e, $outfilename)); // read an array, fails -echo "---\n"; - -var_dump($exists = file_exists($outfilename)); -if ($exists) { - @unlink($outfilename); -} -echo "---\n"; +var_dump(openssl_x509_export($a, $output)); // read cert as a binary string +var_dump(openssl_x509_export($b, $output2)); // read cert from a filename string +var_dump(openssl_x509_export($c, $output3)); // read an invalid cert, fails +var_dump(openssl_x509_export($d, $output4)); // read cert from a resource +var_dump(openssl_x509_export($e, $output5)); // read an array, fails if (PHP_EOL !== "\n") { $a = str_replace(PHP_EOL, "\n", $a); @@ -46,9 +25,8 @@ if (PHP_EOL !== "\n") { var_dump(strcmp($output, $a)); var_dump(strcmp($output, $output2)); var_dump(strcmp($output, $output3)); -var_dump(strcmp($output, $output4)); // different -var_dump(strcmp($output, $output5)); // different - +var_dump(strcmp($output, $output4)); // different +var_dump(strcmp($output, $output5)); // different ?> --EXPECTF-- bool(true) @@ -60,19 +38,6 @@ bool(true) Warning: openssl_x509_export(): cannot get cert from parameter 1 in %s on line %d bool(false) ---- -bool(true) -bool(true) - -Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d -bool(false) -bool(true) - -Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d -bool(false) ---- -bool(true) ---- int(0) int(0) int(%d) diff --git a/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt b/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt new file mode 100644 index 0000000000..68ba93230d --- /dev/null +++ b/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt @@ -0,0 +1,42 @@ +--TEST-- +openssl_x509_export_to_file() tests +--SKIPIF-- +<?php if (!extension_loaded("openssl")) print "skip"; ?> +--FILE-- +<?php +$outfilename = dirname(__FILE__) . "/openssl_x509_export_to_file__outfilename.tmp"; +$cert_file = dirname(__FILE__) . "/cert.crt"; + +$a = file_get_contents($cert_file); +$b = "file://" . $cert_file; +$c = "invalid cert"; +$d = openssl_x509_read($a); +$e = array(); + +var_dump(openssl_x509_export_to_file($a, $outfilename)); // read cert as a binary string +var_dump(openssl_x509_export_to_file($b, $outfilename)); // read cert from a filename string +var_dump(openssl_x509_export_to_file($c, $outfilename)); // read an invalid cert, fails +var_dump(openssl_x509_export_to_file($d, $outfilename)); // read cert from a resource +var_dump(openssl_x509_export_to_file($e, $outfilename)); // read an array, fails +echo "---\n"; +var_dump($exists = file_exists($outfilename)); +?> +--CLEAN-- +<?php +$outfilename = dirname(__FILE__) . "/openssl_x509_export_to_file__outfilename.tmp"; +if (file_exists($outfilename)) { + unlink($outfilename); +} +?> +--EXPECTF-- +bool(true) +bool(true) + +Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) +bool(true) + +Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) +--- +bool(true) diff --git a/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt b/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt index 6cd464a894..766b158fab 100644 --- a/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt +++ b/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -Testing openssl_x509_fingerprint() +openssl_x509_fingerprint() tests --SKIPIF-- <?php if (!extension_loaded("openssl")) die("skip"); diff --git a/ext/openssl/tests/openssl_x509_free_basic.phpt b/ext/openssl/tests/openssl_x509_free_basic.phpt new file mode 100644 index 0000000000..d8b586e8b4 --- /dev/null +++ b/ext/openssl/tests/openssl_x509_free_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +openssl_x509_free() tests +--SKIPIF-- +<?php if (!extension_loaded("openssl")) print "skip"; ?> +--FILE-- +<?php +var_dump($res = openssl_x509_read("file://" . dirname(__FILE__) . "/cert.crt")); +openssl_x509_free($res); +var_dump($res); +openssl_x509_free(false); +?> +--EXPECTF-- +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (Unknown) + +Warning: openssl_x509_free() expects parameter 1 to be resource, boolean given in %s on line %d diff --git a/ext/openssl/tests/openssl_x509_parse_basic.phpt b/ext/openssl/tests/openssl_x509_parse_basic.phpt index 325b2ee4b9..00e32c3b60 100644 --- a/ext/openssl/tests/openssl_x509_parse_basic.phpt +++ b/ext/openssl/tests/openssl_x509_parse_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -openssl_x509_parse() basic test +openssl_x509_parse() tests --SKIPIF-- <?php if (!extension_loaded("openssl")) print "skip"; if (OPENSSL_VERSION_NUMBER < 0x10000000) die("skip Output requires OpenSSL 1.0"); diff --git a/ext/openssl/tests/openssl_x509_read_basic.phpt b/ext/openssl/tests/openssl_x509_read_basic.phpt index cc36e989c6..5f530534ff 100644 --- a/ext/openssl/tests/openssl_x509_read_basic.phpt +++ b/ext/openssl/tests/openssl_x509_read_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -openssl_x509_read() tests with testing openssl_x509_free as well +openssl_x509_read() tests --SKIPIF-- <?php if (!extension_loaded("openssl")) print "skip"; ?> --FILE-- @@ -14,47 +14,24 @@ $d = openssl_x509_read($a); $e = array(); $f = array($b); -var_dump($res = openssl_x509_read($a)); // read cert as a string -openssl_x509_free($res); -var_dump($res); -var_dump($res = openssl_x509_read($b)); // read cert as a filename string -openssl_x509_free($res); -var_dump($res); -var_dump($res = openssl_x509_read($c)); // read an invalid cert, fails -openssl_x509_free($res); -var_dump($res); -var_dump($res = openssl_x509_read($d)); // read cert from a resource -openssl_x509_free($res); -var_dump($res); -var_dump($res = openssl_x509_read($e)); // read an array -openssl_x509_free($res); -var_dump($res); -var_dump($res = openssl_x509_read($f)); // read an array with the filename -openssl_x509_free($res); -var_dump($res); +var_dump(openssl_x509_read($a)); // read cert as a string +var_dump(openssl_x509_read($b)); // read cert as a filename string +var_dump(openssl_x509_read($c)); // read an invalid cert, fails +var_dump(openssl_x509_read($d)); // read cert from a resource +var_dump(openssl_x509_read($e)); // read an array +var_dump(openssl_x509_read($f)); // read an array with the filename ?> --EXPECTF-- resource(%d) of type (OpenSSL X.509) -resource(%d) of type (Unknown) resource(%d) of type (OpenSSL X.509) -resource(%d) of type (Unknown) Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d bool(false) - -Warning: openssl_x509_free() expects parameter 1 to be resource, boolean given in %s on line %d -bool(false) resource(%d) of type (OpenSSL X.509) -resource(%d) of type (Unknown) Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d bool(false) -Warning: openssl_x509_free() expects parameter 1 to be resource, boolean given in %s on line %d -bool(false) - Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d bool(false) -Warning: openssl_x509_free() expects parameter 1 to be resource, boolean given in %s on line %d -bool(false) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index ee3e36b6ab..93bfc00052 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1350,7 +1350,6 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *subject, int limit, int is_callable_replace, int *replace_count) { zval *regex_entry, - *replace_entry = NULL, *replace_value, empty_replace; zend_string *result; @@ -1372,25 +1371,26 @@ static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *sub /* For each entry in the regex array, get the entry */ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(regex), regex_entry) { + zval replace_str; /* Make sure we're dealing with strings. */ zend_string *regex_str = zval_get_string(regex_entry); + ZVAL_UNDEF(&replace_str); /* If replace is an array and not a callable construct */ if (Z_TYPE_P(replace) == IS_ARRAY && !is_callable_replace) { /* Get current entry */ - replace_entry = NULL; while (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) { if (Z_TYPE(Z_ARRVAL_P(replace)->arData[replace_idx].val) != IS_UNDEF) { - replace_entry = &Z_ARRVAL_P(replace)->arData[replace_idx].val; + ZVAL_COPY(&replace_str, &Z_ARRVAL_P(replace)->arData[replace_idx].val); break; } replace_idx++; } - if (replace_entry != NULL) { + if (!Z_ISUNDEF(replace_str)) { if (!is_callable_replace) { - convert_to_string_ex(replace_entry); + convert_to_string(&replace_str); } - replace_value = replace_entry; + replace_value = &replace_str; replace_idx++; } else { /* We've run out of replacement strings, so use an empty one */ @@ -1413,10 +1413,12 @@ static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *sub } else { zend_string_release(subject_str); zend_string_release(regex_str); + zval_dtor(&replace_str); return NULL; } zend_string_release(regex_str); + zval_dtor(&replace_str); } ZEND_HASH_FOREACH_END(); return subject_str; diff --git a/ext/pcre/tests/bug71537.phpt b/ext/pcre/tests/bug71537.phpt new file mode 100644 index 0000000000..cdc2928a28 --- /dev/null +++ b/ext/pcre/tests/bug71537.phpt @@ -0,0 +1,9 @@ +--TEST-- +Fixed bug #71537 (PCRE segfault from Opcache) +--FILE-- +<?php + +var_dump(preg_replace(array("/Monkey/"), array(2016), "Happy Year of Monkey")); +?> +--EXPECT-- +string(18) "Happy Year of 2016" diff --git a/ext/pdo/Makefile.frag b/ext/pdo/Makefile.frag index dc25c9f70b..58125ed872 100644 --- a/ext/pdo/Makefile.frag +++ b/ext/pdo/Makefile.frag @@ -10,7 +10,7 @@ $(srcdir)/pdo_sql_parser.c: $(srcdir)/pdo_sql_parser.re (cd $(top_srcdir); $(RE2C) --no-generation-date -o ext/pdo/pdo_sql_parser.c ext/pdo/pdo_sql_parser.re) install-pdo-headers: - @echo "Installing PDO headers: $(INSTALL_ROOT)$(phpincludedir)/ext/pdo/" + @echo "Installing PDO headers: $(INSTALL_ROOT)$(phpincludedir)/ext/pdo/" @$(mkinstalldirs) $(INSTALL_ROOT)$(phpincludedir)/ext/pdo @for f in $(PDO_HEADER_FILES); do \ if test -f "$(top_srcdir)/$$f"; then \ diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 5ca20fcd5b..6019c39aba 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2107,9 +2107,9 @@ static PHP_METHOD(PDOStatement, debugDumpParams) RETURN_FALSE; } - php_stream_printf(out, "SQL: [%d] %.*s\n", + php_stream_printf(out, "SQL: [%zd] %.*s\n", stmt->query_stringlen, - stmt->query_stringlen, stmt->query_string); + (int) stmt->query_stringlen, stmt->query_string); php_stream_printf(out, "Params: %d\n", stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0); @@ -2119,13 +2119,14 @@ static PHP_METHOD(PDOStatement, debugDumpParams) zend_string *key = NULL; ZEND_HASH_FOREACH_KEY_PTR(stmt->bound_params, num, key, param) { if (key) { - php_stream_printf(out, "Key: Name: [%d] %.*s\n", ZSTR_LEN(key), ZSTR_LEN(key), ZSTR_VAL(key)); + php_stream_printf(out, "Key: Name: [%zd] %.*s\n", + ZSTR_LEN(key), (int) ZSTR_LEN(key), ZSTR_VAL(key)); } else { php_stream_printf(out, "Key: Position #%pd:\n", num); } - php_stream_printf(out, "paramno=%pd\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n", - param->paramno, param->name? ZSTR_LEN(param->name) : 0, param->name? ZSTR_LEN(param->name) : 0, + php_stream_printf(out, "paramno=%pd\nname=[%zd] \"%.*s\"\nis_param=%d\nparam_type=%d\n", + param->paramno, param->name ? ZSTR_LEN(param->name) : 0, param->name ? (int) ZSTR_LEN(param->name) : 0, param->name ? ZSTR_VAL(param->name) : "", param->is_param, param->param_type); diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index cfb386fa0d..dcbaf55a3f 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -331,9 +331,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) ,{"auto",0} /* Only works with FreeTDS. Other drivers will bork */ }; - - nvers = sizeof(tdsver)/sizeof(tdsver[0]); - + struct pdo_data_src_parser vars[] = { { "charset", NULL, 0 } ,{ "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 } @@ -344,7 +342,8 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) }; nvars = sizeof(vars)/sizeof(vars[0]); - + nvers = sizeof(tdsver)/sizeof(tdsver[0]); + php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars); if (driver_options) { diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 484bfbb560..0eff4945dd 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -102,7 +102,7 @@ static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt) /* Cancel any pending results */ dbcancel(H->link); - + return 1; } @@ -268,6 +268,25 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, *ptr = tmp_ptr; break; } + case SQLDATETIM4: + case SQLDATETIME: { + DBDATETIME dt; + DBDATEREC di; + + dbconvert(H->link, coltype, (BYTE*) *ptr, -1, SQLDATETIME, (LPBYTE) &dt, -1); + dbdatecrack(H->link, &di, &dt); + + *len = spprintf((char**) &tmp_ptr, 20, "%d-%02d-%02d %02d:%02d:%02d", +#ifdef PHP_DBLIB_IS_MSSQL || MSDBLIB + di.year, di.month, di.day, di.hour, di.minute, di.second +#else + di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond +#endif + ); + + *ptr = (char*) tmp_ptr; + break; + } default: if (dbwillconvert(coltype, SQLCHAR)) { tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */ diff --git a/ext/pdo_dblib/tests/bug_54648.phpt b/ext/pdo_dblib/tests/bug_54648.phpt new file mode 100644 index 0000000000..aa9f292669 --- /dev/null +++ b/ext/pdo_dblib/tests/bug_54648.phpt @@ -0,0 +1,26 @@ +--TEST-- +PDO_DBLIB: Does not force correct dateformat +--SKIPIF-- +<?php +if (!extension_loaded('pdo_dblib')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +?> +--FILE-- +<?php +require dirname(__FILE__) . '/config.inc'; +$db->query('set dateformat ymd'); +$rs = $db->query("select cast('1950-01-18 23:00:00' as smalldatetime) as sdt, cast('2030-01-01 23:59:59' as datetime) as dt"); +var_dump($rs->fetchAll(PDO::FETCH_ASSOC)); +echo "Done.\n"; +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + ["sdt"]=> + string(19) "1950-01-18 23:00:00" + ["dt"]=> + string(19) "2030-01-01 23:59:59" + } +} +Done. diff --git a/ext/pdo_dblib/tests/bug_68957.phpt b/ext/pdo_dblib/tests/bug_68957.phpt new file mode 100644 index 0000000000..3d6e2fd13d --- /dev/null +++ b/ext/pdo_dblib/tests/bug_68957.phpt @@ -0,0 +1,29 @@ +--TEST-- +PDO_DBLIB bug #68957 PDO::query doesn't support several queries +--SKIPIF-- +<?php +if (!extension_loaded('pdo_dblib')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +?> +--FILE-- +<?php +require dirname(__FILE__) . '/config.inc'; + +$query = "declare @myInt int = 1; select @myInt;"; +$stmt = $db->query($query); +$stmt->nextRowset(); // Added line +$rows = $stmt->fetchAll(); +print_r($rows); + +?> +--EXPECT-- +Array +( + [0] => Array + ( + [computed0] => 1 + [0] => 1 + ) + +) + diff --git a/ext/pdo_mysql/tests/bug71569.phpt b/ext/pdo_mysql/tests/bug71569.phpt new file mode 100644 index 0000000000..32c14b4622 --- /dev/null +++ b/ext/pdo_mysql/tests/bug71569.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #71569 (#70389 fix causes segmentation fault) +--SKIPIF-- +<?php +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); +MySQLPDOTest::skip(); +?> +--FILE-- +<?php +require(dirname(__FILE__). DIRECTORY_SEPARATOR . 'config.inc'); + +try { + new PDO(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS, [ + PDO::MYSQL_ATTR_INIT_COMMAND => null, + ]); +} catch (PDOException $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +SQLSTATE[42000] [1065] Query was empty diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 719ebe10d7..f84f31aed6 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3033,7 +3033,7 @@ static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset)); break; case PHP_PG_DATA_ISNULL: - RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset)) + RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset)); break; } } diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 0ed34dbfcd..63feb3cfb8 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1794,8 +1794,11 @@ static int phar_analyze_path(const char *fname, const char *ext, int ext_len, in #ifdef PHP_WIN32 phar_unixify_path_separators(realpath, strlen(realpath)); #endif - slash = strstr(realpath, filename) + ((ext - fname) + ext_len); - *slash = '\0'; + slash = strstr(realpath, filename); + if (slash) { + slash += ((ext - fname) + ext_len); + *slash = '\0'; + } slash = strrchr(realpath, '/'); if (slash) { diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 51b8b13a2a..22404dddbc 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4085,7 +4085,7 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char * new_state.cwd[0] = DEFAULT_SLASH; new_state.cwd[1] = '\0'; new_state.cwd_length = 1; - if (virtual_file_ex(&new_state, entry->filename, NULL, CWD_EXPAND TSRMLS_CC) != 0 || + if (virtual_file_ex(&new_state, entry->filename, NULL, CWD_EXPAND) != 0 || new_state.cwd_length <= 1) { if (EINVAL == errno && entry->filename_len > 50) { char *tmp = estrndup(entry->filename, 50); diff --git a/ext/phar/tests/bug71331.phpt b/ext/phar/tests/bug71331.phpt index 6cd850d36d..0026c406e8 100644 --- a/ext/phar/tests/bug71331.phpt +++ b/ext/phar/tests/bug71331.phpt @@ -8,8 +8,8 @@ $p = new PharData(__DIR__."/bug71331.tar"); ?> DONE --EXPECTF-- -Fatal error: Uncaught UnexpectedValueException: phar error: "%s/bug71331.tar" is a corrupted tar file (invalid entry size) in %s/bug71331.php:2 +Fatal error: Uncaught UnexpectedValueException: phar error: "%s%ebug71331.tar" is a corrupted tar file (invalid entry size) in %s%ebug71331.php:2 Stack trace: -#0 %s/bug71331.php(2): PharData->__construct('%s') +#0 %s%ebug71331.php(2): PharData->__construct('%s') #1 {main} - thrown in %s/bug71331.php on line 2 + thrown in %s%ebug71331.php on line 2 diff --git a/ext/phar/tests/bug71625.phpt b/ext/phar/tests/bug71625.phpt new file mode 100644 index 0000000000..8e6c31f462 --- /dev/null +++ b/ext/phar/tests/bug71625.phpt @@ -0,0 +1,25 @@ +--TEST-- +Phar - Bug #71625 - Crash in php7.dll +--INI-- +phar.readonly=0 +--SKIPIF-- +<?php + +if (!extension_loaded("phar") || !extension_loaded("zlib")) die("skip"); +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} + +?> +--FILE-- +<?php +$phar = new Phar("A:A:.phar"); +$phar["hello_habr.txt"] = '<? Hello Habr!?>'; +?> +DONE +--EXPECTF-- +Fatal error: Uncaught UnexpectedValueException: Cannot create phar 'A:A:.phar', file extension (or combination) not recognised or the directory does not exist in %sbug71625.php:%d +Stack trace: +#0 %sbug71625.php(%d): Phar->__construct('A:A:.phar') +#1 {main} + thrown in %sbug71625.php on line %d diff --git a/ext/skeleton/create_stubs b/ext/skeleton/create_stubs index 1163908110..a3f3d196b3 100755 --- a/ext/skeleton/create_stubs +++ b/ext/skeleton/create_stubs @@ -195,7 +195,7 @@ END { if (maxargs[i]>0) { fetchargs = "\tif (zend_parse_parameters(" ints = ints "\tint argc = ZEND_NUM_ARGS();\n" - fetchargs = fetchargs "argc TSRMLS_CC, " specs[i] + fetchargs = fetchargs "argc, " specs[i] } else { fetchargs = fetchargs "\tif (zend_parse_parameters_none() == FAILURE) {\n\t\treturn;\n\t}" xmlparams = xmlparams " <void/>\n" diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 67d2ccb67c..685dd27092 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -82,19 +82,29 @@ static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ { #define Z_SPLARRAY_P(zv) spl_array_from_obj(Z_OBJ_P((zv))) -static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props) { /* {{{ */ - if (intern->ar_flags & SPL_ARRAY_IS_SELF - || (check_std_props && (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST)) - ) { +static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */ + //??? TODO: Delay duplication for arrays; only duplicate for write operations + if (intern->ar_flags & SPL_ARRAY_IS_SELF) { if (!intern->std.properties) { rebuild_object_properties(&intern->std); } return intern->std.properties; } else if (intern->ar_flags & SPL_ARRAY_USE_OTHER) { spl_array_object *other = Z_SPLARRAY_P(&intern->array); - return spl_array_get_hash_table(other, check_std_props); + return spl_array_get_hash_table(other); + } else if (Z_TYPE(intern->array) == IS_ARRAY) { + return Z_ARRVAL(intern->array); } else { - return HASH_OF(&intern->array); + zend_object *obj = Z_OBJ(intern->array); + if (!obj->properties) { + rebuild_object_properties(obj); + } else if (GC_REFCOUNT(obj->properties) > 1) { + if (EXPECTED(!(GC_FLAGS(obj->properties) & IS_ARRAY_IMMUTABLE))) { + GC_REFCOUNT(obj->properties)--; + } + obj->properties = zend_array_dup(obj->properties); + } + return obj->properties; } } /* }}} */ @@ -167,10 +177,12 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zval * if (other->ar_flags & SPL_ARRAY_IS_SELF) { ZVAL_UNDEF(&intern->array); } else if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) { - ZVAL_ARR(&intern->array, zend_array_dup(HASH_OF(&other->array))); + ZVAL_ARR(&intern->array, + zend_array_dup(spl_array_get_hash_table(other))); } else { ZEND_ASSERT(Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator); - ZVAL_COPY(&intern->array, &other->array); + ZVAL_COPY(&intern->array, orig); + intern->ar_flags |= SPL_ARRAY_USE_OTHER; } } else { ZVAL_COPY(&intern->array, orig); @@ -269,13 +281,13 @@ static zval *spl_array_get_dimension_ptr(int check_inherited, zval *object, zval zend_long index; zend_string *offset_key; spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *ht = spl_array_get_hash_table(intern, 0); + HashTable *ht = spl_array_get_hash_table(intern); if (!offset || Z_ISUNDEF_P(offset)) { return &EG(uninitialized_zval); } - if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->u.v.nApplyCount > 0)) { + if ((type == BP_VAR_W || type == BP_VAR_RW) && intern->nApplyCount > 0) { zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); return &EG(error_zval); } @@ -434,16 +446,8 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval return; } - if (!offset) { - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } - if (Z_REFCOUNTED_P(value)) { - Z_ADDREF_P(value); - } - zend_hash_next_index_insert(ht, value); + if (intern->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); return; } @@ -451,14 +455,16 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval Z_ADDREF_P(value); } + if (!offset) { + ht = spl_array_get_hash_table(intern); + zend_hash_next_index_insert(ht, value); + return; + } + try_again: switch (Z_TYPE_P(offset)) { case IS_STRING: - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } + ht = spl_array_get_hash_table(intern); zend_symtable_update_ind(ht, Z_STR_P(offset), value); return; case IS_DOUBLE: @@ -476,19 +482,11 @@ try_again: case IS_LONG: index = Z_LVAL_P(offset); num_index: - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } + ht = spl_array_get_hash_table(intern); zend_hash_index_update(ht, index, value); return; case IS_NULL: - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } + ht = spl_array_get_hash_table(intern); zend_hash_next_index_insert(ht, value); return; case IS_REFERENCE: @@ -496,6 +494,7 @@ num_index: goto try_again; default: zend_error(E_WARNING, "Illegal offset type"); + zval_ptr_dtor(value); return; } } /* }}} */ @@ -518,14 +517,15 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval return; } + if (intern->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + try_again: switch (Z_TYPE_P(offset)) { case IS_STRING: - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } + ht = spl_array_get_hash_table(intern); if (ht == &EG(symbol_table)) { if (zend_delete_global_variable(Z_STR_P(offset))) { zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset)); @@ -570,11 +570,7 @@ try_again: case IS_LONG: index = Z_LVAL_P(offset); num_index: - ht = spl_array_get_hash_table(intern, 0); - if (ht->u.v.nApplyCount > 0) { - zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); - return; - } + ht = spl_array_get_hash_table(intern); if (zend_hash_index_del(ht, index) == FAILURE) { zend_error(E_NOTICE,"Undefined offset: %pd", index); } @@ -618,7 +614,7 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o } if (!value) { - HashTable *ht = spl_array_get_hash_table(intern, 0); + HashTable *ht = spl_array_get_hash_table(intern); try_again: switch (Z_TYPE_P(offset)) { @@ -744,7 +740,7 @@ SPL_METHOD(Array, offsetSet) void spl_array_iterator_append(zval *object, zval *append_value) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (!aht) { php_error_docref(NULL, E_NOTICE, "Array was modified outside object and is no longer an array"); @@ -792,22 +788,21 @@ SPL_METHOD(Array, getArrayCopy) zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern, 0))); + RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern))); } /* }}} */ static HashTable *spl_array_get_properties(zval *object) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *result; - if (intern->nApplyCount > 1) { - php_error_docref(NULL, E_ERROR, "Nesting level too deep - recursive dependency?"); + if (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) { + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + return intern->std.properties; } - intern->nApplyCount++; - result = spl_array_get_hash_table(intern, 1); - intern->nApplyCount--; - return result; + return spl_array_get_hash_table(intern); } /* }}} */ static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */ @@ -922,8 +917,8 @@ static int spl_array_compare_objects(zval *o1, zval *o2) /* {{{ */ intern1 = Z_SPLARRAY_P(o1); intern2 = Z_SPLARRAY_P(o2); - ht1 = spl_array_get_hash_table(intern1, 0); - ht2 = spl_array_get_hash_table(intern2, 0); + ht1 = spl_array_get_hash_table(intern1); + ht2 = spl_array_get_hash_table(intern2); result = zend_compare_symbol_tables(ht1, ht2); /* if we just compared std.properties, don't do it again */ @@ -978,7 +973,7 @@ static int spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */ static int spl_array_next(spl_array_object *intern) /* {{{ */ { - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); return spl_array_next_ex(intern, aht); @@ -994,7 +989,7 @@ static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */ static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */ { spl_array_object *object = Z_SPLARRAY_P(&iter->data); - HashTable *aht = spl_array_get_hash_table(object, 0); + HashTable *aht = spl_array_get_hash_table(object); if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) { return zend_user_it_valid(iter); @@ -1011,7 +1006,7 @@ static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */ static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */ { spl_array_object *object = Z_SPLARRAY_P(&iter->data); - HashTable *aht = spl_array_get_hash_table(object, 0); + HashTable *aht = spl_array_get_hash_table(object); if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) { return zend_user_it_get_current_data(iter); @@ -1028,7 +1023,7 @@ static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */ static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */ { spl_array_object *object = Z_SPLARRAY_P(&iter->data); - HashTable *aht = spl_array_get_hash_table(object, 0); + HashTable *aht = spl_array_get_hash_table(object); if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) { zend_user_it_get_current_key(iter, key); @@ -1045,7 +1040,7 @@ static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */ { spl_array_object *object = Z_SPLARRAY_P(&iter->data); - HashTable *aht = spl_array_get_hash_table(object, 0); + HashTable *aht = spl_array_get_hash_table(object); if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) { zend_user_it_move_forward(iter); @@ -1063,7 +1058,7 @@ static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */ static void spl_array_rewind(spl_array_object *intern) /* {{{ */ { - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (!aht) { php_error_docref(NULL, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array"); @@ -1099,13 +1094,13 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar return; } - zval_ptr_dtor(&intern->array); - if (Z_TYPE_P(array) == IS_ARRAY) { //??? TODO: try to avoid array duplication + zval_ptr_dtor(&intern->array); ZVAL_DUP(&intern->array, array); } else { if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator) { + zval_ptr_dtor(&intern->array); if (just_array) { spl_array_object *other = Z_SPLARRAY_P(array); ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK; @@ -1119,18 +1114,13 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar } } else { zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties); - if (handler != std_object_handlers.get_properties - || !spl_array_get_hash_table(intern, 0)) { - ZVAL_UNDEF(&intern->array); - zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_P(array)->name, intern->std.ce->name); - } - //??? TODO: try to avoid array duplication - if (Z_OBJ_P(array)->properties && GC_REFCOUNT(Z_OBJ_P(array)->properties) > 1) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_REFCOUNT(Z_OBJ_P(array)->properties)--; - } - Z_OBJ_P(array)->properties = zend_array_dup(Z_OBJ_P(array)->properties); + if (handler != std_object_handlers.get_properties) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, + "Overloaded object of type %s is not compatible with %s", + ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name)); + return; } + zval_ptr_dtor(&intern->array); ZVAL_COPY(&intern->array, array); } } @@ -1284,7 +1274,12 @@ SPL_METHOD(Array, exchangeArray) return; } - RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern, 0))); + if (intern->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + + RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern))); spl_array_set_array(object, intern, array, 0L, 1); } /* }}} */ @@ -1295,7 +1290,7 @@ SPL_METHOD(Array, getIterator) { zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1332,7 +1327,7 @@ SPL_METHOD(Array, seek) zend_long opos, position; zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); int result; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) { @@ -1361,7 +1356,7 @@ SPL_METHOD(Array, seek) int static spl_array_object_count_elements_helper(spl_array_object *intern, zend_long *count) /* {{{ */ { - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); HashPosition pos, *pos_ptr; if (!aht) { @@ -1426,7 +1421,7 @@ SPL_METHOD(Array, count) static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(getThis()); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); zval function_name, params[2], *arg = NULL; uint32_t old_refcount; @@ -1440,9 +1435,9 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam ZVAL_ARR(Z_REFVAL(params[0]), aht); if (!use_arg) { - aht->u.v.nApplyCount++; + intern->nApplyCount++; call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 1, params, 1, NULL); - aht->u.v.nApplyCount--; + intern->nApplyCount--; } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) { if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) { zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0); @@ -1451,18 +1446,18 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam if (arg) { ZVAL_COPY_VALUE(¶ms[1], arg); } - aht->u.v.nApplyCount++; + intern->nApplyCount++; call_user_function_ex(EG(function_table), NULL, &function_name, return_value, arg ? 2 : 1, params, 1, NULL); - aht->u.v.nApplyCount--; + intern->nApplyCount--; } else { if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &arg) == FAILURE) { zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0); goto exit; } ZVAL_COPY_VALUE(¶ms[1], arg); - aht->u.v.nApplyCount++; + intern->nApplyCount++; call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 2, params, 1, NULL); - aht->u.v.nApplyCount--; + intern->nApplyCount--; } exit: @@ -1515,7 +1510,7 @@ SPL_METHOD(Array, current) zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); zval *entry; - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1553,7 +1548,7 @@ SPL_METHOD(Array, key) void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (spl_array_object_verify_pos(intern, aht) == FAILURE) { return; @@ -1569,7 +1564,7 @@ SPL_METHOD(Array, next) { zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1589,7 +1584,7 @@ SPL_METHOD(Array, valid) { zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1609,7 +1604,7 @@ SPL_METHOD(Array, hasChildren) { zval *object = getThis(), *entry; spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1633,7 +1628,7 @@ SPL_METHOD(Array, getChildren) { zval *object = getThis(), *entry, flags; spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); if (zend_parse_parameters_none() == FAILURE) { return; @@ -1669,7 +1664,7 @@ SPL_METHOD(Array, serialize) { zval *object = getThis(); spl_array_object *intern = Z_SPLARRAY_P(object); - HashTable *aht = spl_array_get_hash_table(intern, 0); + HashTable *aht = spl_array_get_hash_table(intern); zval members, flags; php_serialize_data_t var_hash; smart_str buf = {0}; @@ -1728,7 +1723,6 @@ SPL_METHOD(Array, unserialize) const unsigned char *p, *s; php_unserialize_data_t var_hash; zval *members, *zflags; - HashTable *aht; zend_long flags; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) { @@ -1739,8 +1733,7 @@ SPL_METHOD(Array, unserialize) return; } - aht = spl_array_get_hash_table(intern, 0); - if (aht->u.v.nApplyCount > 0) { + if (intern->nApplyCount > 0) { zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); return; } diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index b0ee3bc7a3..412fc54324 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -834,7 +834,7 @@ SPL_METHOD(DirectoryIterator, seek) zval_ptr_dtor(&retval); } if (!valid) { - zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", pos); + zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position %ld is out of range", pos); return; } zend_call_method_with_0_params(&EX(This), Z_OBJCE(EX(This)), &intern->u.dir.func_next, "next", NULL); diff --git a/ext/spl/tests/ArrayObject_clone_other_std_props.phpt b/ext/spl/tests/ArrayObject_clone_other_std_props.phpt new file mode 100644 index 0000000000..688954c3d7 --- /dev/null +++ b/ext/spl/tests/ArrayObject_clone_other_std_props.phpt @@ -0,0 +1,23 @@ +--TEST-- +Clone ArrayObject using other with STD_PROP_LIST +--FILE-- +<?php + +$a = new ArrayObject([1, 2, 3], ArrayObject::STD_PROP_LIST); +$b = new ArrayObject($a); +$c = clone $b; +var_dump($c); + +?> +--EXPECT-- +object(ArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} diff --git a/ext/spl/tests/ArrayObject_dump_during_sort.phpt b/ext/spl/tests/ArrayObject_dump_during_sort.phpt new file mode 100644 index 0000000000..0fb128b655 --- /dev/null +++ b/ext/spl/tests/ArrayObject_dump_during_sort.phpt @@ -0,0 +1,27 @@ +--TEST-- +Dumping an ArrayObject while it is being sorted +--FILE-- +<?php + +$ao = new ArrayObject([1, 2, 3]); +$i = 0; +$ao->uasort(function($a, $b) use ($ao, &$i) { + if ($i++ == 0) { + var_dump($ao); + } + return $a <=> $b; +}); + +?> +--EXPECT-- +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} diff --git a/ext/spl/tests/ArrayObject_exchange_array_during_sorting.phpt b/ext/spl/tests/ArrayObject_exchange_array_during_sorting.phpt new file mode 100644 index 0000000000..225d42c1ed --- /dev/null +++ b/ext/spl/tests/ArrayObject_exchange_array_during_sorting.phpt @@ -0,0 +1,29 @@ +--TEST-- +Can't use exchangeArray() while ArrayObject is being sorted +--FILE-- +<?php + +$ao = new ArrayObject([1, 2, 3]); +$i = 0; +$ao->uasort(function($a, $b) use ($ao, &$i) { + if ($i++ == 0) { + $ao->exchangeArray([4, 5, 6]); + var_dump($ao); + } + return $a <=> $b; +}); + +?> +--EXPECTF-- +Warning: Modification of ArrayObject during sorting is prohibited in %s on line %d +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} diff --git a/ext/spl/tests/ArrayObject_illegal_offset_leak.phpt b/ext/spl/tests/ArrayObject_illegal_offset_leak.phpt new file mode 100644 index 0000000000..42c649db9f --- /dev/null +++ b/ext/spl/tests/ArrayObject_illegal_offset_leak.phpt @@ -0,0 +1,11 @@ +--TEST-- +Assignments to illegal ArrayObject offsets shouldn't leak +--FILE-- +<?php + +$ao = new ArrayObject([1, 2, 3]); +$ao[[]] = new stdClass; + +?> +--EXPECTF-- +Warning: Illegal offset type in %s on line %d diff --git a/ext/spl/tests/ArrayObject_modify_shared_object_properties.phpt b/ext/spl/tests/ArrayObject_modify_shared_object_properties.phpt new file mode 100644 index 0000000000..24c247cabd --- /dev/null +++ b/ext/spl/tests/ArrayObject_modify_shared_object_properties.phpt @@ -0,0 +1,19 @@ +--TEST-- +Modifications to ArrayObjects should not affect shared properties tables +--FILE-- +<?php + +$obj = (object)['a' => 1, 'b' => 2]; +$ao = new ArrayObject($obj); +$arr = (array) $obj; +$ao['a'] = 42; +var_dump($arr); + +?> +--EXPECT-- +array(2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} diff --git a/ext/spl/tests/ArrayObject_overloaded_object_incompatible.phpt b/ext/spl/tests/ArrayObject_overloaded_object_incompatible.phpt new file mode 100644 index 0000000000..8c1121b8d0 --- /dev/null +++ b/ext/spl/tests/ArrayObject_overloaded_object_incompatible.phpt @@ -0,0 +1,27 @@ +--TEST-- +Objects with overloaded get_properties are incompatible with ArrayObject +--FILE-- +<?php + +$ao = new ArrayObject([1, 2, 3]); +try { + $ao->exchangeArray(new SplFixedArray); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +var_dump($ao); + +?> +--EXPECT-- +Overloaded object of type SplFixedArray is not compatible with ArrayObject +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} diff --git a/ext/spl/tests/ArrayObject_std_props_no_recursion.phpt b/ext/spl/tests/ArrayObject_std_props_no_recursion.phpt new file mode 100644 index 0000000000..193e972530 --- /dev/null +++ b/ext/spl/tests/ArrayObject_std_props_no_recursion.phpt @@ -0,0 +1,28 @@ +--TEST-- +Don't recurse into USE_OTHER when checking for STD_PROP_LIST +--FILE-- +<?php + +$a = new ArrayObject([1, 2, 3], ArrayObject::STD_PROP_LIST); +$a->prop = 'a'; +$b = new ArrayObject($a, 0); +$b->prop = 'b'; +var_dump((array) $b); +$c = new ArrayObject($a); +$c->prop = 'c'; +var_dump((array) $c); + +?> +--EXPECT-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(1) { + ["prop"]=> + string(1) "c" +} diff --git a/ext/spl/tests/bug71617.phpt b/ext/spl/tests/bug71617.phpt new file mode 100644 index 0000000000..412f83f541 --- /dev/null +++ b/ext/spl/tests/bug71617.phpt @@ -0,0 +1,50 @@ +--TEST-- +Bug #71617: private properties lost when unserializing ArrayObject +--FILE-- +<?php + +class Test extends ArrayObject +{ + + private $name = null; + + public function __construct(array $input) + { + parent::__construct($input, ArrayObject::ARRAY_AS_PROPS); + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getName() + { + return $this->name; + } +} + +$test = new Test(['a' => 'a', 'b' => 'b']); +$test->setName('ok'); + +$ser = serialize($test); +$unSer = unserialize($ser); + +var_dump($unSer->getName()); +var_dump($unSer); + +?> +--EXPECT-- +string(2) "ok" +object(Test)#2 (2) { + ["name":"Test":private]=> + string(2) "ok" + ["storage":"ArrayObject":private]=> + array(2) { + ["a"]=> + string(1) "a" + ["b"]=> + string(1) "b" + } +} diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 6f2656ab51..912cc9cb2d 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -117,7 +117,8 @@ PHP_METHOD(sqlite3, open) if (strlen(filename) != filename_len) { return; } - if (memcmp(filename, ":memory:", sizeof(":memory:")) != 0) { + if (filename_len != sizeof(":memory:")-1 || + memcmp(filename, ":memory:", sizeof(":memory:")-1) != 0) { if (!(fullpath = expand_filepath(filename, NULL))) { zend_throw_exception(zend_ce_exception, "Unable to expand filepath", 0); return; diff --git a/ext/standard/array.c b/ext/standard/array.c index 62279287b6..def7d7c465 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1771,7 +1771,7 @@ PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t Imports variables into symbol table from an array */ PHP_FUNCTION(extract) { - zval *var_array, *prefix = NULL; + zval *var_array_param, *prefix = NULL; zend_long extract_type = EXTR_OVERWRITE; zval *entry; zend_string *var_name; @@ -1779,14 +1779,15 @@ PHP_FUNCTION(extract) int var_exists, count = 0; int extract_refs = 0; zend_array *symbol_table; + zval var_array; #ifndef FAST_ZPP - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array_param, &extract_type, &prefix) == FAILURE) { return; } #else ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_ARRAY(var_array) + Z_PARAM_ARRAY(var_array_param) Z_PARAM_OPTIONAL Z_PARAM_LONG(extract_type) Z_PARAM_ZVAL_EX(prefix, 0, 1) @@ -1795,7 +1796,7 @@ PHP_FUNCTION(extract) extract_refs = (extract_type & EXTR_REFS); if (extract_refs) { - SEPARATE_ZVAL(var_array); + SEPARATE_ZVAL(var_array_param); } extract_type &= 0xff; @@ -1825,7 +1826,11 @@ PHP_FUNCTION(extract) } #endif - ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(var_array), num_key, var_name, entry) { + /* The array might be stored in a local variable that will be overwritten. To avoid losing the + * reference in that case we work on a copy. */ + ZVAL_COPY(&var_array, var_array_param); + + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(var_array), num_key, var_name, entry) { zval final_name; ZVAL_NULL(&final_name); @@ -1926,6 +1931,7 @@ PHP_FUNCTION(extract) } zval_dtor(&final_name); } ZEND_HASH_FOREACH_END(); + zval_ptr_dtor(&var_array); RETURN_LONG(count); } @@ -1938,6 +1944,7 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu ZVAL_DEREF(entry); if (Z_TYPE_P(entry) == IS_STRING) { if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) { + ZVAL_DEREF(value_ptr); ZVAL_COPY(&data, value_ptr); zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data); } @@ -3491,6 +3498,10 @@ static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv) } } + if (prop) { + ZVAL_DEREF(prop); + } + return prop; } diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 480da221a4..7e5a8987b4 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -206,7 +206,7 @@ PHP_FUNCTION(iptcembed) } if (iptcdata_len >= SIZE_MAX - sizeof(psheader) - 1025) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "IPTC data too large"); + php_error_docref(NULL, E_WARNING, "IPTC data too large"); RETURN_FALSE; } diff --git a/ext/standard/pack.c b/ext/standard/pack.c index ab7e9c71dc..a24ee69ad2 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -986,7 +986,7 @@ PHP_FUNCTION(unpack) /* Reached end of input for '*' repeater */ break; } else { - php_error_docref(NULL, E_WARNING, "Type %c: not enough input, need %d, have %d", type, size, inputlen - inputpos); + php_error_docref(NULL, E_WARNING, "Type %c: not enough input, need %d, have " ZEND_LONG_FMT, type, size, inputlen - inputpos); zval_dtor(return_value); RETURN_FALSE; } diff --git a/ext/standard/string.c b/ext/standard/string.c index 2dbe41ed5e..489006b261 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -4943,7 +4943,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha * state == 2 (PHP). Switch back to HTML. */ - if (state == 2 && p > buf+2 && strncasecmp(p-4, "<?xm", 4) == 0) { + if (state == 2 && p > buf+4 && strncasecmp(p-4, "<?xm", 4) == 0) { state = 1; is_xml=1; break; } diff --git a/ext/standard/tests/array/bug71603.phpt b/ext/standard/tests/array/bug71603.phpt new file mode 100644 index 0000000000..0c25be660c --- /dev/null +++ b/ext/standard/tests/array/bug71603.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #71603 (compact() maintains references in php7) +--FILE-- +<?php +$foo = "okey"; +$foo_reference =& $foo; + +$array = compact('foo_reference'); + +$foo = 'changed!'; + +var_dump($array['foo_reference']); + +--EXPECT-- +string(4) "okey" diff --git a/ext/standard/tests/array/bug71660.phpt b/ext/standard/tests/array/bug71660.phpt new file mode 100644 index 0000000000..c2d7192378 --- /dev/null +++ b/ext/standard/tests/array/bug71660.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #71660 (array_column behaves incorrectly after foreach by reference) +--FILE-- +<?php +$arr = array('id' => 12345, 'name' => 'sam'); +foreach ($arr as &$v) { + $v = $v; +} + +$arr = [$arr]; + +var_dump(array_column($arr, 'name', 'id')); +?> +--EXPECT-- +array(1) { + [12345]=> + string(3) "sam" +} diff --git a/ext/standard/tests/math/mt_rand_value.phpt b/ext/standard/tests/math/mt_rand_value.phpt new file mode 100644 index 0000000000..772305ad63 --- /dev/null +++ b/ext/standard/tests/math/mt_rand_value.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test mt_rand() output +--FILE-- +<?php + +mt_srand(12345678); + +for ($i=0; $i<16; $i++) { + echo mt_rand().PHP_EOL; +} +echo PHP_EOL; + +$x = 0; +for ($i=0; $i<1024; $i++) { + $x ^= mt_rand(); +} +echo $x.PHP_EOL; + +/* + * Note that the output will be different from the original mt19937ar.c, + * because PHP's implementation contains a bug. Thus, this test actually + * checks to make sure that PHP's behaviour is wrong, but consistently so. + */ + +?> +--EXPECTF-- +1614640687 +1711027313 +857485497 +688176834 +1386682158 +412773096 +813703253 +898651287 +2087374214 +1382556330 +1640700129 +1863374167 +1324097651 +1923803667 +676334965 +853386222 + +1571178311 diff --git a/ext/standard/var.c b/ext/standard/var.c index 61a7179dbb..fcee7a9cc6 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -108,7 +108,7 @@ again: php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc)); break; case IS_STRING: - php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_P(struc)); + php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc)); PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc)); PUTS("\"\n"); break; @@ -278,7 +278,7 @@ again: php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc)); break; case IS_STRING: - php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_P(struc)); + php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc)); PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc)); php_printf("\" refcount(%u)\n", Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1); break; @@ -336,7 +336,7 @@ again: break; case IS_RESOURCE: { const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc)); - php_printf("%sresource(" ZEND_LONG_FMT ") of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc)); + php_printf("%sresource(%d) of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc)); break; } case IS_REFERENCE: @@ -1045,7 +1045,8 @@ PHP_FUNCTION(unserialize) } zval_ptr_dtor(return_value); if (!EG(exception)) { - php_error_docref(NULL, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %d bytes", (zend_long)((char*)p - buf), buf_len); + php_error_docref(NULL, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %zd bytes", + (zend_long)((char*)p - buf), buf_len); } RETURN_FALSE; } diff --git a/ext/xmlrpc/tests/bug71501.phpt b/ext/xmlrpc/tests/bug71501.phpt new file mode 100644 index 0000000000..950d21d6d4 --- /dev/null +++ b/ext/xmlrpc/tests/bug71501.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #71501 (xmlrpc_encode_request ignores encoding option) +--SKIPIF-- +<?php +if (!extension_loaded("xmlrpc")) print "skip"; +?> +--FILE-- +<?php +$params = 'Lê Trung Hiếu'; +echo xmlrpc_encode_request('foo', $params, ['encoding' => 'UTF-8', 'escaping' => 'markup']); +?> +--EXPECTF-- +<?xml version="1.0" encoding="UTF-8"?> +<methodCall> +<methodName>foo</methodName> +<params> + <param> + <value> + <string>Lê Trung Hiếu</string> + </value> + </param> +</params> +</methodCall> diff --git a/ext/xmlrpc/xmlrpc-epi-php.c b/ext/xmlrpc/xmlrpc-epi-php.c index dd39047bf0..ea62bdc9a9 100644 --- a/ext/xmlrpc/xmlrpc-epi-php.c +++ b/ext/xmlrpc/xmlrpc-epi-php.c @@ -411,45 +411,46 @@ static void set_output_options(php_output_options* options, zval* output_opts) } } - /* encoding code set */ - if ((val = zend_hash_str_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN)) != NULL) { - if (Z_TYPE_P(val) == IS_STRING) { - options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_P(val)); - } + } + + /* encoding code set */ + if ((val = zend_hash_str_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN)) != NULL) { + if (Z_TYPE_P(val) == IS_STRING) { + options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_P(val)); } + } - /* escaping options */ - if ((val = zend_hash_str_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN)) != NULL) { - /* multiple values allowed. check if array */ - if (Z_TYPE_P(val) == IS_ARRAY) { - zval* iter_val; - - options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping; - - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), iter_val) { - if (Z_TYPE_P(iter_val) == IS_STRING && Z_STRVAL_P(iter_val)) { - if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_CDATA)) { - options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping; - } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_NON_ASCII)) { - options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping; - } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_NON_PRINT)) { - options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping; - } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_MARKUP)) { - options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping; - } + /* escaping options */ + if ((val = zend_hash_str_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN)) != NULL) { + /* multiple values allowed. check if array */ + if (Z_TYPE_P(val) == IS_ARRAY) { + zval* iter_val; + + options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping; + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), iter_val) { + if (Z_TYPE_P(iter_val) == IS_STRING && Z_STRVAL_P(iter_val)) { + if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_CDATA)) { + options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping; + } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_NON_ASCII)) { + options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping; + } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_NON_PRINT)) { + options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping; + } else if (!strcmp(Z_STRVAL_P(iter_val), ESCAPING_VALUE_MARKUP)) { + options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping; } - } ZEND_HASH_FOREACH_END(); - /* else, check for single value */ - } else if (Z_TYPE_P(val) == IS_STRING) { - if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_CDATA)) { - options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping; - } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_NON_ASCII)) { - options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping; - } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_NON_PRINT)) { - options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping; - } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_MARKUP)) { - options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping; } + } ZEND_HASH_FOREACH_END(); + /* else, check for single value */ + } else if (Z_TYPE_P(val) == IS_STRING) { + if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_CDATA)) { + options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping; + } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_NON_ASCII)) { + options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping; + } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_NON_PRINT)) { + options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping; + } else if (!strcmp(Z_STRVAL_P(val), ESCAPING_VALUE_MARKUP)) { + options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping; } } } diff --git a/ext/xsl/tests/bug71540.phpt b/ext/xsl/tests/bug71540.phpt new file mode 100644 index 0000000000..a268021765 --- /dev/null +++ b/ext/xsl/tests/bug71540.phpt @@ -0,0 +1,69 @@ +--TEST-- +Bug #71540 (NULL pointer dereference in xsl_ext_function_php()) +--SKIPIF-- +<?php +if (!extension_loaded('xsl')) die("skip Extension XSL is required\n"); +?> +--FILE-- +<?php +$xml = <<<EOB +<allusers> + <user> + <uid>bob</uid> + </user> +</allusers> +EOB; +$xsl = <<<EOB +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:php="http://php.net/xsl"> +<xsl:output method="html" encoding="utf-8" indent="yes"/> + <xsl:template match="allusers"> + <html><body> + <h2>Users</h2> + <table> + <xsl:for-each select="user"> + <tr><td> + <xsl:value-of + select="php:function('test',uid,test(test))"/> + </td></tr> + </xsl:for-each> + </table> + </body></html> + </xsl:template> +</xsl:stylesheet> +EOB; + +$xmldoc = new DOMDocument(); +$xmldoc->loadXML($xml); +$xsldoc = new DOMDocument(); +$xsldoc->loadXML($xsl); + +$proc = new XSLTProcessor(); +$proc->registerPHPFunctions(); +$proc->importStyleSheet($xsldoc); +echo $proc->transformToXML($xmldoc); +?> +DONE +--EXPECTF-- +Warning: XSLTProcessor::transformToXml(): xmlXPathCompOpEval: function test not found in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): Unregistered function in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): Stack usage errror in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): Stack usage errror in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): Handler name must be a string in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): xmlXPathCompiledEval: 2 objects left on the stack. in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): runtime error: file %s line 13 element value-of in %sbug71540.php on line %d + +Warning: XSLTProcessor::transformToXml(): XPath evaluation returned no result. in %sbug71540.php on line %d +<html xmlns:php="http://php.net/xsl"><body> +<h2>Users</h2> +<table><tr><td></td></tr></table> +</body></html> +DONE
\ No newline at end of file diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index be46d38de1..600c7cddb0 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -231,6 +231,10 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t /* Reverse order to pop values off ctxt stack */ for (i = nargs - 2; i >= 0; i--) { obj = valuePop(ctxt); + if (obj == NULL) { + ZVAL_NULL(&args[i]); + continue; + } switch (obj->type) { case XPATH_STRING: ZVAL_STRING(&args[i], (char *)obj->stringval); @@ -300,7 +304,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t obj = valuePop(ctxt); - if (obj->stringval == NULL) { + if (obj == NULL || obj->stringval == NULL) { php_error_docref(NULL, E_WARNING, "Handler name must be a string"); xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewString((const xmlChar *) "")); diff --git a/ext/zip/config.m4 b/ext/zip/config.m4 index 6dbc1e292b..81f47df556 100644 --- a/ext/zip/config.m4 +++ b/ext/zip/config.m4 @@ -122,6 +122,7 @@ if test "$PHP_ZIP" != "no"; then lib/zip_get_archive_comment.c lib/zip_get_archive_flag.c lib/zip_get_compression_implementation.c\ lib/zip_get_encryption_implementation.c lib/zip_get_file_comment.c lib/zip_get_name.c lib/zip_get_num_entries.c \ lib/zip_get_num_files.c lib/zip_memdup.c lib/zip_name_locate.c lib/zip_new.c lib/zip_open.c lib/zip_rename.c lib/zip_replace.c\ + lib/zip_hash.c \ lib/zip_set_archive_comment.c lib/zip_set_archive_flag.c lib/zip_set_default_password.c lib/zip_set_file_comment.c\ lib/zip_set_file_compression.c lib/zip_set_name.c lib/zip_source_buffer.c lib/zip_source_close.c lib/zip_source_crc.c\ lib/zip_source_deflate.c lib/zip_source_error.c lib/zip_source_file.c lib/zip_source_filep.c lib/zip_source_free.c\ diff --git a/ext/zip/config.w32 b/ext/zip/config.w32 index 0aa9f3eaa0..5460b6d6bd 100644 --- a/ext/zip/config.w32 +++ b/ext/zip/config.w32 @@ -21,6 +21,7 @@ if (PHP_ZIP != "no") { zip_get_archive_comment.c zip_get_archive_flag.c zip_get_compression_implementation.c\ zip_get_encryption_implementation.c zip_get_file_comment.c zip_get_name.c zip_get_num_entries.c \ zip_get_num_files.c zip_memdup.c zip_name_locate.c zip_new.c zip_open.c zip_rename.c zip_replace.c\ + zip_hash.c \ zip_set_archive_comment.c zip_set_archive_flag.c zip_set_default_password.c zip_set_file_comment.c\ zip_set_file_compression.c zip_set_name.c zip_source_buffer.c zip_source_close.c zip_source_crc.c\ zip_source_deflate.c zip_source_error.c zip_source_filep.c zip_source_free.c\ diff --git a/ext/zip/lib/zip_add_entry.c b/ext/zip/lib/zip_add_entry.c index 24dbdaf47c..9a9465c5f0 100644 --- a/ext/zip/lib/zip_add_entry.c +++ b/ext/zip/lib/zip_add_entry.c @@ -1,6 +1,6 @@ /* zip_add_entry.c -- create and init struct zip_entry - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -46,8 +46,19 @@ _zip_add_entry(zip_t *za) if (za->nentry+1 >= za->nentry_alloc) { zip_entry_t *rentries; - zip_uint64_t nalloc = za->nentry_alloc + 16; - zip_uint64_t realloc_size = sizeof(struct zip_entry) * (size_t)nalloc; + zip_uint64_t nalloc = za->nentry_alloc; + zip_uint64_t additional_entries = 2 * nalloc; + zip_uint64_t realloc_size; + + if (additional_entries < 16) { + additional_entries = 16; + } + else if (additional_entries > 1024) { + additional_entries = 1024; + } + /* neither + nor * overflows can happen: nentry_alloc * sizeof(struct zip_entry) < UINT64_MAX */ + nalloc += additional_entries; + realloc_size = sizeof(struct zip_entry) * (size_t)nalloc; if (sizeof(struct zip_entry) * (size_t)za->nentry_alloc > realloc_size) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); diff --git a/ext/zip/lib/zip_buffer.c b/ext/zip/lib/zip_buffer.c index 3d79b09f13..43864f9ba9 100644 --- a/ext/zip/lib/zip_buffer.c +++ b/ext/zip/lib/zip_buffer.c @@ -303,6 +303,17 @@ _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset) } +int +_zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length) { + zip_uint64_t offset = buffer->offset + length; + + if (offset < buffer->offset) { + buffer->ok = false; + return -1; + } + return _zip_buffer_set_offset(buffer, offset); +} + zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer) { diff --git a/ext/zip/lib/zip_close.c b/ext/zip/lib/zip_close.c index a13e4466b3..b5eca67a46 100644 --- a/ext/zip/lib/zip_close.c +++ b/ext/zip/lib/zip_close.c @@ -40,7 +40,6 @@ #ifdef HAVE_STRINGS_H #include <strings.h> #endif -#include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif diff --git a/ext/zip/lib/zip_delete.c b/ext/zip/lib/zip_delete.c index b3e7abb848..34520b0310 100644 --- a/ext/zip/lib/zip_delete.c +++ b/ext/zip/lib/zip_delete.c @@ -1,6 +1,6 @@ /* zip_delete.c -- delete file from zip archive - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -38,6 +38,8 @@ ZIP_EXTERN int zip_delete(zip_t *za, zip_uint64_t idx) { + const char *name; + if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; @@ -48,6 +50,14 @@ zip_delete(zip_t *za, zip_uint64_t idx) return -1; } + if ((name=_zip_get_name(za, idx, 0, &za->error)) == NULL) { + return -1; + } + + if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) { + return -1; + } + /* allow duplicate file names, because the file will * be removed directly afterwards */ if (_zip_unchange(za, idx, 1) != 0) diff --git a/ext/zip/lib/zip_dirent.c b/ext/zip/lib/zip_dirent.c index e3a78b3146..630b6a49cb 100644 --- a/ext/zip/lib/zip_dirent.c +++ b/ext/zip/lib/zip_dirent.c @@ -1,6 +1,6 @@ /* zip_dirent.c -- read directory entry (local or central), clean dirent - Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -17,7 +17,7 @@ 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,7 +35,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> #include <sys/types.h> #include <sys/stat.h> @@ -67,7 +66,7 @@ _zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) { zip_cdir_t *cd; zip_uint64_t i; - + if ((cd=(zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; @@ -110,7 +109,7 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor } offset = (zip_uint64_t)off; - is_zip64 = 0; + is_zip64 = false; for (i=0; i<survivors; i++) { zip_entry_t *entry = za->entry+filelist[i].idx; @@ -135,7 +134,7 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } - + if (is_zip64) { _zip_buffer_put(buffer, EOCD64_MAGIC, 4); _zip_buffer_put_64(buffer, EOCD64LEN-12); @@ -152,7 +151,7 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor _zip_buffer_put_64(buffer, offset+size); _zip_buffer_put_32(buffer, 1); } - + _zip_buffer_put(buffer, EOCD_MAGIC, 4); _zip_buffer_put_32(buffer, 0); _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); @@ -163,7 +162,7 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor comment = za->comment_changed ? za->comment_changes : za->comment_orig; _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); - + if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); @@ -199,7 +198,7 @@ _zip_dirent_clone(const zip_dirent_t *sde) memcpy(tde, sde, sizeof(*sde)); else _zip_dirent_init(tde); - + tde->changed = 0; tde->cloned = 1; @@ -289,7 +288,7 @@ _zip_dirent_new(void) Fills the zip directory entry zde. If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed. - + If local is true, it reads a local header instead of a central directory entry. Returns size of dirent read if successful. On error, error is filled in and -1 is returned. @@ -304,7 +303,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo zip_uint16_t filename_len, comment_len, ef_len; bool from_buffer = (buffer != NULL); - + size = local ? LENTRYSIZE : CDENTRYSIZE; if (buffer) { @@ -337,19 +336,19 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo zde->version_needed = _zip_buffer_get_16(buffer); zde->bitflags = _zip_buffer_get_16(buffer); zde->comp_method = _zip_buffer_get_16(buffer); - + /* convert to time_t */ dostime = _zip_buffer_get_16(buffer); dosdate = _zip_buffer_get_16(buffer); zde->last_mod = _zip_d2u_time(dostime, dosdate); - + zde->crc = _zip_buffer_get_32(buffer); zde->comp_size = _zip_buffer_get_32(buffer); zde->uncomp_size = _zip_buffer_get_32(buffer); - + filename_len = _zip_buffer_get_16(buffer); ef_len = _zip_buffer_get_16(buffer); - + if (local) { comment_len = 0; zde->disk_number = 0; @@ -363,7 +362,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo zde->ext_attrib = _zip_buffer_get_32(buffer); zde->offset = _zip_buffer_get_32(buffer); } - + if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (!from_buffer) { @@ -386,7 +385,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } else { _zip_buffer_free(buffer); - + if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) { return -1; } @@ -424,7 +423,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } return -1; } - if ((zde->extra_fields=_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error)) == NULL) { + if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) { free(ef); if (!from_buffer) { _zip_buffer_free(buffer); @@ -471,7 +470,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } return -1; } - + if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); if (!from_buffer) { @@ -479,11 +478,14 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } return -1; } - + if (zde->uncomp_size == ZIP_UINT32_MAX) zde->uncomp_size = _zip_buffer_get_64(ef_buffer); - else if (local) - ef += 8; + else if (local) { + /* From appnote.txt: This entry in the Local header MUST + include BOTH original and compressed file size fields. */ + (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ + } if (zde->comp_size == ZIP_UINT32_MAX) zde->comp_size = _zip_buffer_get_64(ef_buffer); if (!local) { @@ -492,7 +494,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo if (zde->disk_number == ZIP_UINT16_MAX) zde->disk_number = _zip_buffer_get_32(buffer); } - + if (!_zip_buffer_eof(ef_buffer)) { zip_error_set(error, ZIP_ER_INCONS, 0); _zip_buffer_free(ef_buffer); @@ -503,7 +505,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } _zip_buffer_free(ef_buffer); } - + if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (!from_buffer) { @@ -520,7 +522,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo zip_error_set(error, ZIP_ER_SEEK, EFBIG); return -1; } - + zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields); return (zip_int64_t)(size + variable_size); @@ -535,15 +537,15 @@ _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string zip_buffer_t *buffer; const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL); - + if (ef == NULL || ef_len < 5 || ef[0] != 1) { return str; } - + if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { return str; } - + _zip_buffer_get_8(buffer); ef_crc = _zip_buffer_get_32(buffer); @@ -556,9 +558,9 @@ _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string str = ef_str; } } - + _zip_buffer_free(buffer); - + return str; } @@ -578,7 +580,7 @@ _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) _zip_error_set_from_source(error, src); return -1; } - + if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) { return -1; } @@ -586,7 +588,7 @@ _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) for (i=0; i<(local ? 2 : 3); i++) { size += _zip_buffer_get_16(buffer); } - + if (!_zip_buffer_eof(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); @@ -614,16 +616,15 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) zip_uint16_t dostime, dosdate; zip_encoding_type_t com_enc, name_enc; zip_extra_field_t *ef; + zip_extra_field_t *ef64; + zip_uint32_t ef_total_size; bool is_zip64; bool is_really_zip64; zip_uint8_t buf[CDENTRYSIZE]; zip_buffer_t *buffer; - zip_uint32_t ef_total_size; ef = NULL; - is_zip64 = false; - name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); @@ -648,20 +649,19 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) ef = ef2; } } - + is_really_zip64 = _zip_dirent_needs_zip64(de, flags); is_zip64 = (flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64) || is_really_zip64; - + if (is_zip64) { zip_uint8_t ef_zip64[EFZIP64SIZE]; zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64)); - zip_extra_field_t *ef64; if (ef_buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef); return -1; } - + if (flags & ZIP_FL_LOCAL) { if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) { _zip_buffer_put_64(ef_buffer, de->uncomp_size); @@ -681,7 +681,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) } } } - + if (!_zip_buffer_ok(ef_buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ef_buffer); @@ -700,9 +700,9 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) _zip_ef_free(ef); return -1; } - + _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4); - + if ((flags & ZIP_FL_LOCAL) == 0) { _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby)); } @@ -715,7 +715,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) _zip_buffer_put_16(buffer, dosdate); _zip_buffer_put_32(buffer, de->crc); - + if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) { /* In local headers, if a ZIP64 EF is written, it MUST contain * both compressed and uncompressed sizes (even if one of the @@ -744,7 +744,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) /* TODO: check for overflow */ ef_total_size = (zip_uint32_t)_zip_ef_size(de->extra_fields, flags) + (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size); - + if ((flags & ZIP_FL_LOCAL) == 0) { _zip_buffer_put_16(buffer, _zip_string_length(de->comment)); _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); @@ -755,7 +755,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) else _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } - + if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(buffer); @@ -768,7 +768,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) _zip_ef_free(ef); return -1; } - + _zip_buffer_free(buffer); if (de->filename) { @@ -810,10 +810,10 @@ _zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) struct tm tm; memset(&tm, 0, sizeof(tm)); - + /* let mktime decide if DST is in effect */ tm.tm_isdst = -1; - + tm.tm_year = ((ddate>>9)&127) + 1980 - 1900; tm.tm_mon = ((ddate>>5)&15) - 1; tm.tm_mday = ddate&31; @@ -834,13 +834,16 @@ _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) zip_buffer_t *buffer; zip_extra_field_t *ef; - raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL); + if ((raw=_zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { + /* error already set */ + return NULL; + } if (len+5 > ZIP_UINT16_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */ return NULL; } - + if ((buffer = _zip_buffer_new(NULL, len+5)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; @@ -855,7 +858,7 @@ _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) _zip_buffer_free(buffer); return NULL; } - + ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH); _zip_buffer_free(buffer); @@ -898,6 +901,10 @@ _zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) struct tm *tm; tm = localtime(&intime); + if (tm->tm_year < 80) { + tm->tm_year = 80; + } + *ddate = (zip_uint16_t)(((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday); *dtime = (zip_uint16_t)(((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1)); diff --git a/ext/zip/lib/zip_discard.c b/ext/zip/lib/zip_discard.c index db22370842..1876c84f0c 100644 --- a/ext/zip/lib/zip_discard.c +++ b/ext/zip/lib/zip_discard.c @@ -1,6 +1,6 @@ /* zip_discard.c -- discard and free struct zip - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -58,6 +58,8 @@ zip_discard(zip_t *za) _zip_string_free(za->comment_orig); _zip_string_free(za->comment_changes); + _zip_hash_free(za->names); + if (za->entry) { for (i=0; i<za->nentry; i++) _zip_entry_finalize(za->entry+i); diff --git a/ext/zip/lib/zip_error.c b/ext/zip/lib/zip_error.c index a21a00bc29..43ddf4f9cb 100644 --- a/ext/zip/lib/zip_error.c +++ b/ext/zip/lib/zip_error.c @@ -1,6 +1,6 @@ /* zip_error.c -- zip_error_t helper functions - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -31,7 +31,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdlib.h> #include "zipint.h" diff --git a/ext/zip/lib/zip_error_strerror.c b/ext/zip/lib/zip_error_strerror.c index 2f124ccd46..29efc8a91c 100644 --- a/ext/zip/lib/zip_error_strerror.c +++ b/ext/zip/lib/zip_error_strerror.c @@ -1,6 +1,6 @@ /* zip_error_sterror.c -- get string representation of struct zip_error - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ */ -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/ext/zip/lib/zip_error_to_str.c b/ext/zip/lib/zip_error_to_str.c index d4119253f7..22de177842 100644 --- a/ext/zip/lib/zip_error_to_str.c +++ b/ext/zip/lib/zip_error_to_str.c @@ -1,6 +1,6 @@ /* zip_error_to_str.c -- get string representation of zip error code - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ */ -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/ext/zip/lib/zip_extra_field.c b/ext/zip/lib/zip_extra_field.c index b2566c6887..035047827e 100644 --- a/ext/zip/lib/zip_extra_field.c +++ b/ext/zip/lib/zip_extra_field.c @@ -31,13 +31,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include "zipint.h" - -#include <errno.h> #include <stdlib.h> #include <string.h> +#include "zipint.h" + zip_extra_field_t * _zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) @@ -207,20 +205,20 @@ _zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_fla } -zip_extra_field_t * -_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_error_t *error) +bool +_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) { zip_buffer_t *buffer; zip_extra_field_t *ef, *ef2, *ef_head; if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); - return NULL; + return false; } ef_head = ef = NULL; - while (_zip_buffer_ok(buffer) && !_zip_buffer_eof(buffer)) { + while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) { zip_uint16_t fid, flen; zip_uint8_t *ef_data; @@ -229,14 +227,17 @@ _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_ ef_data = _zip_buffer_get(buffer, flen); if (ef_data == NULL) { - break; + zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_buffer_free(buffer); + _zip_ef_free(ef_head); + return false; } if ((ef2=_zip_ef_new(fid, flen, ef_data, flags)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_buffer_free(buffer); _zip_ef_free(ef_head); - return NULL; + return false; } if (ef_head) { @@ -248,15 +249,29 @@ _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_ } if (!_zip_buffer_eof(buffer)) { - zip_error_set(error, ZIP_ER_INCONS, 0); - _zip_buffer_free(buffer); - _zip_ef_free(ef_head); - return NULL; + /* Android APK files align stored file data with padding in extra fields; ignore. */ + /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */ + size_t glen = _zip_buffer_left(buffer); + zip_uint8_t *garbage; + garbage = _zip_buffer_get(buffer, glen); + if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", glen) != 0) { + zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_buffer_free(buffer); + _zip_ef_free(ef_head); + return false; + } } _zip_buffer_free(buffer); + + if (ef_head_p) { + *ef_head_p = ef_head; + } + else { + _zip_ef_free(ef_head); + } - return ef_head; + return true; } @@ -400,14 +415,16 @@ _zip_read_local_ef(zip_t *za, zip_uint64_t idx) if (ef_raw == NULL) return -1; - if ((ef=_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &za->error)) == NULL) { + if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) { free(ef_raw); return -1; } free(ef_raw); - - ef = _zip_ef_remove_internal(ef); - e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); + + if (ef) { + ef = _zip_ef_remove_internal(ef); + e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); + } } e->orig->local_extra_fields_read = 1; diff --git a/ext/zip/lib/zip_fdopen.c b/ext/zip/lib/zip_fdopen.c index c5b55311d2..bbcdf4f6bf 100644 --- a/ext/zip/lib/zip_fdopen.c +++ b/ext/zip/lib/zip_fdopen.c @@ -33,6 +33,9 @@ #include "zipint.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif ZIP_EXTERN zip_t * diff --git a/ext/zip/lib/zip_file_get_offset.c b/ext/zip/lib/zip_file_get_offset.c index 1aaca712d7..0257b042bc 100644 --- a/ext/zip/lib/zip_file_get_offset.c +++ b/ext/zip/lib/zip_file_get_offset.c @@ -1,6 +1,6 @@ /* zip_file_get_offset.c -- get offset of file data in archive. - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -35,7 +35,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> #include <sys/types.h> #include <sys/stat.h> diff --git a/ext/zip/lib/zip_filerange_crc.c b/ext/zip/lib/zip_filerange_crc.c index 8e06e8fa8b..f2a27fab34 100644 --- a/ext/zip/lib/zip_filerange_crc.c +++ b/ext/zip/lib/zip_filerange_crc.c @@ -1,6 +1,6 @@ /* zip_filerange_crc.c -- compute CRC32 for a range of a file - Copyright (C) 2008-2014 Dieter Baron and Thomas Klausner + Copyright (C) 2008-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -33,7 +33,6 @@ #include <stdio.h> -#include <errno.h> #include "zipint.h" diff --git a/ext/zip/lib/zip_fopen_index.c b/ext/zip/lib/zip_fopen_index.c index e9a169a2e1..7496f9829f 100644 --- a/ext/zip/lib/zip_fopen_index.c +++ b/ext/zip/lib/zip_fopen_index.c @@ -1,6 +1,6 @@ /* zip_fopen_index.c -- open file in zip archive for reading by index - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ */ -#include <errno.h> #include <stdio.h> #include <stdlib.h> diff --git a/ext/zip/lib/zip_fopen_index_encrypted.c b/ext/zip/lib/zip_fopen_index_encrypted.c index 21cc43333c..92258e85fe 100644 --- a/ext/zip/lib/zip_fopen_index_encrypted.c +++ b/ext/zip/lib/zip_fopen_index_encrypted.c @@ -1,6 +1,6 @@ /* zip_fopen_index_encrypted.c -- open file for reading by index w/ password - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ */ -#include <errno.h> #include <stdio.h> #include <stdlib.h> diff --git a/ext/zip/lib/zip_hash.c b/ext/zip/lib/zip_hash.c new file mode 100644 index 0000000000..23f9708dfd --- /dev/null +++ b/ext/zip/lib/zip_hash.c @@ -0,0 +1,267 @@ +/* + zip_hash.c -- hash table string -> uint64 + Copyright (C) 2015-2016 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <string.h> +#include "zipint.h" + +struct zip_hash_entry { + const zip_uint8_t *name; + zip_int64_t orig_index; + zip_int64_t current_index; + struct zip_hash_entry *next; +}; +typedef struct zip_hash_entry zip_hash_entry_t; + +struct zip_hash { + zip_uint16_t table_size; + zip_hash_entry_t **table; +}; + +zip_hash_t * +_zip_hash_new(zip_uint16_t table_size, zip_error_t *error) +{ + zip_hash_t *hash; + + if (table_size == 0) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return NULL; + } + + if ((hash=(zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + hash->table_size = table_size; + if ((hash->table=(zip_hash_entry_t**)calloc(table_size, sizeof(zip_hash_entry_t *))) == NULL) { + free(hash); + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + return hash; +} + +static void +_free_list(zip_hash_entry_t *entry) +{ + zip_hash_entry_t *next; + do { + next = entry->next; + free(entry); + entry = next; + } while (entry != NULL); +} + +void +_zip_hash_free(zip_hash_t *hash) +{ + zip_uint16_t i; + + if (hash == NULL) { + return; + } + + for (i=0; i<hash->table_size; i++) { + if (hash->table[i] != NULL) { + _free_list(hash->table[i]); + } + } + free(hash->table); + free(hash); +} + +static zip_uint16_t +_hash_string(const zip_uint8_t *name, zip_uint16_t size) +{ +#define HASH_MULTIPLIER 33 + zip_uint16_t value = 5381; + + if (name == NULL) + return 0; + + while (*name != 0) { + value = (zip_uint16_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % size); + name++; + } + + return value; +} + +/* insert into hash, return error on existence or memory issues */ +bool +_zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error) +{ + zip_uint16_t hash_value; + zip_hash_entry_t *entry; + + if (hash == NULL || name == NULL || index > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return false; + } + + hash_value = _hash_string(name, hash->table_size); + for (entry = hash->table[hash_value]; entry != NULL; entry = entry->next) { + if (strcmp((const char *)name, (const char *)entry->name) == 0) { + if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) { + zip_error_set(error, ZIP_ER_EXISTS, 0); + return false; + } + else { + break; + } + } + } + + if (entry == NULL) { + if ((entry=(zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + entry->name = name; + entry->next = hash->table[hash_value]; + hash->table[hash_value] = entry; + entry->orig_index = -1; + } + + if (flags & ZIP_FL_UNCHANGED) { + entry->orig_index = (zip_int64_t)index; + } + entry->current_index = (zip_int64_t)index; + + return true; +} + +/* remove entry from hash, error if not found */ +bool +_zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error) +{ + zip_uint16_t hash_value; + zip_hash_entry_t *entry, *previous; + + if (hash == NULL || name == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return false; + } + + hash_value = _hash_string(name, hash->table_size); + previous = NULL; + entry = hash->table[hash_value]; + while (entry) { + if (strcmp((const char *)name, (const char *)entry->name) == 0) { + if (entry->orig_index == -1) { + if (previous) { + previous->next = entry->next; + } + else { + hash->table[hash_value] = entry->next; + } + free(entry); + } + else { + entry->current_index = -1; + } + return true; + } + previous = entry; + entry = entry->next; + }; + + zip_error_set(error, ZIP_ER_NOENT, 0); + return false; +} + +/* find value for entry in hash, -1 if not found */ +zip_int64_t +_zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error) +{ + zip_uint16_t hash_value; + zip_hash_entry_t *entry; + + if (hash == NULL || name == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + hash_value = _hash_string(name, hash->table_size); + for (entry = hash->table[hash_value]; entry != NULL; entry = entry->next) { + if (strcmp((const char *)name, (const char *)entry->name) == 0) { + if (flags & ZIP_FL_UNCHANGED) { + if (entry->orig_index != -1) { + return entry->orig_index; + } + } + else { + if (entry->current_index != -1) { + return entry->current_index; + } + } + break; + } + } + + zip_error_set(error, ZIP_ER_NOENT, 0); + return -1; +} + +void +_zip_hash_revert(zip_hash_t *hash) +{ + zip_uint16_t i; + zip_hash_entry_t *entry, *previous; + + for (i = 0; i < hash->table_size; i++) { + previous = NULL; + entry = hash->table[i]; + while (entry) { + if (entry->orig_index == -1) { + zip_hash_entry_t *p; + if (previous) { + previous->next = entry->next; + } + else { + hash->table[i] = entry->next; + } + p = entry; + entry = entry->next; + /* previous does not change */ + free(p); + } + else { + entry->current_index = entry->orig_index; + previous = entry; + entry = entry->next; + } + } + } +} diff --git a/ext/zip/lib/zip_io_util.c b/ext/zip/lib/zip_io_util.c index 4a6bc1ddc1..b16927defb 100644 --- a/ext/zip/lib/zip_io_util.c +++ b/ext/zip/lib/zip_io_util.c @@ -1,6 +1,6 @@ /* zip_io_util.c -- I/O helper functions - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -31,7 +31,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdlib.h> #include <string.h> diff --git a/ext/zip/lib/zip_name_locate.c b/ext/zip/lib/zip_name_locate.c index 820ea0ca7f..50ca40b1a9 100644 --- a/ext/zip/lib/zip_name_locate.c +++ b/ext/zip/lib/zip_name_locate.c @@ -1,6 +1,6 @@ /* zip_name_locate.c -- get index by name - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -62,27 +62,33 @@ _zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags, zip_error_t *e return -1; } - cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; - - for (i=0; i<za->nentry; i++) { - fn = _zip_get_name(za, i, flags, error); - - /* newly added (partially filled) entry or error */ - if (fn == NULL) - continue; - - if (flags & ZIP_FL_NODIR) { - p = strrchr(fn, '/'); - if (p) - fn = p+1; + if (flags & (ZIP_FL_NOCASE|ZIP_FL_NODIR|ZIP_FL_ENC_CP437)) { + /* can't use hash table */ + cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; + + for (i=0; i<za->nentry; i++) { + fn = _zip_get_name(za, i, flags, error); + + /* newly added (partially filled) entry or error */ + if (fn == NULL) + continue; + + if (flags & ZIP_FL_NODIR) { + p = strrchr(fn, '/'); + if (p) + fn = p+1; + } + + if (cmp(fname, fn) == 0) { + _zip_error_clear(error); + return (zip_int64_t)i; + } } - if (cmp(fname, fn) == 0) { - _zip_error_clear(error); - return (zip_int64_t)i; - } + zip_error_set(error, ZIP_ER_NOENT, 0); + return -1; + } + else { + return _zip_hash_lookup(za->names, (const zip_uint8_t *)fname, flags, error); } - - zip_error_set(error, ZIP_ER_NOENT, 0); - return -1; } diff --git a/ext/zip/lib/zip_new.c b/ext/zip/lib/zip_new.c index d54a247c29..562dd76a36 100644 --- a/ext/zip/lib/zip_new.c +++ b/ext/zip/lib/zip_new.c @@ -1,6 +1,6 @@ /* zip_new.c -- create and init struct zip - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -52,6 +52,11 @@ _zip_new(zip_error_t *error) return NULL; } + if ((za->names = _zip_hash_new(ZIP_HASH_TABLE_SIZE, error)) == NULL) { + free(za); + return NULL; + } + za->src = NULL; za->open_flags = 0; zip_error_init(&za->error); diff --git a/ext/zip/lib/zip_open.c b/ext/zip/lib/zip_open.c index fb9c566cb1..d6209ee1e7 100644 --- a/ext/zip/lib/zip_open.c +++ b/ext/zip/lib/zip_open.c @@ -33,7 +33,6 @@ #include <sys/stat.h> -#include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> @@ -184,7 +183,7 @@ _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) zip_t *za; zip_cdir_t *cdir; struct zip_stat st; - zip_uint64_t len; + zip_uint64_t len, idx; zip_stat_init(&st); if (zip_source_stat(src, &st) < 0) { @@ -223,11 +222,31 @@ _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) za->nentry = cdir->nentry; za->nentry_alloc = cdir->nentry_alloc; za->comment_orig = cdir->comment; - - za->ch_flags = za->flags; free(cdir); + for (idx = 0; idx < za->nentry; idx++) { + const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error); + if (name == NULL) { + /* keep src so discard does not get rid of it */ + zip_source_keep(src); + zip_discard(za); + return NULL; + } + + if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) { + if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) { + _zip_error_copy(error, &za->error); + /* keep src so discard does not get rid of it */ + zip_source_keep(src); + zip_discard(za); + return NULL; + } + } + } + + za->ch_flags = za->flags; + return za; } @@ -274,11 +293,6 @@ _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_err return NULL; } - if (_zip_buffer_get_32(buffer) != 0) { - zip_error_set(error, ZIP_ER_MULTIDISK, 0); - return NULL; - } - if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) { _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN); cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error); @@ -649,7 +663,8 @@ _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little } -static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) +static zip_cdir_t * +_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) { zip_cdir_t *cd; zip_uint64_t i, nentry, size, offset, eocd_offset; @@ -661,7 +676,12 @@ static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, eocd_offset = _zip_buffer_offset(buffer); - _zip_buffer_get(buffer, 8); /* magic and number of disks already verified */ + _zip_buffer_get(buffer, 4); /* magic already verified */ + + if (_zip_buffer_get_32(buffer) != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } /* number of cdir-entries on this disk */ i = _zip_buffer_get_16(buffer); @@ -711,10 +731,14 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse zip_uint64_t eocd_offset; zip_uint64_t size, nentry, i, eocdloc_offset; bool free_buffer; + zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64; eocdloc_offset = _zip_buffer_offset(buffer); - _zip_buffer_get(buffer, 8); /* magic and single disk already verified */ + _zip_buffer_get(buffer, 4); /* magic already verified */ + + num_disks = _zip_buffer_get_16(buffer); + eocd_disk = _zip_buffer_get_16(buffer); eocd_offset = _zip_buffer_get_64(buffer); if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) { @@ -760,8 +784,29 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse return NULL; } - _zip_buffer_get(buffer, 12); /* skip version made by/needed and num disks */ - + _zip_buffer_get(buffer, 4); /* skip version made by/needed */ + + num_disks64 = _zip_buffer_get_32(buffer); + eocd_disk64 = _zip_buffer_get_32(buffer); + + /* if eocd values are 0xffff, we have to use eocd64 values. + otherwise, if the values are not the same, it's inconsistent; + in any case, if the value is not 0, we don't support it */ + if (num_disks == 0xffff) { + num_disks = num_disks64; + } + if (eocd_disk == 0xffff) { + eocd_disk = eocd_disk64; + } + if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) { + zip_error_set(error, ZIP_ER_INCONS, 0); + return NULL; + } + if (num_disks != 0 || eocd_disk != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } + nentry = _zip_buffer_get_64(buffer); i = _zip_buffer_get_64(buffer); diff --git a/ext/zip/lib/zip_set_default_password.c b/ext/zip/lib/zip_set_default_password.c index ac098dc5fc..10b48062fd 100644 --- a/ext/zip/lib/zip_set_default_password.c +++ b/ext/zip/lib/zip_set_default_password.c @@ -44,8 +44,7 @@ zip_set_default_password(zip_t *za, const char *passwd) if (za == NULL) return -1; - if (za->default_password) - free(za->default_password); + free(za->default_password); if (passwd) { if ((za->default_password=strdup(passwd)) == NULL) { diff --git a/ext/zip/lib/zip_set_name.c b/ext/zip/lib/zip_set_name.c index 5a10381753..2a461437e2 100644 --- a/ext/zip/lib/zip_set_name.c +++ b/ext/zip/lib/zip_set_name.c @@ -1,6 +1,6 @@ /* zip_set_name.c -- rename helper function - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -43,8 +43,10 @@ _zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { zip_entry_t *e; zip_string_t *str; - int changed; + bool same_as_orig; zip_int64_t i; + const zip_uint8_t *old_name, *new_name; + zip_string_t *old_str; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); @@ -56,7 +58,7 @@ _zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) return -1; } - if (name && strlen(name) > 0) { + if (name && name[0] != '\0') { /* TODO: check for string too long */ if ((str=_zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL) return -1; @@ -81,34 +83,75 @@ _zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) e = za->entry+idx; - if (e->changes) { - _zip_string_free(e->changes->filename); - e->changes->filename = NULL; - e->changes->changed &= ~ZIP_DIRENT_FILENAME; - } - if (e->orig) - changed = !_zip_string_equal(e->orig->filename, str); + same_as_orig = _zip_string_equal(e->orig->filename, str); else - changed = 1; - - if (changed) { - if (e->changes == NULL) { - if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { - zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - _zip_string_free(str); - return -1; - } - } - e->changes->filename = str; - e->changes->changed |= ZIP_DIRENT_FILENAME; + same_as_orig = false; + + if (!same_as_orig && e->changes == NULL) { + if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_string_free(str); + return -1; + } + } + + if ((new_name = _zip_string_get(same_as_orig ? e->orig->filename : str, NULL, 0, &za->error)) == NULL) { + _zip_string_free(str); + return -1; + } + + if (e->changes) { + old_str = e->changes->filename; + } + else if (e->orig) { + old_str = e->orig->filename; } else { + old_str = NULL; + } + + if (old_str) { + if ((old_name = _zip_string_get(old_str, NULL, 0, &za->error)) == NULL) { + _zip_string_free(str); + return -1; + } + } + else { + old_name = NULL; + } + + if (_zip_hash_add(za->names, new_name, idx, 0, &za->error) == false) { + _zip_string_free(str); + return -1; + } + if (old_name) { + _zip_hash_delete(za->names, old_name, NULL); + } + + if (same_as_orig) { + if (e->changes) { + if (e->changes->changed & ZIP_DIRENT_FILENAME) { + _zip_string_free(e->changes->filename); + e->changes->changed &= ~ZIP_DIRENT_FILENAME; + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + else { + /* TODO: what if not cloned? can that happen? */ + e->changes->filename = e->orig->filename; + } + } + } _zip_string_free(str); - if (e->changes && e->changes->changed == 0) { - _zip_dirent_free(e->changes); - e->changes = NULL; + } + else { + if (e->changes->changed & ZIP_DIRENT_FILENAME) { + _zip_string_free(e->changes->filename); } + e->changes->changed |= ZIP_DIRENT_FILENAME; + e->changes->filename = str; } return 0; diff --git a/ext/zip/lib/zip_source_buffer.c b/ext/zip/lib/zip_source_buffer.c index aadf6e40b0..f3f8ee0d58 100644 --- a/ext/zip/lib/zip_source_buffer.c +++ b/ext/zip/lib/zip_source_buffer.c @@ -1,6 +1,6 @@ /* zip_source_buffer.c -- create zip data source from buffer - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -31,7 +31,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdlib.h> #include <string.h> @@ -376,6 +375,7 @@ static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { zip_uint64_t n, i, fragment_offset; + zip_uint8_t **fragments; if (buffer->offset + length + buffer->fragment_size - 1 < length) { zip_error_set(error, ZIP_ER_INVAL, 0); @@ -388,7 +388,6 @@ buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip if (needed_fragments > buffer->fragments_capacity) { zip_uint64_t new_capacity = buffer->fragments_capacity; - zip_uint8_t **fragments; while (new_capacity < needed_fragments) { new_capacity *= 2; diff --git a/ext/zip/lib/zip_source_crc.c b/ext/zip/lib/zip_source_crc.c index eed726616a..01f526c647 100644 --- a/ext/zip/lib/zip_source_crc.c +++ b/ext/zip/lib/zip_source_crc.c @@ -1,6 +1,6 @@ /* zip_source_crc.c -- pass-through source that calculates CRC32 and size - Copyright (C) 2009-2014 Dieter Baron and Thomas Klausner + Copyright (C) 2009-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -39,10 +39,12 @@ #include "zipint.h" struct crc_context { - int eof; - int validate; + int validate; /* whether to check CRC on EOF and return error on mismatch */ + int crc_complete; /* whether CRC was computed for complete file */ zip_error_t error; zip_uint64_t size; + zip_uint64_t position; /* current reading position */ + zip_uint64_t crc_position; /* how far we've computed the CRC */ zip_uint32_t crc; }; @@ -64,12 +66,13 @@ zip_source_crc(zip_t *za, zip_source_t *src, int validate) return NULL; } - ctx->eof = 0; - ctx->validate = validate; zip_error_init(&ctx->error); + ctx->validate = validate; + ctx->crc_complete = 0; + ctx->crc_position = 0; + ctx->crc = (zip_uint32_t)crc32(0, NULL, 0); ctx->size = 0; - ctx->crc = 0; - + return zip_source_layered(za, src, crc_read, ctx); } @@ -84,51 +87,50 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source switch (cmd) { case ZIP_SOURCE_OPEN: - ctx->eof = 0; - ctx->crc = (zip_uint32_t)crc32(0, NULL, 0); - ctx->size = 0; - + ctx->position = 0; return 0; case ZIP_SOURCE_READ: - if (ctx->eof || len == 0) - return 0; - - if ((n=zip_source_read(src, data, len)) < 0) { + if ((n = zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { - ctx->eof = 1; - if (ctx->validate) { - struct zip_stat st; + if (ctx->crc_position == ctx->position) { + ctx->crc_complete = 1; + ctx->size = ctx->position; + + if (ctx->validate) { + struct zip_stat st; - if (zip_source_stat(src, &st) < 0) { - _zip_error_set_from_source(&ctx->error, src); - return -1; - } + if (zip_source_stat(src, &st) < 0) { + _zip_error_set_from_source(&ctx->error, src); + return -1; + } - if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { - zip_error_set(&ctx->error, ZIP_ER_CRC, 0); - return -1; - } - if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { - zip_error_set(&ctx->error, ZIP_ER_INCONS, 0); - return -1; + if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { + zip_error_set(&ctx->error, ZIP_ER_CRC, 0); + return -1; + } + if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { + zip_error_set(&ctx->error, ZIP_ER_INCONS, 0); + return -1; + } } } } - else { + else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { zip_uint64_t i, nn; - for (i=0; i < (zip_uint64_t)n; i += nn) { + for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) { nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i); ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn); + ctx->crc_position += nn; } - ctx->size += (zip_uint64_t)n; } + ctx->position += (zip_uint64_t)n; return n; case ZIP_SOURCE_CLOSE: @@ -140,7 +142,7 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source st = (zip_stat_t *)data; - if (ctx->eof) { + if (ctx->crc_complete) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; @@ -161,7 +163,37 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source return 0; case ZIP_SOURCE_SUPPORTS: - return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1); + { + zip_int64_t mask = zip_source_supports(src); + + if (mask < 0) { + _zip_error_set_from_source(&ctx->error, src); + return -1; + } + + return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1); + } + + case ZIP_SOURCE_SEEK: + { + zip_int64_t new_position; + zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + + if (args == NULL) { + return -1; + } + if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) { + _zip_error_set_from_source(&ctx->error, src); + return -1; + } + + ctx->position = (zip_uint64_t)new_position; + + return 0; + } + + case ZIP_SOURCE_TELL: + return (zip_int64_t)ctx->position; default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); diff --git a/ext/zip/lib/zip_source_file.c b/ext/zip/lib/zip_source_file.c index 1465e1700e..b3cd7ab29f 100644 --- a/ext/zip/lib/zip_source_file.c +++ b/ext/zip/lib/zip_source_file.c @@ -32,7 +32,6 @@ */ -#include <errno.h> #include <stdio.h> #include "zipint.h" diff --git a/ext/zip/lib/zip_source_filep.c b/ext/zip/lib/zip_source_filep.c index e541305d7f..70255dec41 100644 --- a/ext/zip/lib/zip_source_filep.c +++ b/ext/zip/lib/zip_source_filep.c @@ -31,15 +31,17 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include "zipint.h" - #include <sys/stat.h> -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "zipint.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + #ifdef _WIN32 /* WIN32 needs <fcntl.h> for _O_BINARY */ #include <fcntl.h> @@ -49,11 +51,12 @@ #ifndef S_ISREG #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif -#ifndef S_IRWXG -#define S_IRWXG (S_IRWXU >> 3) -#endif -#ifndef S_IRWXO -#define S_IRWXO (S_IRWXG >> 3) +#if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO) +#define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO) +#elif defined(_S_IWRITE) +#define _SAFE_MASK (_S_IWRITE) +#else +#error do not know safe values for umask, please report this #endif #ifdef _MSC_VER @@ -183,13 +186,7 @@ create_temp_output(struct read_file *ctx) } sprintf(temp, "%s.XXXXXX", ctx->fname); -#ifdef _WIN32 - /* This might work under VS2015, however there's no good documentation - about it. So let it be for now. */ - mask = 0; -#else - mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); -#endif + mask = umask(_SAFE_MASK); if ((tfd=mkstemp(temp)) == -1) { zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); umask(mask); diff --git a/ext/zip/lib/zip_source_pkware.c b/ext/zip/lib/zip_source_pkware.c index ce281ac148..125e4e2c2a 100644 --- a/ext/zip/lib/zip_source_pkware.c +++ b/ext/zip/lib/zip_source_pkware.c @@ -1,6 +1,6 @@ /* zip_source_pkware.c -- Traditional PKWARE de/encryption routines - Copyright (C) 2009-2014 Dieter Baron and Thomas Klausner + Copyright (C) 2009-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -107,7 +107,7 @@ decrypt(struct trad_pkware *ctx, zip_uint8_t *out, const zip_uint8_t *in, if (!update_only) { /* decrypt next byte */ tmp = (zip_uint16_t)(ctx->key[2] | 2); - tmp = (zip_uint16_t)((tmp * (tmp ^ 1)) >> 8); + tmp = (zip_uint16_t)(((zip_uint32_t)tmp * (tmp ^ 1)) >> 8); b ^= (Bytef)tmp; } diff --git a/ext/zip/lib/zip_source_stat.c b/ext/zip/lib/zip_source_stat.c index 34cb05f452..a6b46d06a6 100644 --- a/ext/zip/lib/zip_source_stat.c +++ b/ext/zip/lib/zip_source_stat.c @@ -1,6 +1,6 @@ /* zip_source_stat.c -- get meta information from zip_source - Copyright (C) 2009-2014 Dieter Baron and Thomas Klausner + Copyright (C) 2009-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -35,7 +35,7 @@ #include "zipint.h" -int +ZIP_EXTERN int zip_source_stat(zip_source_t *src, zip_stat_t *st) { if (src->source_closed) { diff --git a/ext/zip/lib/zip_source_supports.c b/ext/zip/lib/zip_source_supports.c index 3c100fb71f..75a4a4626d 100644 --- a/ext/zip/lib/zip_source_supports.c +++ b/ext/zip/lib/zip_source_supports.c @@ -1,6 +1,6 @@ /* zip_source_supports.c -- check for supported functions - Copyright (C) 2014 Dieter Baron and Thomas Klausner + Copyright (C) 2014-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -44,7 +44,7 @@ zip_source_supports(zip_source_t *src) } -zip_int64_t +ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t cmd0, ...) { zip_int64_t bitmap; diff --git a/ext/zip/lib/zip_source_win32a.c b/ext/zip/lib/zip_source_win32a.c index e9786c473e..85493b660e 100644 --- a/ext/zip/lib/zip_source_win32a.c +++ b/ext/zip/lib/zip_source_win32a.c @@ -1,6 +1,6 @@ /* zip_source_win32a.c -- create data source from Windows file (ANSI) -Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner +Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdio.h> #include "zipint.h" diff --git a/ext/zip/lib/zip_source_win32handle.c b/ext/zip/lib/zip_source_win32handle.c index d195a119db..35e2e67972 100644 --- a/ext/zip/lib/zip_source_win32handle.c +++ b/ext/zip/lib/zip_source_win32handle.c @@ -1,6 +1,6 @@ /* zip_source_win32file.c -- create data source from HANDLE (Win32) -Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner +Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -33,7 +33,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <wchar.h> -#include <errno.h> #include <stdlib.h> #include <string.h> @@ -409,6 +408,7 @@ _win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd static int _win32_create_temp_file(_zip_source_win32_read_file_t *ctx) { + zip_uint32_t value; /* Windows has GetTempFileName(), but it closes the file after creation, leaving it open to a horrible race condition. So @@ -423,7 +423,6 @@ _win32_create_temp_file(_zip_source_win32_read_file_t *ctx) PSECURITY_ATTRIBUTES psa = NULL; DWORD len; BOOL success; - zip_uint32_t value; /* Read the DACL from the original file, so we can copy it to the temp file. diff --git a/ext/zip/lib/zip_source_win32utf8.c b/ext/zip/lib/zip_source_win32utf8.c index e11214ba05..004c66ac2b 100644 --- a/ext/zip/lib/zip_source_win32utf8.c +++ b/ext/zip/lib/zip_source_win32utf8.c @@ -32,7 +32,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdio.h> #include "zipint.h" diff --git a/ext/zip/lib/zip_source_win32w.c b/ext/zip/lib/zip_source_win32w.c index 34134561f1..551aba5f37 100644 --- a/ext/zip/lib/zip_source_win32w.c +++ b/ext/zip/lib/zip_source_win32w.c @@ -1,6 +1,6 @@ /* zip_source_win32w.c -- create data source from Windows file (UTF-16) -Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner +Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -32,7 +32,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <stdio.h> #include "zipint.h" @@ -100,7 +99,7 @@ _win32_create_temp_w(_zip_source_win32_read_file_t *ctx, void **temp, zip_uint32 return INVALID_HANDLE_VALUE; } } - if (swprintf((wchar_t *)*temp, len, L"%s.%08x", (const wchar_t *)ctx->fname, value) != len - 1) { + if (_snwprintf((wchar_t *)*temp, len, L"%s.%08x", (const wchar_t *)ctx->fname, value) != len - 1) { return INVALID_HANDLE_VALUE; } diff --git a/ext/zip/lib/zip_unchange.c b/ext/zip/lib/zip_unchange.c index 6c8a495c78..5ef5462127 100644 --- a/ext/zip/lib/zip_unchange.c +++ b/ext/zip/lib/zip_unchange.c @@ -1,6 +1,6 @@ /* zip_unchange.c -- undo changes to file in zip archive - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -48,6 +48,7 @@ int _zip_unchange(zip_t *za, zip_uint64_t idx, int allow_duplicates) { zip_int64_t i; + const char *orig_name, *changed_name; if (idx >= za->nentry) { zip_error_set(&za->error, ZIP_ER_INVAL, 0); @@ -55,9 +56,32 @@ _zip_unchange(zip_t *za, zip_uint64_t idx, int allow_duplicates) } if (!allow_duplicates && za->entry[idx].changes && (za->entry[idx].changes->changed & ZIP_DIRENT_FILENAME)) { - i = _zip_name_locate(za, _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), 0, NULL); - if (i >= 0 && (zip_uint64_t)i != idx) { - zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + if (za->entry[idx].orig != NULL) { + if ((orig_name=_zip_get_name(za, idx, ZIP_FL_UNCHANGED, &za->error)) == NULL) { + return -1; + } + + i = _zip_name_locate(za, orig_name, 0, NULL); + if (i >= 0 && (zip_uint64_t)i != idx) { + zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + } + else { + orig_name = NULL; + } + + if ((changed_name=_zip_get_name(za, idx, 0, &za->error)) == NULL) { + return -1; + } + + if (orig_name) { + if (_zip_hash_add(za->names, (const zip_uint8_t *)orig_name, idx, 0, &za->error) == false) { + return -1; + } + } + if (_zip_hash_delete(za->names, (const zip_uint8_t *)changed_name, &za->error) == false) { + _zip_hash_delete(za->names, (const zip_uint8_t *)orig_name, NULL); return -1; } } diff --git a/ext/zip/lib/zip_unchange_all.c b/ext/zip/lib/zip_unchange_all.c index 60076838d4..dc89f7fdaf 100644 --- a/ext/zip/lib/zip_unchange_all.c +++ b/ext/zip/lib/zip_unchange_all.c @@ -1,6 +1,6 @@ /* zip_unchange.c -- undo changes to all files in zip archive - Copyright (C) 1999-2014 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -43,6 +43,8 @@ zip_unchange_all(zip_t *za) int ret; zip_uint64_t i; + _zip_hash_revert(za->names); + ret = 0; for (i=0; i<za->nentry; i++) ret |= _zip_unchange(za, i, 1); diff --git a/ext/zip/lib/zipconf.h b/ext/zip/lib/zipconf.h index c8716fb952..8ac2652e1d 100644 --- a/ext/zip/lib/zipconf.h +++ b/ext/zip/lib/zipconf.h @@ -7,10 +7,10 @@ This file was generated automatically by CMake based on ../cmake-zipconf.h.in. */ -#define LIBZIP_VERSION "1.0.1" +#define LIBZIP_VERSION "1.1.2" #define LIBZIP_VERSION_MAJOR 1 -#define LIBZIP_VERSION_MINOR 0 -#define LIBZIP_VERSION_MICRO 1 +#define LIBZIP_VERSION_MINOR 1 +#define LIBZIP_VERSION_MICRO 2 /* #undef HAVE_INTTYPES_H_LIBZIP */ diff --git a/ext/zip/lib/zipint.h b/ext/zip/lib/zipint.h index d13bab42ab..68b18c70a3 100644 --- a/ext/zip/lib/zipint.h +++ b/ext/zip/lib/zipint.h @@ -3,7 +3,7 @@ /* zipint.h -- internal declarations. - Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at <libzip@nih.at> @@ -65,6 +65,22 @@ typedef char bool; #define false 0 #endif +#include <errno.h> + +/* at least MinGW does not provide EOPNOTSUPP, see + * http://sourceforge.net/p/mingw/bugs/263/ + */ +#ifndef EOPNOTSUPP +#define EOPNOTSUPP EINVAL +#endif + +/* at least MinGW does not provide EOVERFLOW, see + * http://sourceforge.net/p/mingw/bugs/242/ + */ +#ifndef EOVERFLOW +#define EOVERFLOW EFBIG +#endif + #ifdef _WIN32 #if defined(HAVE__CLOSE) #define close _close @@ -76,7 +92,7 @@ typedef char bool; #if defined(HAVE__FDOPEN) #define fdopen _fdopen #endif -#if defined(HAVE__FILENO) +#if !defined(HAVE_FILENO) && defined(HAVE__FILENO) #define fileno _fileno #endif /* Windows' open() doesn't understand Unix permissions */ @@ -92,6 +108,9 @@ typedef char bool; #define strdup _strdup #endif #endif +#if !defined(HAVE__SETMODE) && defined(HAVE_SETMODE) +#define _setmode setmode +#endif #endif #ifndef HAVE_FSEEKO @@ -110,6 +129,8 @@ int _zip_mkstemp(char *); #if !defined(HAVE_STRCASECMP) #if defined(HAVE__STRICMP) #define strcasecmp _stricmp +#elif defined(HAVE_STRICMP) +#define strcasecmp stricmp #endif #endif @@ -129,12 +150,10 @@ int _zip_mkstemp(char *); #if defined(HAVE_FTELLO) && defined(HAVE_FSEEKO) #define ZIP_FSEEK_MAX ZIP_OFF_MAX #define ZIP_FSEEK_MIN ZIP_OFF_MIN -#elif SIZEOF_LONG >= 8 -#define ZIP_FSEEK_MAX (long)ZIP_INT64_MAX -#define ZIP_FSEEK_MIN (long)ZIP_INT64_MIN #else -#define ZIP_FSEEK_MAX (long)ZIP_INT32_MAX -#define ZIP_FSEEK_MIN (long)ZIP_INT32_MIN +#include <limits.h> +#define ZIP_FSEEK_MAX LONG_MAX +#define ZIP_FSEEK_MIN LONG_MIN #endif #ifndef SIZE_MAX @@ -255,13 +274,19 @@ enum zip_encoding_type { typedef enum zip_encoding_type zip_encoding_type_t; +#ifndef ZIP_HASH_TABLE_SIZE +#define ZIP_HASH_TABLE_SIZE 8192 +#endif + +struct zip_hash; + typedef struct zip_cdir zip_cdir_t; typedef struct zip_dirent zip_dirent_t; typedef struct zip_entry zip_entry_t; typedef struct zip_extra_field zip_extra_field_t; typedef struct zip_string zip_string_t; typedef struct zip_buffer zip_buffer_t; - +typedef struct zip_hash zip_hash_t; /* zip archive, part of API */ @@ -276,7 +301,7 @@ struct zip { char *default_password; /* password used when no other supplied */ zip_string_t *comment_orig; /* archive comment */ - zip_string_t *comment_changes; /* changed archive comment */ + zip_string_t *comment_changes; /* changed archive comment */ bool comment_changed; /* whether archive comment was changed */ zip_uint64_t nentry; /* number of entries */ @@ -286,6 +311,8 @@ struct zip { unsigned int nopen_source; /* number of open sources using archive */ unsigned int nopen_source_alloc; /* number of sources allocated */ zip_source_t **open_source; /* open sources using archive */ + + zip_hash_t *names; /* hash table for name lookup */ char *tempdir; /* custom temp dir (needed e.g. for OS X sandboxing) */ }; @@ -312,7 +339,7 @@ struct zip_file { struct zip_dirent { zip_uint32_t changed; bool local_extra_fields_read; /* whether we already read in local header extra fields */ - bool cloned; /* whether this instance is cloned, and thus shares non-changed strings */ + bool cloned; /* whether this instance is cloned, and thus shares non-changed strings */ zip_uint16_t version_madeby; /* (c) version of creator */ zip_uint16_t version_needed; /* (cl) version needed to extract */ @@ -415,7 +442,7 @@ struct zip_buffer { struct zip_filelist { zip_uint64_t idx; -// TODO const char *name; +/* TODO const char *name; */ }; typedef struct zip_filelist zip_filelist_t; @@ -453,6 +480,7 @@ int _zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i); int _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i); int _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i); int _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i); +int _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length); int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset); zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer); @@ -478,7 +506,7 @@ void _zip_ef_free(zip_extra_field_t *); const zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *, zip_uint16_t *, zip_uint16_t, zip_uint16_t, zip_flags_t, zip_error_t *); zip_extra_field_t *_zip_ef_merge(zip_extra_field_t *, zip_extra_field_t *); zip_extra_field_t *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_flags_t); -zip_extra_field_t *_zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, zip_error_t *); +bool _zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, zip_extra_field_t **, zip_error_t *); zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *); zip_uint16_t _zip_ef_size(const zip_extra_field_t *, zip_flags_t); int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags); @@ -505,6 +533,13 @@ zip_dirent_t *_zip_get_dirent(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *) enum zip_encoding_type _zip_guess_encoding(zip_string_t *, enum zip_encoding_type); zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t * const, zip_uint32_t, zip_uint32_t *, zip_error_t *); +bool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error); +bool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *key, zip_error_t *error); +void _zip_hash_free(zip_hash_t *hash); +zip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error); +zip_hash_t *_zip_hash_new(zip_uint16_t hash_size, zip_error_t *error); +void _zip_hash_revert(zip_hash_t *hash); + zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *); int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error); diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index c31ace1f8d..db201af634 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -16,7 +16,6 @@ +----------------------------------------------------------------------+ */ -/* $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -331,7 +330,7 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path, char } if (Z_STRLEN_P(option) >= MAXPATHLEN) { - php_error_docref(NULL, E_WARNING, "remove_path string is too long (max: %i, %i given)", + php_error_docref(NULL, E_WARNING, "remove_path string is too long (max: %d, %zd given)", MAXPATHLEN - 1, Z_STRLEN_P(option)); return -1; } @@ -351,7 +350,7 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path, char } if (Z_STRLEN_P(option) >= MAXPATHLEN) { - php_error_docref(NULL, E_WARNING, "add_path string too long (max: %i, %i given)", + php_error_docref(NULL, E_WARNING, "add_path string too long (max: %d, %zd given)", MAXPATHLEN - 1, Z_STRLEN_P(option)); return -1; } @@ -1506,7 +1505,7 @@ static ZIPARCHIVE_METHOD(close) ze_obj = Z_ZIP_P(self); if ((err = zip_close(intern))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zip_strerror(intern)); + php_error_docref(NULL, E_WARNING, "%s", zip_strerror(intern)); zip_discard(intern); } @@ -2668,7 +2667,7 @@ static ZIPARCHIVE_METHOD(extractTo) for (i = 0; i < filecount; i++) { char *file = (char*)zip_get_name(intern, i, ZIP_FL_UNCHANGED); - if (!php_zip_extract_file(intern, pathto, file, strlen(file))) { + if (!file || !php_zip_extract_file(intern, pathto, file, strlen(file))) { RETURN_FALSE; } } @@ -3134,7 +3133,6 @@ static PHP_MINFO_FUNCTION(zip) php_info_print_table_start(); php_info_print_table_row(2, "Zip", "enabled"); - php_info_print_table_row(2, "Extension Version","$Id$"); php_info_print_table_row(2, "Zip version", PHP_ZIP_VERSION); php_info_print_table_row(2, "Libzip version", LIBZIP_VERSION); diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 602b1b1c44..f5df19e79a 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -16,7 +16,6 @@ +----------------------------------------------------------------------+ */ -/* $Id$ */ #ifndef PHP_ZIP_H #define PHP_ZIP_H @@ -38,7 +37,7 @@ extern zend_module_entry zip_module_entry; #define ZIP_OVERWRITE ZIP_TRUNCATE #endif -#define PHP_ZIP_VERSION "1.13.0" +#define PHP_ZIP_VERSION "1.13.2" #ifndef Z_SET_REFCOUNT_P # if PHP_MAJOR_VERSION < 6 && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3) diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c index 3b200e89d1..a1f620182c 100644 --- a/ext/zip/zip_stream.c +++ b/ext/zip/zip_stream.c @@ -16,7 +16,6 @@ +----------------------------------------------------------------------+ */ -/* $Id$ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index eda939d66e..bfca0f42f7 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1064,7 +1064,7 @@ PHP_FUNCTION(deflate_init) case Z_DEFAULT_STRATEGY: break; default: - php_error_docref(NULL, E_WARNING, "strategy must be one of ZLIB_FILTERED, ZLIB_HUFFMAN_ONLY, ZLIB_RLE, ZLIB_FIXED or ZLIB_DEFAULT_STRATEGY", strategy); + php_error_docref(NULL, E_WARNING, "strategy must be one of ZLIB_FILTERED, ZLIB_HUFFMAN_ONLY, ZLIB_RLE, ZLIB_FIXED or ZLIB_DEFAULT_STRATEGY"); RETURN_FALSE; } diff --git a/main/main.c b/main/main.c index 77a2f64b40..ab879369bc 100644 --- a/main/main.c +++ b/main/main.c @@ -1566,6 +1566,9 @@ int php_request_startup(void) #endif /* HAVE_DTRACE */ #ifdef PHP_WIN32 +# if defined(ZTS) + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); +# endif PG(com_initialized) = 0; #endif diff --git a/main/output.c b/main/output.c index 2154949810..2a51100960 100644 --- a/main/output.c +++ b/main/output.c @@ -665,7 +665,7 @@ PHPAPI int php_output_handler_alias_register(const char *name, size_t name_len, } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC) +/* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg) * Output handler hook for output handler functions to check/modify the current handlers abilities */ PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg) { @@ -715,7 +715,7 @@ PHPAPI void php_output_handler_dtor(php_output_handler *handler) } /* }}} */ -/* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC) +/* {{{ void php_output_handler_free(php_output_handler **handler) * Destroy and free an output handler */ PHPAPI void php_output_handler_free(php_output_handler **h) { diff --git a/main/php.h b/main/php.h index 14a52a6476..bb06a3edac 100644 --- a/main/php.h +++ b/main/php.h @@ -297,19 +297,13 @@ static inline ZEND_ATTRIBUTE_DEPRECATED void php_std_error_handling() {} PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int type, const char *format, va_list args) PHP_ATTRIBUTE_FORMAT(printf, 4, 0); -#ifdef ZTS -#define PHP_ATTR_FMT_OFFSET 1 -#else -#define PHP_ATTR_FMT_OFFSET 0 -#endif - /* PHPAPI void php_error(int type, const char *format, ...); */ PHPAPI ZEND_COLD void php_error_docref0(const char *docref, int type, const char *format, ...) - PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 3, PHP_ATTR_FMT_OFFSET + 4); + PHP_ATTRIBUTE_FORMAT(printf, 3, 4); PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, int type, const char *format, ...) - PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 4, PHP_ATTR_FMT_OFFSET + 5); + PHP_ATTRIBUTE_FORMAT(printf, 4, 5); PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format, ...) - PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 5, PHP_ATTR_FMT_OFFSET + 6); + PHP_ATTRIBUTE_FORMAT(printf, 5, 6); #ifdef PHP_WIN32 PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2); #endif diff --git a/main/php_streams.h b/main/php_streams.h index 0cb9849d3b..de7c280050 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -313,11 +313,7 @@ PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t coun PHPAPI void _php_stream_fill_read_buffer(php_stream *stream, size_t size); #define php_stream_fill_read_buffer(stream, size) _php_stream_fill_read_buffer((stream), (size)) -#ifdef ZTS -PHPAPI size_t _php_stream_printf(php_stream *stream, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -#else PHPAPI size_t _php_stream_printf(php_stream *stream, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); -#endif /* php_stream_printf macro & function require */ #define php_stream_printf _php_stream_printf @@ -579,11 +575,7 @@ PHPAPI const char *php_stream_locate_eol(php_stream *stream, zend_string *buf); php_stream_open_wrapper_ex(Z_STRVAL_PP((zstream)), (mode), (options), (opened), (context)) : NULL /* pushes an error message onto the stack for a wrapper instance */ -#ifdef ZTS -PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5); -#else PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -#endif #define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */ #define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */ diff --git a/main/php_version.h b/main/php_version.h index 4096d9d50c..0bf06b34b4 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.in to change version number */ #define PHP_MAJOR_VERSION 7 #define PHP_MINOR_VERSION 0 -#define PHP_RELEASE_VERSION 4 +#define PHP_RELEASE_VERSION 5 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "7.0.4-dev" -#define PHP_VERSION_ID 70004 +#define PHP_VERSION "7.0.5-dev" +#define PHP_VERSION_ID 70005 diff --git a/main/streams/memory.c b/main/streams/memory.c index 09da047d86..56ffe344aa 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -22,7 +22,7 @@ #include "php.h" #include "ext/standard/base64.h" -PHPAPI int php_url_decode(char *str, int len); +PHPAPI size_t php_url_decode(char *str, size_t len); /* Memory streams use a dynamic memory buffer to emulate a stream. * You can use php_stream_memory_open to create a readonly stream @@ -730,7 +730,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con ilen = (int)ZSTR_LEN(base64_comma); } else { comma = estrndup(comma, dlen); - dlen = php_url_decode(comma, (int)dlen); + dlen = php_url_decode(comma, dlen); ilen = (int)dlen; } diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index a387059e27..907f629c01 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -517,7 +517,7 @@ static void php_cli_usage(char *argv0) " -a Run interactively\n" #endif " -c <path>|<file> Look for php.ini file in this directory\n" - " -n No php.ini file will be used\n" + " -n No configuration (ini) files will be used\n" " -d foo[=bar] Define INI entry foo with value 'bar'\n" " -e Generate extended information for debugger/profiler\n" " -f <file> Parse and execute <file>.\n" diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 4ee85bf538..ac41c44def 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1955,6 +1955,19 @@ static int php_cli_server_begin_send_static(php_cli_server *server, php_cli_serv return php_cli_server_send_error_page(server, client, 400); } +#ifdef PHP_WIN32 + /* The win32 namespace will cut off trailing dots and spaces. Since the + VCWD functionality isn't used here, a sophisticated functionality + would have to be reimplemented to know ahead there are no files + with invalid names there. The simplest is just to forbid invalid + filenames, which is done here. */ + if (client->request.path_translated && + ('.' == client->request.path_translated[client->request.path_translated_len-1] || + ' ' == client->request.path_translated[client->request.path_translated_len-1])) { + return php_cli_server_send_error_page(server, client, 500); + } +#endif + fd = client->request.path_translated ? open(client->request.path_translated, O_RDONLY): -1; if (fd < 0) { return php_cli_server_send_error_page(server, client, 404); diff --git a/sapi/fpm/Makefile.frag b/sapi/fpm/Makefile.frag index e39fbcb1e8..b0b4b34658 100644 --- a/sapi/fpm/Makefile.frag +++ b/sapi/fpm/Makefile.frag @@ -19,6 +19,6 @@ install-fpm: $(SAPI_FPM_PATH) @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man8 @$(INSTALL_DATA) sapi/fpm/php-fpm.8 $(INSTALL_ROOT)$(mandir)/man8/php-fpm$(program_suffix).8 - @echo "Installing PHP FPM status page: $(INSTALL_ROOT)$(datadir)/fpm/" + @echo "Installing PHP FPM status page: $(INSTALL_ROOT)$(datadir)/fpm/" @$(mkinstalldirs) $(INSTALL_ROOT)$(datadir)/fpm @$(INSTALL_DATA) sapi/fpm/status.html $(INSTALL_ROOT)$(datadir)/fpm/status.html diff --git a/sapi/fpm/fpm/fpm_signals.c b/sapi/fpm/fpm/fpm_signals.c index c5d0692f18..a637e69e71 100644 --- a/sapi/fpm/fpm/fpm_signals.c +++ b/sapi/fpm/fpm/fpm_signals.c @@ -241,6 +241,10 @@ int fpm_signals_init_child() /* {{{ */ zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()"); return -1; } + +#ifdef ZEND_SIGNALS + zend_signal_init(); +#endif return 0; } /* }}} */ diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag index 767c2e5eb1..125a3b13da 100644 --- a/sapi/litespeed/Makefile.frag +++ b/sapi/litespeed/Makefile.frag @@ -4,6 +4,6 @@ $(SAPI_LITESPEED_PATH): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_LITESPEED_OB $(BUILD_LITESPEED) install-litespeed: $(SAPI_LITESPEED_PATH) - @echo "Installing PHP LiteSpeed binary: $(INSTALL_ROOT)$(bindir)/" + @echo "Installing PHP LiteSpeed binary: $(INSTALL_ROOT)$(bindir)/" @$(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/lsphp diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 8acf061983..9321eed2d3 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -554,11 +554,11 @@ static PHP_FUNCTION(phpdbg_get_executable) if (ce->type == ZEND_USER_CLASS) { if (zend_hash_exists(files, ce->info.user.filename)) { ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { - if (func->type == ZEND_USER_FUNCTION) { + if (func->type == ZEND_USER_FUNCTION && zend_hash_exists(files, func->op_array.filename)) { insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename); if (by_function) { - zend_string *fn_name = strpprintf(ZSTR_LEN(name) + ZSTR_LEN(func->op_array.function_name) + 2, "%.*s::%.*s", ZSTR_LEN(name), ZSTR_VAL(name), ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); + zend_string *fn_name = strpprintf(ZSTR_LEN(name) + ZSTR_LEN(func->op_array.function_name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(name), ZSTR_VAL(name), (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); insert_ht = phpdbg_add_empty_array(insert_ht, fn_name); zend_string_release(fn_name); } @@ -654,7 +654,7 @@ static PHP_FUNCTION(phpdbg_end_oplog) if (last_scope == NULL) { fn_name = zend_string_copy(last_function); } else { - fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name), ZSTR_LEN(last_function), ZSTR_VAL(last_function)); + fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name), (int) ZSTR_LEN(last_function), ZSTR_VAL(last_function)); } insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), fn_name); zend_string_release(fn_name); @@ -896,7 +896,7 @@ static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { send(PHPDBG_G(socket_fd), message, length, 0); } - return phpdbg_script(P_STDOUT, "%.*s", length, message); + return phpdbg_script(P_STDOUT, "%.*s", (int) length, message); } /* }}} */ /* beginning of struct, see main/streams/plain_wrapper.c line 111 */ diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index eac67d4ac7..5436bda5db 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -563,12 +563,14 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break) /* { } else { zend_execute_data *execute_data = EG(current_execute_data); do { - zend_op_array *op_array = &execute_data->func->op_array; - if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) { - if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) { - return SUCCESS; - } else { - return 2; + if (ZEND_USER_CODE(execute_data->func->common.type)) { + zend_op_array *op_array = &execute_data->func->op_array; + if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) { + if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) { + return SUCCESS; + } else { + return 2; + } } } } while ((execute_data = execute_data->prev_execute_data) != NULL); diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c index 2d0c693a1e..ab1b554f76 100644 --- a/sapi/phpdbg/phpdbg_frame.c +++ b/sapi/phpdbg/phpdbg_frame.c @@ -218,7 +218,7 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */ while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) { if (file) { /* userland */ phpdbg_out("frame #%d: ", i); - phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"%d\"", i, Z_STRVAL_P(file), Z_LVAL_P(line)); + phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", i, Z_STRVAL_P(file), Z_LVAL_P(line)); phpdbg_dump_prototype(tmp); phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line)); i++; diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index 76b26ef1e0..5d7608fa76 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -120,12 +120,18 @@ PHPDBG_INFO(constants) /* {{{ */ phpdbg_out("Address Refs Type Constant\n"); ZEND_HASH_FOREACH_PTR(&consts, data) { -#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("constant", "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %.*s" msg, &data->value, Z_REFCOUNTED(data->value) ? Z_REFCOUNT(data->value) : 1, zend_zval_type_name(&data->value), ZSTR_LEN(data->name), ZSTR_VAL(data->name), ##__VA_ARGS__) +#define VARIABLEINFO(attrs, msg, ...) \ + phpdbg_writeln("constant", \ + "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, \ + "%-18p %-7d %-9s %.*s" msg, &data->value, \ + Z_REFCOUNTED(data->value) ? Z_REFCOUNT(data->value) : 1, \ + zend_zval_type_name(&data->value), \ + (int) ZSTR_LEN(data->name), ZSTR_VAL(data->name), ##__VA_ARGS__) switch (Z_TYPE(data->value)) { case IS_STRING: phpdbg_try_access { - VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : ""); + VARIABLEINFO("length=\"%zd\" value=\"%.*s\"", "\nstring (%zd) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? (int) Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : ""); } phpdbg_catch_access { VARIABLEINFO("", ""); } phpdbg_end_try_access(); @@ -158,7 +164,7 @@ static int phpdbg_arm_auto_global(zval *ptrzv) { if (auto_global->armed) { if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { - phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", ZSTR_LEN(auto_global->name), ZSTR_VAL(auto_global->name)); + phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", (int) ZSTR_LEN(auto_global->name), ZSTR_VAL(auto_global->name)); } else { auto_global->armed = auto_global->auto_global_callback(auto_global->name); } @@ -224,7 +230,10 @@ static int phpdbg_print_symbols(zend_bool show_globals) { ZEND_HASH_FOREACH_STR_KEY_VAL(&vars, var, data) { phpdbg_try_access { const char *isref = ""; -#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNTED_P(data) ? Z_REFCOUNT_P(data) : 1, zend_zval_type_name(data), isref, ZSTR_LEN(var), ZSTR_VAL(var), ##__VA_ARGS__) +#define VARIABLEINFO(attrs, msg, ...) \ + phpdbg_writeln("variable", \ + "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, \ + "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNTED_P(data) ? Z_REFCOUNT_P(data) : 1, zend_zval_type_name(data), isref, (int) ZSTR_LEN(var), ZSTR_VAL(var), ##__VA_ARGS__) retry_switch: switch (Z_TYPE_P(data)) { case IS_RESOURCE: @@ -237,14 +246,14 @@ retry_switch: break; case IS_OBJECT: phpdbg_try_access { - VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", Z_OBJCE_P(data)->name); + VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", ZSTR_VAL(Z_OBJCE_P(data)->name)); } phpdbg_catch_access { VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (unknown)\n"); } phpdbg_end_try_access(); break; case IS_STRING: phpdbg_try_access { - VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : ""); + VARIABLEINFO("length=\"%zd\" value=\"%.*s\"", "\nstring (%zd) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? (int) Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : ""); } phpdbg_catch_access { VARIABLEINFO("", ""); } phpdbg_end_try_access(); @@ -369,7 +378,7 @@ static inline void phpdbg_print_class_name(zend_class_entry *ce) /* {{{ */ const char *visibility = ce->type == ZEND_USER_CLASS ? "User" : "Internal"; const char *type = (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : (ce->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class"; - phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, ZSTR_LEN(ce->name), ZSTR_VAL(ce->name), zend_hash_num_elements(&ce->function_table)); + phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, (int) ZSTR_LEN(ce->name), ZSTR_VAL(ce->name), zend_hash_num_elements(&ce->function_table)); } /* }}} */ PHPDBG_INFO(classes) /* {{{ */ diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c index fd9c92811d..0ea4324845 100644 --- a/sapi/phpdbg/phpdbg_opcode.c +++ b/sapi/phpdbg/phpdbg_opcode.c @@ -49,10 +49,10 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t } break; case IS_VAR: - spprintf(&decode, 0, "@%td", EX_VAR_TO_NUM(op->var) - ops->last_var); + spprintf(&decode, 0, "@%u", EX_VAR_TO_NUM(op->var) - ops->last_var); break; case IS_TMP_VAR: - spprintf(&decode, 0, "~%td", EX_VAR_TO_NUM(op->var) - ops->last_var); + spprintf(&decode, 0, "~%u", EX_VAR_TO_NUM(op->var) - ops->last_var); break; case IS_CONST: { zval *literal = RT_CONSTANT(ops, *op); diff --git a/sapi/phpdbg/phpdbg_out.h b/sapi/phpdbg/phpdbg_out.h index 0a0d7c2410..a6f28da14d 100644 --- a/sapi/phpdbg/phpdbg_out.h +++ b/sapi/phpdbg/phpdbg_out.h @@ -34,20 +34,11 @@ enum { P_LOG }; -#ifdef ZTS -PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 6, 7); -PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -#else PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6); PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); -#endif - #define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR , PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) #define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE , PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c index 6b6c706f92..00209cb239 100644 --- a/sapi/phpdbg/phpdbg_print.c +++ b/sapi/phpdbg/phpdbg_print.c @@ -42,7 +42,7 @@ const phpdbg_command_t phpdbg_print_commands[] = { PHPDBG_PRINT(opline) /* {{{ */ { if (PHPDBG_G(in_execution) && EG(current_execute_data)) { - phpdbg_print_opline(EG(current_execute_data), 1); + phpdbg_print_opline(phpdbg_user_execute_data(EG(current_execute_data)), 1); } else { phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); } @@ -124,7 +124,7 @@ return SUCCESS; PHPDBG_PRINT(stack) /* {{{ */ { if (PHPDBG_G(in_execution) && EG(current_execute_data)) { - zend_op_array *ops = &EG(current_execute_data)->func->op_array; + zend_op_array *ops = &phpdbg_user_execute_data(EG(current_execute_data))->func->op_array; if (ops->function_name) { if (ops->scope) { phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ZSTR_VAL(ops->scope->name), ZSTR_VAL(ops->function_name), ops->last); @@ -278,7 +278,7 @@ void phpdbg_print_opcodes_function(const char *function, size_t len) { return; } - phpdbg_out("function name: %.*s\n", ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); + phpdbg_out("function name: %.*s\n", (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); phpdbg_print_function_helper(func); } @@ -351,7 +351,7 @@ static void phpdbg_print_opcodes_ce(zend_class_entry *ce) { phpdbg_out("\n"); ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, method_name, method) { - phpdbg_out("\nfunction name: %s\n", method_name); + phpdbg_out("\nfunction name: %s\n", ZSTR_VAL(method_name)); phpdbg_print_function_helper(method); } ZEND_HASH_FOREACH_END(); } diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 97249765f8..558ca469b5 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -518,13 +518,14 @@ PHPDBG_COMMAND(continue) /* {{{ */ } /* }}} */ int phpdbg_skip_line_helper() /* {{{ */ { - const zend_op_array *op_array = &EG(current_execute_data)->func->op_array; + zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data)); + const zend_op_array *op_array = &ex->func->op_array; const zend_op *opline = op_array->opcodes; PHPDBG_G(flags) |= PHPDBG_IN_UNTIL; - PHPDBG_G(seek_ex) = EG(current_execute_data); + PHPDBG_G(seek_ex) = ex; do { - if (opline->lineno != EG(current_execute_data)->opline->lineno + if (opline->lineno != ex->opline->lineno || opline->opcode == ZEND_RETURN || opline->opcode == ZEND_FAST_RET || opline->opcode == ZEND_GENERATOR_RETURN @@ -562,10 +563,11 @@ PHPDBG_COMMAND(next) /* {{{ */ } /* }}} */ static void phpdbg_seek_to_end(void) /* {{{ */ { - const zend_op_array *op_array = &EG(current_execute_data)->func->op_array; + zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data)); + const zend_op_array *op_array = &ex->func->op_array; const zend_op *opline = op_array->opcodes; - PHPDBG_G(seek_ex) = EG(current_execute_data); + PHPDBG_G(seek_ex) = ex; do { switch (opline->opcode) { case ZEND_RETURN: @@ -588,7 +590,7 @@ PHPDBG_COMMAND(finish) /* {{{ */ } phpdbg_seek_to_end(); - if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) EG(current_execute_data)->opline)) { + if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) { zend_hash_clean(&PHPDBG_G(seek)); } else { PHPDBG_G(flags) |= PHPDBG_IN_FINISH; @@ -605,7 +607,7 @@ PHPDBG_COMMAND(leave) /* {{{ */ } phpdbg_seek_to_end(); - if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) EG(current_execute_data)->opline)) { + if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) { zend_hash_clean(&PHPDBG_G(seek)); phpdbg_notice("leave", "type=\"end\"", "Already at the end of the function"); return SUCCESS; @@ -1518,7 +1520,11 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */ line = zval_get_long(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("line"), 1, &rv)); msg = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("message"), 1, &rv)); - phpdbg_error("exception", "name=\"%s\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", "Uncaught %s in %s on line " ZEND_LONG_FMT ": %.*s", ZSTR_VAL(exception->ce->name), ZSTR_VAL(file), line, ZSTR_LEN(msg) < 80 ? ZSTR_LEN(msg) : 80, ZSTR_VAL(msg)); + phpdbg_error("exception", + "name=\"%s\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", + "Uncaught %s in %s on line " ZEND_LONG_FMT ": %.*s", + ZSTR_VAL(exception->ce->name), ZSTR_VAL(file), line, + ZSTR_LEN(msg) < 80 ? (int) ZSTR_LEN(msg) : 80, ZSTR_VAL(msg)); zend_string_release(msg); zend_string_release(file); diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index 696e11e762..a944d256ae 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -484,11 +484,11 @@ PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable key = ZSTR_VAL(strkey); keylen = ZSTR_LEN(strkey); } else { - keylen = spprintf(&key, 0, "%llu", numkey); + keylen = spprintf(&key, 0, ZEND_ULONG_FMT, numkey); } propkey = phpdbg_get_property_key(key); name = emalloc(i + keylen + 2); - namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, keylen - (propkey - key), propkey, input[len - 1] == ']'?"]":""); + namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, (int) (keylen - (propkey - key)), propkey, input[len - 1] == ']'?"]":""); if (!strkey) { efree(key); } @@ -597,7 +597,7 @@ static int phpdbg_xml_array_element_dump(zval *zv, zend_string *key, zend_ulong phpdbg_try_access { if (key) { /* string key */ - phpdbg_xml(" name=\"%.*s\"", ZSTR_LEN(key), ZSTR_VAL(key)); + phpdbg_xml(" name=\"%.*s\"", (int) ZSTR_LEN(key), ZSTR_VAL(key)); } else { /* numeric key */ phpdbg_xml(" name=\"%ld\"", num); } @@ -631,7 +631,7 @@ static int phpdbg_xml_object_property_dump(zval *zv, zend_string *key, zend_ulon phpdbg_xml(" class=\"%s\" protection=\"private\"", class_name); } } else { - phpdbg_xml(" name=\"%.*s\" protection=\"public\"", ZSTR_LEN(key), ZSTR_VAL(key)); + phpdbg_xml(" name=\"%.*s\" protection=\"public\"", (int) ZSTR_LEN(key), ZSTR_VAL(key)); } } else { /* numeric key */ phpdbg_xml(" name=\"%ld\" protection=\"public\"", num); @@ -683,7 +683,7 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) { phpdbg_xml("<float refstatus=\"%s\" value=\"%.*G\" />", COMMON, (int) EG(precision), Z_DVAL_P(zv)); break; case IS_STRING: - phpdbg_xml("<string refstatus=\"%s\" length=\"%d\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), Z_STRLEN_P(zv), Z_STRVAL_P(zv)); + phpdbg_xml("<string refstatus=\"%s\" length=\"%zd\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), (int) Z_STRLEN_P(zv), Z_STRVAL_P(zv)); break; case IS_ARRAY: myht = Z_ARRVAL_P(zv); @@ -705,7 +705,7 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) { } class_name = Z_OBJ_HANDLER_P(zv, get_class_name)(Z_OBJ_P(zv)); - phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, ZSTR_LEN(class_name), ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0); + phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, (int) ZSTR_LEN(class_name), ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0); zend_string_release(class_name); element_dump_func = phpdbg_xml_object_property_dump; @@ -729,7 +729,7 @@ head_done: break; case IS_RESOURCE: { const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(zv)); - phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%ld\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown"); + phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%s\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown"); break; } default: diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h index 2bd4f35d71..4ba756139b 100644 --- a/sapi/phpdbg/phpdbg_utils.h +++ b/sapi/phpdbg/phpdbg_utils.h @@ -99,6 +99,14 @@ char *phpdbg_short_zval_print(zval *zv, int maxlen); PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *ex, zend_object *exception); +static zend_always_inline zend_execute_data *phpdbg_user_execute_data(zend_execute_data *ex) { + while (!ex->func || !ZEND_USER_CODE(ex->func->common.type)) { + ex = ex->prev_execute_data; + ZEND_ASSERT(ex); + } + return ex; +} + #ifdef ZTS #define PHPDBG_OUTPUT_BACKUP_DEFINES() \ zend_output_globals *output_globals_ptr; \ diff --git a/sapi/phpdbg/phpdbg_wait.c b/sapi/phpdbg/phpdbg_wait.c index 180b48c864..c3ae23b7cd 100644 --- a/sapi/phpdbg/phpdbg_wait.c +++ b/sapi/phpdbg/phpdbg_wait.c @@ -231,7 +231,7 @@ void phpdbg_webdata_decompress(char *msg, int len) { } else if (mode > 0) { // not loaded module if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) { - phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_P(module), Z_STRVAL_P(module), Z_STRLEN_P(module), Z_STRVAL_P(module)); + phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", (int) Z_STRLEN_P(module), Z_STRVAL_P(module), (int) Z_STRLEN_P(module), Z_STRVAL_P(module)); } } } while (module); @@ -292,7 +292,7 @@ void phpdbg_webdata_decompress(char *msg, int len) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) { if (Z_TYPE_P(name) == IS_STRING) { - phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_P(name), Z_STRVAL_P(name)); + phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", (int) Z_STRLEN_P(name), Z_STRVAL_P(name)); } } ZEND_HASH_FOREACH_END(); } diff --git a/win32/build/Makefile.phpize b/win32/build/Makefile.phpize index 1f92f7716c..cd74336039 100644 --- a/win32/build/Makefile.phpize +++ b/win32/build/Makefile.phpize @@ -18,11 +18,13 @@ clean-pecl: clean-all:
@echo Cleaning standard build dirs
+ cd $(BUILD_DIR)
@for %D in (_x $(BUILD_DIRS_SUB)) do @if exist %D @rd /s /q %D
-@del /f /q $(BUILD_DIR)\*.res $(BUILD_DIR)\*.manifest $(BUILD_DIR)\*.lib $(BUILD_DIR)\*.ilk $(BUILD_DIR)\*.pdb $(BUILD_DIR)\*.exp $(PHPDEF) $(BUILD_DIR)\*.rc $(BUILD_DIR)\*.dbg $(BUILD_DIR)\*.bin $(BUILD_DIR)\php*.dll $(BUILD_DIR)\php*.exe > NUL
clean: clean-pecl
@echo Cleaning distribution build dirs
+ cd $(BUILD_DIR)
@for %D in (_x $(BUILD_DIRS_SUB)) do @if exist %D @del /F /Q %D\*.* > NUL
-@del /F /Q $(BUILD_DIR)\*.res $(BUILD_DIR)\*.lib $(BUILD_DIR)\*.ilk $(BUILD_DIR)\*.pdb $(BUILD_DIR)\*.exp $(PHPDEF) $(BUILD_DIR)\php-$(PHP_VERSION_STRING)-Win32.zip $(BUILD_DIR)\pecl-$(PHP_VERSION_STRING)-Win32.zip > NUL
diff --git a/win32/build/confutils.js b/win32/build/confutils.js index 91af62aa5c..95f7985c3d 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -1449,79 +1449,117 @@ function ADD_SOURCES(dir, file_list, target, obj_dir) var sub_build = "$(BUILD_DIR)\\"; - /* if module dir is not a child of the main source dir, - * we need to tweak it; we should have detected such a - * case in condense_path and rewritten the path to - * be relative. - * This probably breaks for non-sibling dirs, but that - * is not a problem as buildconf only checks for pecl - * as either a child or a sibling */ - if (obj_dir == null) { - var build_dir = dir.replace(new RegExp("^..\\\\"), ""); - var mangle_dir = build_dir.replace(new RegExp("[\\\\/.-]", "g"), "_"); - var bd_flags_name = "CFLAGS_BD_" + mangle_dir.toUpperCase(); - } - else { - var build_dir = obj_dir.replace(new RegExp("^..\\\\"), ""); - var mangle_dir = build_dir.replace(new RegExp("[\\\\/.-]", "g"), "_"); - var bd_flags_name = "CFLAGS_BD_" + mangle_dir.toUpperCase(); - } - - var dirs = build_dir.split("\\"); - var i, d = ""; - for (i = 0; i < dirs.length; i++) { - d += dirs[i]; - build_dirs[build_dirs.length] = d; - d += "\\"; - } - sub_build += d; - - - DEFINE(bd_flags_name, "/Fp" + sub_build + " /FR" + sub_build + " "); - if (VS_TOOLSET) { - ADD_FLAG(bd_flags_name, "/Fd" + sub_build); - } + var srcs_by_dir = {}; + /* Parse the file list to create an aggregated structure based on the subdirs passed. */ for (i in file_list) { src = file_list[i]; - obj = src.replace(re, ".obj"); - tv += " " + sub_build + obj; - resp += " " + sub_build.replace('$(BUILD_DIR)', bd) + obj; - - if (!PHP_MP_DISABLED) { - if (i > 0) { - objs_line += " " + sub_build + obj; - srcs_line += " " + dir + "\\" + src; + + var _tmp = src.split("\\"); + + var filename = _tmp.pop(); + + // build the obj out dir and use it as a key + var dirname = _tmp.join("\\"); + + //WARNING("dir: " + dir + " dirname: " + dirname + " filename: " + filename); + + /* if module dir is not a child of the main source dir, + * we need to tweak it; we should have detected such a + * case in condense_path and rewritten the path to + * be relative. + * This probably breaks for non-sibling dirs, but that + * is not a problem as buildconf only checks for pecl + * as either a child or a sibling */ + if (obj_dir == null) { + if (MODE_PHPIZE) { + /* In the phpize mode, the subdirs are always relative to BUID_DIR. + No need to differentiate by extension, only one gets built. */ + var build_dir = (dirname ? dirname : "").replace(new RegExp("^..\\\\"), ""); } else { - objs_line = sub_build + obj; - srcs_line = dir + "\\" + src; + var build_dir = (dirname ? (dir + "\\" + dirname) : dir).replace(new RegExp("^..\\\\"), ""); } - } else { - MFO.WriteLine(sub_build + obj + ": " + dir + "\\" + src); + } + else { + var build_dir = (dirname ? obj_dir + "\\" + dirname : obj_dir).replace(new RegExp("^..\\\\"), ""); + } - if (PHP_ANALYZER == "pvs") { - MFO.WriteLine("\t@\"$(PVS_STUDIO)\" --cl-params $(" + flags + ") $(CFLAGS) $(" + bd_flags_name + ") /c " + dir + "\\" + src + " --source-file " + dir + "\\" + src - + " --cfg PVS-Studio.conf --errors-off \"V122 V117 V111\" "); - } - MFO.WriteLine("\t@$(CC) $(" + flags + ") $(CFLAGS) $(" + bd_flags_name + ") /c " + dir + "\\" + src + " /Fo" + sub_build + obj); + obj = sub_build + build_dir + "\\" + filename.replace(re, ".obj"); + + if (i > 0) { + srcs_line += " " + dir + "\\" + src; + objs_line += " " + obj + } else { + srcs_line = dir + "\\" + src; + objs_line = obj; } + + resp += " " + obj.replace('$(BUILD_DIR)', bd); + tv += " " + obj; + + if (!srcs_by_dir.hasOwnProperty(build_dir)) { + srcs_by_dir[build_dir] = []; + } + + /* storing the index from the file_list */ + srcs_by_dir[build_dir].push(i); } - if (!PHP_MP_DISABLED) { - MFO.WriteLine(objs_line + ": " + srcs_line); - MFO.WriteLine("\t$(CC) $(" + flags + ") $(CFLAGS) /Fo" + sub_build + " $(" + bd_flags_name + ") /c " + srcs_line); + /* Create makefile build targets and dependencies. */ + MFO.WriteLine(objs_line + ": " + srcs_line); + + /* Create target subdirs if any and produce the compiler calls, /mp is respected if enabled. */ + for (var k in srcs_by_dir) { + var dirs = k.split("\\"); + var i, d = ""; + for (i = 0; i < dirs.length; i++) { + d += dirs[i]; + build_dirs[build_dirs.length] = d; + d += "\\"; + } + + var mangle_dir = k.replace(new RegExp("[\\\\/.-]", "g"), "_"); + var bd_flags_name = "CFLAGS_BD_" + mangle_dir.toUpperCase(); + + DEFINE(bd_flags_name, "/Fp" + sub_build + d + " /FR" + sub_build + d + " "); + if (VS_TOOLSET) { + ADD_FLAG(bd_flags_name, "/Fd" + sub_build + d); + } + + if (PHP_MP_DISABLED) { + for (var j in srcs_by_dir[k]) { + src = file_list[srcs_by_dir[k][j]]; + if (PHP_ANALYZER == "pvs") { + MFO.WriteLine("\t@\"$(PVS_STUDIO)\" --cl-params $(" + flags + ") $(CFLAGS) $(" + bd_flags_name + ") /c " + dir + "\\" + src + " --source-file " + dir + "\\" + src + + " --cfg PVS-Studio.conf --errors-off \"V122 V117 V111\" "); + } + + var _tmp = src.split("\\"); + var filename = _tmp.pop(); + obj = filename.replace(re, ".obj"); + + MFO.WriteLine("\t@$(CC) $(" + flags + ") $(CFLAGS) $(" + bd_flags_name + ") /c " + dir + "\\" + src + " /Fo" + sub_build + d + obj); + } + } else { + /* TODO create a response file at least for the source files to work around the cmd line length limit. */ + var src_line = ""; + for (var j in srcs_by_dir[k]) { + src_line += dir + "\\" + file_list[srcs_by_dir[k][j]] + " "; + } + + MFO.WriteLine("\t$(CC) $(" + flags + ") $(CFLAGS) /Fo" + sub_build + d + " $(" + bd_flags_name + ") /c " + src_line); + } } DEFINE(sym, tv); - /* Generate the response file and define it to the Makefile. This can be - useful when getting the "command line too long" linker errors. */ + /* Generate the object response file and define it to the Makefile. This can be + useful when getting the "command line too long" linker errors. + TODO pack this into a function when response files are used for other kinds of info. */ var obj_lst_fh = null; if (!FSO.FileExists(obj_lst_fn)) { obj_lst_fh = FSO.CreateTextFile(obj_lst_fn); - //STDOUT.WriteLine("Creating " + obj_lst_fn); } else { - //STDOUT.WriteLine("Appending to " + obj_lst_fn); obj_lst_fh = FSO.OpenTextFile(obj_lst_fn, 8); } @@ -2109,7 +2147,16 @@ function ADD_FLAG(name, flags, target) if (configure_subst.Exists(name)) { var curr_flags = configure_subst.Item(name); - if (curr_flags.indexOf(flags) >= 0) { + /* Prefix with a space, thus making sure the + current flag is not a substring of some + other. It's still not a complete check if + some flags with spaces got added. + + TODO rework to use an array, so direct + match can be done. This will also + help to normalize flags and to not + to insert duplicates. */ + if (curr_flags.indexOf(" " + flags) >= 0) { return; } |