diff --git a/NEWS b/NEWS index 1e935141776..3372504cdfd 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,90 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? 2016, PHP 7.1.0RC1 +?? ??? 2016, PHP 7.1.0RC2 + +- Opcache: + . Fixed bug #72982 (Memory leak in zend_accel_blacklist_update_regexp() + function). (Laruence) +01 Sep 2016, PHP 7.1.0RC1 + +- Core: + . Fixed bug #72944 (Null pointer deref in zval_delref_p). (Dmitry) + . Fixed bug #72943 (assign_dim on string doesn't reset hval). (Laruence) + . Fixed bug #72598 (Reference is lost after array_slice()) (Nikita) + . Fixed bug #72703 (Out of bounds global memory read in BF_crypt triggered by + password_verify). (Anatol) + . Implement \ArgumentCountError when passing in too few arguments (Davey) + +- COM: + . Fixed bug #72922 (COM called from PHP does not return out parameters). + (Anatol) + +- Dba: + . Fixed bug #70825 (Cannot fetch multiple values with group in ini file). + (cmb) + +- GD: + . Fixed bug #66005 (imagecopy does not support 1bit transparency on truecolor + images). (cmb) + . Fixed bug #72913 (imagecopy() loses single-color transparency on palette + images). (cmb) + . Fixed bug #68716 (possible resource leaks in _php_image_convert()). (cmb) + +- iconv: + . Fixed bug #72320 (iconv_substr returns false for empty strings). (cmb) + +- Intl: + . Fixed bug #65732 (grapheme_*() is not Unicode compliant on CR LF + sequence). (cmb) + +- JSON: + . Implemented earlier return when json_encode fails, fixes bugs #68992 + (Stacking exceptions thrown by JsonSerializable) and #70275 (On recursion + error, json_encode can eat up all system memory). (Jakub Zelenka) + +- mbstring: + . Fixed bug #66797 (mb_substr only takes 32-bit signed integer). (cmb) + +- Opcache: + . Fixed bug #72949 (Typo in opcache error message). (cmb) + +- PDO_DBlib: + . Implemented stringify 'uniqueidentifier' fields. + (Alexander Zhuravlev, Adam Baratz) + +- Reflection: + . Reverted prepending \ for class names. (Trowski) + +- Session: + . Fixed bug #72940 (SID always return "name=ID", even if session + cookie exist). (Yasuo) + . Implemented session_gc() (Yasuo) + https://wiki.php.net/rfc/session-create-id + . Implemented session_create_id() (Yasuo) + https://wiki.php.net/rfc/session-gc + +- SimpleXML: + . Fixed bug #72971 (SimpleXML isset/unset do not respect namespace). (Nikita) + . Fixed bug #72957 (Null coalescing operator doesn't behave as expected with + SimpleXMLElement). (Nikita) + +- SOAP: + . Fixed bug #71711 (Soap Server Member variables reference bug). (Nikita) + . Fixed bug #71996 (Using references in arrays doesn't work like expected). + (Nikita) + +- Standard: + . Fixed bug #72920 (Accessing a private constant using constant() creates + an exception AND warning). (Laruence) + . Fixed bug #65550 (get_browser() incorrectly parses entries with "+" sign). + (cmb) + . Fixed bug #71882 (Negative ftruncate() on php://memory exhausts memory). + (cmb) + +- XML: + . Fixed bug #72714 (_xml_startElementHandler() segmentation fault). (cmb) 18 Aug 2016, PHP 7.1.0beta3 @@ -18,6 +100,8 @@ PHP NEWS . Fixed bug #72681 (PHP Session Data Injection Vulnerability). (Stas) . Fixed bug #72742 (memory allocator fails to realloc small block to large one). (Stas) + . Fixed URL rewriter. It would not rewrite '//example.com/' URL + unconditionally. URL rewrite target hosts whitelist is implemented. (Yasuo) - Bz2: . Fixed bug #72837 (integer overflow in bzdecompress caused heap @@ -59,8 +143,10 @@ PHP NEWS - Reflection: . Implemented request #38992 (invoke() and invokeArgs() static method calls should match). (cmb). - . Add ReflectionNamedType::getName() and return leading "?" for nullable types - from ReflectionType::__toString(). (Trowski) + . Add ReflectionNamedType::getName(). This method should be used instead of + ReflectionType::__toString() + . Prepend \ for class names and ? for nullable types returned from + ReflectionType::__toString(). (Trowski) - Session: . Implemented RFC: Session ID without hashing. (Yasuo) diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 4651cbf0798..ae92e1fbf17 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -672,6 +672,12 @@ TSRM_API int shmget(int key, int size, int flags) } } else { if (flags & IPC_EXCL) { + if (shm_handle) { + CloseHandle(shm_handle); + } + if (info_handle) { + CloseHandle(info_handle); + } return -1; } } diff --git a/UPGRADING b/UPGRADING index 410a0f25732..53d7b5f9e61 100644 --- a/UPGRADING +++ b/UPGRADING @@ -61,7 +61,7 @@ PHP 7.1 UPGRADE NOTES . Fixes to random number generators mean that mt_rand() now produces a different sequence of outputs to previous versions. If you relied on mt_srand() to produce a deterministic sequence, it can be called using - mt_srand($seed, MT_RAND_PHP) to produce old the sequences. + mt_srand($seed, MT_RAND_PHP) to produce the old sequences. . URL rewriter has been improved. . Use dedicated buffer for Session module rewrite and User rewrite. . Full path URL rewrite is supported. Allowed domain can be specified. @@ -122,7 +122,7 @@ PHP 7.1 UPGRADE NOTES - Reflection: . The behavior of ReflectionMethod::invoke() and ::invokeArgs() has been - aligned, what causes slightly different behavior than before for some + aligned, which causes slightly different behavior than before for some pathological cases. . ReflectionType::__toString() will now return the type name with a leading "?" if it is nullable. To retrieve the type name without leading "?" the new @@ -236,6 +236,12 @@ PHP 7.1 UPGRADE NOTES . Added pcntl_signal_get_handler() that returns the current signal handler for a particular signal. +- Session: + . Added session_gc() that performs session data garbage collection. + https://wiki.php.net/rfc/session-gc + . Added session_create_id() for creating custom session ID. + https://wiki.php.net/rfc/session-create-id + - Standard: . Added is_iterable() that determines if a value will be accepted by the new iterable pseudo-type. @@ -262,7 +268,7 @@ PHP 7.1 UPGRADE NOTES - DBA: . Data modification functions (e.g.: dba_insert()) now throw an instance of - Error instead of triggering a catchable fatal error if the key is does not + Error instead of triggering a catchable fatal error if the key does not contain exactly two elements. - DOM: diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 1a922e6294a..710c131297b 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -82,6 +82,8 @@ changes. See: https://wiki.php.net/phpng-upgrading a. Unix build system changes b. Windows build system changes + Static analysis with clang and Cppcheck is supported by passing "clang" or + "cppcheck" keyword to the --with-analyzer configure option. ======================== 3. Module changes diff --git a/Zend/tests/bug38047.phpt b/Zend/tests/bug38047.phpt index 09739d23ebb..e6eeb6631dd 100644 --- a/Zend/tests/bug38047.phpt +++ b/Zend/tests/bug38047.phpt @@ -44,7 +44,7 @@ Non-static method A::A_ftk() should not be called statically 2 %sbug38047.php:36 kalus_error_handler() -Fatal error: Uncaught Error: Too few arguments to function A::A_ftk(), 0 passed in %sbug38047.php on line 36 and exactly 1 expected in %sbug38047.php:7 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function A::A_ftk(), 0 passed in %sbug38047.php on line 36 and exactly 1 expected in %sbug38047.php:7 Stack trace: #0 %sbug38047.php(36): A::A_ftk() #1 {main} diff --git a/Zend/tests/bug55705.phpt b/Zend/tests/bug55705.phpt index fc17139344d..06811bbc1b9 100644 --- a/Zend/tests/bug55705.phpt +++ b/Zend/tests/bug55705.phpt @@ -6,7 +6,7 @@ function f(callable $c) {} f(); ?> --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function f(), 0 passed in %s on line 3 and exactly 1 expected in %s:2 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %s on line 3 and exactly 1 expected in %s:2 Stack trace: #0 %s(%d): f() #1 {main} diff --git a/Zend/tests/bug70689.phpt b/Zend/tests/bug70689.phpt index 286b6f42258..882dd89b75c 100644 --- a/Zend/tests/bug70689.phpt +++ b/Zend/tests/bug70689.phpt @@ -19,7 +19,7 @@ try { ?> --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function foo(), 0 passed in %sbug70689.php on line 12 and exactly 1 expected in %sbug70689.php:3 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in %sbug70689.php on line 12 and exactly 1 expected in %sbug70689.php:3 Stack trace: #0 %sbug70689.php(12): foo() #1 {main} diff --git a/Zend/tests/bug72598.phpt b/Zend/tests/bug72598.phpt new file mode 100644 index 00000000000..dfb09a05b8f --- /dev/null +++ b/Zend/tests/bug72598.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #72598 (Reference is lost after array_slice()) +--FILE-- + +--EXPECTF-- +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598.php on line 11 +object(class@anonymous)#1 (0) { +} + +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598.php on line 11 +object(class@anonymous)#1 (0) { +} diff --git a/Zend/tests/bug72598_2.phpt b/Zend/tests/bug72598_2.phpt new file mode 100644 index 00000000000..c3943806ff4 --- /dev/null +++ b/Zend/tests/bug72598_2.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #72598.2 (Reference is lost after array_slice()) +--FILE-- + +--EXPECTF-- +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598_2.php on line 14 +int(0) + +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598_2.php on line 14 +int(0) diff --git a/Zend/tests/bug72911.phpt b/Zend/tests/bug72911.phpt new file mode 100644 index 00000000000..098261cadf2 --- /dev/null +++ b/Zend/tests/bug72911.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72911 (Memleak in zend_binary_assign_op_obj_helper) +--FILE-- +b->i -= 0; + +var_dump($b); + +?> +--EXPECTF-- +Warning: Attempt to modify property of non-object in %sbug72911.php on line %d + +Warning: Attempt to assign property of non-object in %sbug72911.php on line %d +NULL diff --git a/Zend/tests/bug72943.phpt b/Zend/tests/bug72943.phpt new file mode 100644 index 00000000000..8bab6de4564 --- /dev/null +++ b/Zend/tests/bug72943.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #72943 (assign_dim on string doesn't reset hval) +--FILE-- + 1); + +$a = "lest"; +var_dump($array[$a]); +$a[0] = "f"; +var_dump($array[$a]); +$a[0] = "t"; +var_dump($array[$a]); +?> +--EXPECTF-- +Notice: Undefined index: lest in %sbug72943.php on line %d +NULL + +Notice: Undefined index: fest in %sbug72943.php on line %d +NULL +int(1) diff --git a/Zend/tests/bug72944.phpt b/Zend/tests/bug72944.phpt new file mode 100644 index 00000000000..541730a22a7 --- /dev/null +++ b/Zend/tests/bug72944.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #72944 (Null pointer deref in zval_delref_p). +--FILE-- + +--EXPECTF-- +Notice: Use of undefined constant e - assumed 'e' in %sbug72944.php on line 2 + +Notice: Undefined variable: A in %sbug72944.php on line 2 +OK diff --git a/Zend/tests/call_user_func_008.phpt b/Zend/tests/call_user_func_008.phpt new file mode 100644 index 00000000000..3e727e7f43c --- /dev/null +++ b/Zend/tests/call_user_func_008.phpt @@ -0,0 +1,54 @@ +--TEST-- +call_user_func() behavior with references +--FILE-- + +--EXPECTF-- +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) diff --git a/Zend/tests/function_arguments/argument_count_correct.phpt b/Zend/tests/function_arguments/argument_count_correct.phpt new file mode 100644 index 00000000000..44a87b8ba8a --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_correct.phpt @@ -0,0 +1,20 @@ +--TEST-- +Call function with correct number of arguments +--FILE-- +getMessage() . PHP_EOL; +} + +array_diff([]); +--EXPECTF-- +ArgumentCountError +substr() expects at least 2 parameters, 1 given + +Warning: array_diff(): at least 2 parameters are required, 1 given in %s \ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt new file mode 100644 index 00000000000..97faa4eb5c1 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt @@ -0,0 +1,44 @@ +--TEST-- +Call userland function with incorrect number of arguments +--FILE-- +getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected \ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt new file mode 100644 index 00000000000..9029dc26253 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt @@ -0,0 +1,54 @@ +--TEST-- +Call userland function with incorrect number of arguments with strict types +--FILE-- +getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat(123, 456); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +TypeError +Argument 1 passed to bat() must be of the type integer, string given, called in %s +TypeError +Argument 2 passed to bat() must be of the type string, integer given, called in %s \ No newline at end of file diff --git a/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt index 5de93bb7d62..3050feed53c 100644 --- a/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt +++ b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt @@ -9,7 +9,7 @@ function f(?callable $p) {} f(); --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function f(), 0 passed in %snullable_type_parameters_do_not_have_default_value.php on line %d and exactly 1 expected in %s:%d +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %snullable_type_parameters_do_not_have_default_value.php on line %d and exactly 1 expected in %s:%d Stack trace: #%d %s #%d %s diff --git a/Zend/zend.c b/Zend/zend.c index 118bd6c4961..12801c8b70a 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1372,6 +1372,23 @@ ZEND_API ZEND_COLD void zend_internal_type_error(zend_bool throw_exception, cons va_end(va); } /* }}} */ +ZEND_API ZEND_COLD void zend_internal_argument_count_error(zend_bool throw_exception, const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + if (throw_exception) { + zend_throw_exception(zend_ce_argument_count_error, message, 0); + } else { + zend_error(E_WARNING, "%s", message); + } + efree(message); + + va_end(va); +} /* }}} */ + ZEND_API ZEND_COLD void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) /* {{{ */ { #if ZEND_DEBUG diff --git a/Zend/zend.h b/Zend/zend.h index 94f2fbdcf4d..04c9052e283 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -271,6 +271,7 @@ ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRI ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API ZEND_COLD void zend_type_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); ZEND_API ZEND_COLD void zend_internal_type_error(zend_bool throw_exception, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD void zend_internal_argument_count_error(zend_bool throw_exception, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_COLD void zenderror(const char *error); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fb0194f4af5..eaed067b69a 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -157,7 +157,7 @@ ZEND_API ZEND_COLD void zend_wrong_param_count(void) /* {{{ */ const char *space; const char *class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); + zend_internal_argument_count_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); } /* }}} */ @@ -208,14 +208,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int num_ zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects %s %d parameter%s, %d given", - class_name, \ - class_name[0] ? "::" : "", \ - ZSTR_VAL(active_function->common.function_name), - min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most", - num_args < min_num_args ? min_num_args : max_num_args, - (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s", - num_args); + zend_internal_argument_count_error( + ZEND_ARG_USES_STRICT_TYPES(), + "%s%s%s() expects %s %d parameter%s, %d given", + class_name, \ + class_name[0] ? "::" : "", \ + ZSTR_VAL(active_function->common.function_name), + min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most", + num_args < min_num_args ? min_num_args : max_num_args, + (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s", + num_args); } /* }}} */ @@ -875,7 +877,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; zend_bool throw_exception = ZEND_ARG_USES_STRICT_TYPES() || (flags & ZEND_PARSE_PARAMS_THROW); - zend_internal_type_error(throw_exception, "%s%s%s() expects %s %d parameter%s, %d given", + zend_internal_argument_count_error(throw_exception, "%s%s%s() expects %s %d parameter%s, %d given", class_name, class_name[0] ? "::" : "", ZSTR_VAL(active_function->common.function_name), @@ -2909,7 +2911,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca zend_string *mname, *cname; zend_string *lmname; const char *colon; - size_t clen, mlen; + size_t clen; HashTable *ftable; int call_via_handler = 0; zend_class_entry *scope; @@ -2962,6 +2964,8 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca colon > Z_STRVAL_P(callable) && *(colon-1) == ':' ) { + size_t mlen; + colon--; clen = colon - Z_STRVAL_P(callable); mlen = Z_STRLEN_P(callable) - clen - 2; @@ -2994,7 +2998,6 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca mname = zend_string_init(Z_STRVAL_P(callable) + clen + 2, mlen, 0); } else if (ce_org) { /* Try to fetch find static method of given class. */ - mlen = Z_STRLEN_P(callable); mname = Z_STR_P(callable); zend_string_addref(mname); ftable = &ce_org->function_table; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b61a8195282..24da5209d7d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2198,10 +2198,42 @@ static inline uint32_t zend_emit_jump(uint32_t opnum_target) /* {{{ */ } /* }}} */ +ZEND_API int zend_is_smart_branch(zend_op *opline) /* {{{ */ +{ + switch (opline->opcode) { + case ZEND_IS_IDENTICAL: + case ZEND_IS_NOT_IDENTICAL: + case ZEND_IS_EQUAL: + case ZEND_IS_NOT_EQUAL: + case ZEND_IS_SMALLER: + case ZEND_IS_SMALLER_OR_EQUAL: + case ZEND_CASE: + case ZEND_ISSET_ISEMPTY_VAR: + case ZEND_ISSET_ISEMPTY_DIM_OBJ: + case ZEND_ISSET_ISEMPTY_PROP_OBJ: + case ZEND_INSTANCEOF: + case ZEND_TYPE_CHECK: + case ZEND_DEFINED: + return 1; + default: + return 0; + } +} +/* }}} */ + static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target) /* {{{ */ { uint32_t opnum = get_next_op_number(CG(active_op_array)); - zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL); + zend_op *opline; + + if ((cond->op_type & (IS_CV|IS_CONST)) + && opnum > 0 + && zend_is_smart_branch(CG(active_op_array)->opcodes + opnum - 1)) { + /* emit extra NOP to avoid incorrect SMART_BRANCH in very rare cases */ + zend_emit_op(NULL, ZEND_NOP, NULL, NULL); + opnum = get_next_op_number(CG(active_op_array)); + } + opline = zend_emit_op(NULL, opcode, cond, NULL); opline->op2.opline_num = opnum_target; return opnum; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 56b80eed6a3..1f0773d9a7a 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -791,6 +791,7 @@ ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers); uint32_t zend_get_class_fetch_type(zend_string *name); ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc); +ZEND_API int zend_is_smart_branch(zend_op *opline); typedef zend_bool (*zend_auto_global_callback)(zend_string *name); typedef struct _zend_auto_global { diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 5301850310e..dc073de6339 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -36,6 +36,7 @@ ZEND_API zend_class_entry *zend_ce_error_exception; ZEND_API zend_class_entry *zend_ce_error; ZEND_API zend_class_entry *zend_ce_parse_error; ZEND_API zend_class_entry *zend_ce_type_error; +ZEND_API zend_class_entry *zend_ce_argument_count_error; ZEND_API zend_class_entry *zend_ce_arithmetic_error; ZEND_API zend_class_entry *zend_ce_division_by_zero_error; @@ -709,7 +710,7 @@ ZEND_METHOD(exception, __toString) ZVAL_UNDEF(&trace); } - if (Z_OBJCE_P(exception) == zend_ce_type_error && strstr(ZSTR_VAL(message), ", called in ")) { + if ((Z_OBJCE_P(exception) == zend_ce_type_error || Z_OBJCE_P(exception) == zend_ce_argument_count_error) && strstr(ZSTR_VAL(message), ", called in ")) { zend_string *real_message = zend_strpprintf(0, "%s and defined", ZSTR_VAL(message)); zend_string_release(message); message = real_message; @@ -859,6 +860,10 @@ void zend_register_default_exception(void) /* {{{ */ zend_ce_type_error = zend_register_internal_class_ex(&ce, zend_ce_error); zend_ce_type_error->create_object = zend_default_exception_new; + INIT_CLASS_ENTRY(ce, "ArgumentCountError", NULL); + zend_ce_argument_count_error = zend_register_internal_class_ex(&ce, zend_ce_type_error); + zend_ce_argument_count_error->create_object = zend_default_exception_new; + INIT_CLASS_ENTRY(ce, "ArithmeticError", NULL); zend_ce_arithmetic_error = zend_register_internal_class_ex(&ce, zend_ce_error); zend_ce_arithmetic_error->create_object = zend_default_exception_new; diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 04857f29fab..18caf355539 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -32,6 +32,7 @@ extern ZEND_API zend_class_entry *zend_ce_error_exception; extern ZEND_API zend_class_entry *zend_ce_error; extern ZEND_API zend_class_entry *zend_ce_parse_error; extern ZEND_API zend_class_entry *zend_ce_type_error; +extern ZEND_API zend_class_entry *zend_ce_argument_count_error; extern ZEND_API zend_class_entry *zend_ce_arithmetic_error; extern ZEND_API zend_class_entry *zend_ce_division_by_zero_error; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d2411ad5c3b..c748a777111 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -696,20 +696,24 @@ static ZEND_COLD void zend_verify_arg_error( const char *fname, *fsep, *fclass; const char *need_msg, *need_kind, *need_or_null, *given_msg, *given_kind; - zend_verify_type_error_common( - zf, arg_info, ce, value, - &fname, &fsep, &fclass, &need_msg, &need_kind, &need_or_null, &given_msg, &given_kind); + if (value) { + zend_verify_type_error_common( + zf, arg_info, ce, value, + &fname, &fsep, &fclass, &need_msg, &need_kind, &need_or_null, &given_msg, &given_kind); - if (zf->common.type == ZEND_USER_FUNCTION) { - if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { - zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given, called in %s on line %d", - arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind, - ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno); + if (zf->common.type == ZEND_USER_FUNCTION) { + if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { + zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given, called in %s on line %d", + arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind, + ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno); + } else { + zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); + } } else { zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); } } else { - zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); + zend_missing_arg_error(ptr); } } @@ -955,7 +959,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data * zend_execute_data *ptr = EX(prev_execute_data); if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { - zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected", + zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected", EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "", EX(func)->common.scope ? "::" : "", ZSTR_VAL(EX(func)->common.function_name), @@ -965,7 +969,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data * EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least", EX(func)->common.required_num_args); } else { - zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed and %s %d expected", + zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed and %s %d expected", EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "", EX(func)->common.scope ? "::" : "", ZSTR_VAL(EX(func)->common.function_name), @@ -1330,6 +1334,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zend_string_release(old_str); } else { SEPARATE_STRING(str); + zend_string_forget_hash_val(Z_STR_P(str)); } Z_STRVAL_P(str)[offset] = c; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3432064eafa..dc411af8355 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -788,41 +788,29 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (fci->no_separation && - !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { - if (i) { - /* hack to clean up the stack */ - ZEND_CALL_NUM_ARGS(call) = i; - zend_vm_stack_free_args(call); - } - zend_vm_stack_free_call_frame(call); - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - i+1, + if (!fci->no_separation) { + /* Separation is enabled -- create a ref */ + ZVAL_NEW_REF(arg, arg); + } else if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { + /* By-value send is not allowed -- emit a warning, + * but still perform the call with a by-value send. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, func->common.scope ? ZSTR_VAL(func->common.scope->name) : "", func->common.scope ? "::" : "", ZSTR_VAL(func->common.function_name)); - if (EG(current_execute_data) == &dummy_execute_data) { - EG(current_execute_data) = dummy_execute_data.prev_execute_data; - } - return FAILURE; } - - ZVAL_NEW_REF(arg, arg); } - Z_ADDREF_P(arg); } else { if (Z_ISREF_P(arg) && !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { /* don't separate references for __call */ arg = Z_REFVAL_P(arg); } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } } + param = ZEND_CALL_ARG(call, i+1); - ZVAL_COPY_VALUE(param, arg); + ZVAL_COPY(param, arg); } if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index b59d5885a6d..622d94a5f5d 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2444,7 +2444,6 @@ ZEND_API int ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t l register const char *tmp = key; const char *end = key + length; - ZEND_ASSERT(*end == '\0'); if (*tmp == '-') { tmp++; diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index bc7826440eb..09b9137ce44 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -328,32 +328,19 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{ buf->st_dev = buf->st_rdev = 0; } else { wchar_t cur_path[MAXPATHLEN+1]; - DWORD len = sizeof(cur_path); - wchar_t *tmp = cur_path; - while(1) { - DWORD r = GetCurrentDirectoryW(len, tmp); - if (r < len) { - if (tmp[1] == L':') { - if (pathw[0] >= L'A' && pathw[0] <= L'Z') { - buf->st_dev = buf->st_rdev = pathw[0] - L'A'; - } else { - buf->st_dev = buf->st_rdev = pathw[0] - L'a'; - } + if (NULL != _wgetcwd(cur_path, sizeof(cur_path)/sizeof(wchar_t))) { + if (cur_path[1] == L':') { + if (pathw[0] >= L'A' && pathw[0] <= L'Z') { + buf->st_dev = buf->st_rdev = pathw[0] - L'A'; } else { - buf->st_dev = buf->st_rdev = -1; + buf->st_dev = buf->st_rdev = pathw[0] - L'a'; } - break; - } else if (!r) { - buf->st_dev = buf->st_rdev = -1; - break; } else { - len = r+1; - tmp = (wchar_t*)malloc(len*sizeof(wchar_t)); + buf->st_dev = buf->st_rdev = -1; } - } - if (tmp != cur_path) { - free(tmp); + } else { + buf->st_dev = buf->st_rdev = -1; } } @@ -934,7 +921,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i wchar_t * reparsetarget; BOOL isVolume = FALSE; char *printname = NULL, *substitutename = NULL; - int printname_len, substitutename_len; + int substitutename_len; int substitutename_off = 0; if(++(*ll) > LINK_MAX) { @@ -969,7 +956,6 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) { reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget; - printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR); isabsolute = (pbuffer->SymbolicLinkReparseBuffer.Flags == 0) ? 1 : 0; printname = php_win32_ioutil_w_to_any(reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)); if (!printname) { @@ -992,7 +978,6 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { isabsolute = 1; reparsetarget = pbuffer->MountPointReparseBuffer.ReparseTarget; - printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR); printname = php_win32_ioutil_w_to_any(reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)); if (!printname) { free_alloca(pbuffer, use_heap_large); @@ -1406,6 +1391,7 @@ verify: tmp = erealloc(state->cwd, state->cwd_length+1); if (tmp == NULL) { + CWD_STATE_FREE(&old_state); #if VIRTUAL_CWD_DEBUG fprintf (stderr, "Out of memory\n"); #endif diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1a52041ab3f..c64eebb7816 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4626,23 +4626,15 @@ ZEND_VM_C_LABEL(send_array): if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + /* By-value send is not allowed -- emit a warning, + * but still perform the call. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", arg_num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - break; } } } else { @@ -4673,25 +4665,12 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM) param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3d0bcf8a191..15acbd29fbd 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1423,23 +1423,15 @@ send_array: if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + /* By-value send is not allowed -- emit a warning, + * but still perform the call. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", arg_num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - break; } } } else { @@ -15904,25 +15896,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { @@ -34925,24 +34904,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { @@ -61867,7 +61834,7 @@ void zend_init_opcodes_handlers(void) 4596 }; zend_opcode_handlers = labels; - zend_handlers_count = sizeof(labels) / sizeof(void*); + zend_handlers_count = sizeof(labels) / sizeof(void*); zend_spec_handlers = specs; } diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index ff6c8f5ad1d..d379599a16c 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1827,7 +1827,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) gen_specs($f, $spec, $kind, $prolog."\t", $specs); out($f,$prolog."};\n"); out($f,$prolog."zend_opcode_handlers = labels;\n"); - out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n"); + out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n"); out($f,$prolog."zend_spec_handlers = specs;\n"); } break; diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index 513725f5c28..28d275d32c1 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -92,7 +92,7 @@ typedef struct bc_struct /* Define the _PROTOTYPE macro if it is needed. */ #ifndef _PROTOTYPE -#ifdef __STDC__ +#if defined(__STDC__) || defined(PHP_WIN32) && defined(__clang__) #define _PROTOTYPE(func, args) func args #else #define _PROTOTYPE(func, args) func() diff --git a/ext/com_dotnet/com_com.c b/ext/com_dotnet/com_com.c index bb87d8fb2f2..ec1c72191c8 100644 --- a/ext/com_dotnet/com_com.c +++ b/ext/com_dotnet/com_com.c @@ -553,7 +553,10 @@ int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function * for (i = 0, j = 0; i < nargs; i++) { /* if this was byref, update the zval */ if (f->arg_info[nargs - i - 1].pass_by_reference) { - SEPARATE_ZVAL_IF_NOT_REF(&args[nargs - i - 1]); + zval *arg = &args[nargs - i - 1]; + + ZVAL_DEREF(arg); + SEPARATE_ZVAL_NOREF(arg); /* if the variant is pointing at the byref_vals, we need to map * the pointee value as a zval; otherwise, the value is pointing @@ -561,14 +564,12 @@ int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function * if (V_VT(&vargs[i]) & VT_BYREF) { if (vargs[i].byref == &V_UINT(&byref_vals[j])) { /* copy that value */ - php_com_zval_from_variant(&args[nargs - i - 1], &byref_vals[j], - obj->code_page); + php_com_zval_from_variant(arg, &byref_vals[j], obj->code_page); } } else { /* not sure if this can ever happen; the variant we marked as BYREF * is no longer BYREF - copy its value */ - php_com_zval_from_variant(&args[nargs - i - 1], &vargs[i], - obj->code_page); + php_com_zval_from_variant(arg, &vargs[i], obj->code_page); } VariantClear(&byref_vals[j]); j++; diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 122c618426c..a477093311d 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -279,7 +279,6 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER; f.function_name = zend_string_copy(name); f.handler = PHP_FN(com_method_handler); - zend_set_function_arg_flags((zend_function*)&f); fptr = &f; @@ -305,11 +304,12 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) { f.arg_info[i].allow_null = 1; if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) { - f.arg_info[i].pass_by_reference = 1; + f.arg_info[i].pass_by_reference = ZEND_SEND_BY_REF; } } f.num_args = bindptr.lpfuncdesc->cParams; + zend_set_function_arg_flags((zend_function*)&f); ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc); break; diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 08846808fc6..0fe4dbf2e96 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1901,8 +1901,9 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode) int len; char s[64]; char *tmp; - strncpy(s, slist->data, 64); - tmp = memchr(s, ':', 64); + strncpy(s, slist->data, sizeof(s)); + s[sizeof(s)-1] = '\0'; + tmp = memchr(s, ':', sizeof(s)); if(tmp) { *tmp = '\0'; len = strlen(s); diff --git a/ext/dba/libinifile/inifile.c b/ext/dba/libinifile/inifile.c index 18a7cb97a7a..25d8a6d2432 100644 --- a/ext/dba/libinifile/inifile.c +++ b/ext/dba/libinifile/inifile.c @@ -250,6 +250,7 @@ val_type inifile_fetch(inifile *dba, const key_type *key, int skip) { if (skip == -1 && dba->next.key.group && dba->next.key.name && !inifile_key_cmp(&dba->next.key, key)) { /* we got position already from last fetch */ php_stream_seek(dba->fp, dba->next.pos, SEEK_SET); + ln.key.group = estrdup(dba->next.key.group); } else { /* specific instance or not same key -> restart search */ /* the slow way: restart and seacrch */ diff --git a/ext/dba/tests/bug70825.phpt b/ext/dba/tests/bug70825.phpt new file mode 100644 index 00000000000..ff05f01cf4f --- /dev/null +++ b/ext/dba/tests/bug70825.phpt @@ -0,0 +1,71 @@ +--TEST-- +Bug #70825 (Cannot fetch multiple values with group in ini file) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +string(2) "23" +string(2) "42" +string(4) "1337" +string(2) "23" +string(2) "42" +string(4) "1337" +string(2) "23" +string(2) "42" +string(4) "1337" +string(2) "23" +string(2) "42" +string(4) "1337" +==DONE== +--CLEAN-- + diff --git a/ext/dba/tests/bug71514.phpt b/ext/dba/tests/bug71514.phpt new file mode 100644 index 00000000000..08338f3793c --- /dev/null +++ b/ext/dba/tests/bug71514.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #71514 (Bad dba_replace condition because of wrong API usage) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +string(6) "value2" +==DONE== +--CLEAN-- + diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index 5629c2e3122..1a04cd179be 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -139,7 +139,10 @@ if ($pid) { $buf = fread($s, 2048); } - if (!preg_match('/^USER (\w+)\r\n$/', $buf, $m)) { + if ($buf == "AUTH TLS\r\n") { + fputs($s, "500 not supported.\r\n"); + return ; + } else if (!preg_match('/^USER (\w+)\r\n$/', $buf, $m)) { fputs($s, "500 Syntax error, command unrecognized.\r\n"); dump_and_exit($buf); } @@ -208,6 +211,10 @@ if ($pid) { $ascii = true; fputs($s, "200 OK\r\n"); + } elseif ($buf === "AUTH SSL\r\n") { + $ascii = true; + fputs($s, "500 not supported\r\n"); + } elseif ($buf === "TYPE I\r\n") { $ascii = false; fputs($s, "200 OK\r\n"); diff --git a/ext/gd/gd.c b/ext/gd/gd.c index d2655a6022d..bd5af9004a0 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -4071,6 +4071,7 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) dest = VCWD_FOPEN(fn_dest, "wb"); if (!dest) { php_error_docref(NULL, E_WARNING, "Unable to open '%s' for writing", fn_dest); + fclose(org); RETURN_FALSE; } @@ -4079,6 +4080,8 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) im_org = gdImageCreateFromGif(org); if (im_org == NULL) { php_error_docref(NULL, E_WARNING, "Unable to open '%s' Not a valid GIF file", fn_dest); + fclose(org); + fclose(dest); RETURN_FALSE; } break; @@ -4089,6 +4092,8 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) im_org = gdImageCreateFromJpegEx(org, ignore_warning); if (im_org == NULL) { php_error_docref(NULL, E_WARNING, "Unable to open '%s' Not a valid JPEG file", fn_dest); + fclose(org); + fclose(dest); RETURN_FALSE; } break; @@ -4099,6 +4104,8 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) im_org = gdImageCreateFromPng(org); if (im_org == NULL) { php_error_docref(NULL, E_WARNING, "Unable to open '%s' Not a valid PNG file", fn_dest); + fclose(org); + fclose(dest); RETURN_FALSE; } break; @@ -4106,10 +4113,14 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) default: php_error_docref(NULL, E_WARNING, "Format not supported"); + fclose(org); + fclose(dest); RETURN_FALSE; break; } + fclose(org); + org_width = gdImageSX (im_org); org_height = gdImageSY (im_org); @@ -4140,6 +4151,8 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) im_tmp = gdImageCreate (dest_width, dest_height); if (im_tmp == NULL ) { php_error_docref(NULL, E_WARNING, "Unable to allocate temporary buffer"); + fclose(dest); + gdImageDestroy(im_org); RETURN_FALSE; } @@ -4147,23 +4160,29 @@ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type ) gdImageDestroy(im_org); - fclose(org); - im_dest = gdImageCreate(dest_width, dest_height); if (im_dest == NULL) { php_error_docref(NULL, E_WARNING, "Unable to allocate destination buffer"); + fclose(dest); + gdImageDestroy(im_tmp); RETURN_FALSE; } white = gdImageColorAllocate(im_dest, 255, 255, 255); if (white == -1) { php_error_docref(NULL, E_WARNING, "Unable to allocate the colors for the destination buffer"); + fclose(dest); + gdImageDestroy(im_tmp); + gdImageDestroy(im_dest); RETURN_FALSE; } black = gdImageColorAllocate(im_dest, 0, 0, 0); if (black == -1) { php_error_docref(NULL, E_WARNING, "Unable to allocate the colors for the destination buffer"); + fclose(dest); + gdImageDestroy(im_tmp); + gdImageDestroy(im_dest); RETURN_FALSE; } diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c index 51258d484f4..928fdb89ca9 100644 --- a/ext/gd/libgd/gd.c +++ b/ext/gd/libgd/gd.c @@ -2245,7 +2245,9 @@ void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, for (y = 0; (y < h); y++) { for (x = 0; (x < w); x++) { int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y); - gdImageSetPixel (dst, dstX + x, dstY + y, c); + if (c != src->transparent) { + gdImageSetPixel (dst, dstX + x, dstY + y, c); + } } } } else { @@ -2262,26 +2264,6 @@ void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, return; } - /* Destination is palette based */ - if (src->trueColor) { /* But source is truecolor (Ouch!) */ - toy = dstY; - for (y = srcY; (y < (srcY + h)); y++) { - tox = dstX; - for (x = srcX; x < (srcX + w); x++) { - int nc; - c = gdImageGetPixel (src, x, y); - - /* Get best match possible. */ - nc = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c)); - - gdImageSetPixel(dst, tox, toy, nc); - tox++; - } - toy++; - } - return; - } - /* Palette based to palette based */ for (i = 0; i < gdMaxColors; i++) { colorMap[i] = (-1); diff --git a/ext/gd/tests/bug66005.phpt b/ext/gd/tests/bug66005.phpt new file mode 100644 index 00000000000..a01c5c32b85 --- /dev/null +++ b/ext/gd/tests/bug66005.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #66005 (imagecopy does not support 1bit transparency on truecolor images) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +9b36049de01006b367efd433f1689043 +==DONE== diff --git a/ext/gd/tests/bug72913.phpt b/ext/gd/tests/bug72913.phpt new file mode 100644 index 00000000000..0ad03a7d3c1 --- /dev/null +++ b/ext/gd/tests/bug72913.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #72913 (imagecopy() loses single-color transparency on palette images) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +f03c27f20710e21debd7090c660f1a1e +==DONE== diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index 0d44936ea63..ab51dd046a5 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -720,7 +720,6 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, default: /* other error */ - retval = PHP_ICONV_ERR_UNKNOWN; zend_string_free(out_buf); return PHP_ICONV_ERR_UNKNOWN; } @@ -858,7 +857,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval, } - if ((size_t)offset >= total_len) { + if ((size_t)offset > total_len) { return PHP_ICONV_ERR_SUCCESS; } @@ -2108,7 +2107,7 @@ PHP_FUNCTION(iconv_substr) err = _php_iconv_substr(&retval, ZSTR_VAL(str), ZSTR_LEN(str), offset, length, charset); _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset); - if (err == PHP_ICONV_ERR_SUCCESS && ZSTR_LEN(str) > 0 && retval.s != NULL) { + if (err == PHP_ICONV_ERR_SUCCESS && ZSTR_LEN(str) >= 0 && retval.s != NULL) { RETURN_NEW_STR(retval.s); } smart_str_free(&retval); diff --git a/ext/iconv/tests/bug72320.phpt b/ext/iconv/tests/bug72320.phpt new file mode 100644 index 00000000000..0c83d33db03 --- /dev/null +++ b/ext/iconv/tests/bug72320.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #72320 (iconv_substr returns false for empty strings) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(0) "" +string(0) "" diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c index 39d7fbb1cac..9416a7e34de 100644 --- a/ext/imap/php_imap.c +++ b/ext/imap/php_imap.c @@ -3962,7 +3962,7 @@ int _php_imap_mail(char *to, char *subject, char *message, char *headers, char * bt_len++; offset = 0; addr = NULL; - rfc822_parse_adrlist(&addr, tempMailTo, NULL); + rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST"); while (addr) { if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) { PHP_IMAP_BAD_DEST; @@ -3991,7 +3991,7 @@ int _php_imap_mail(char *to, char *subject, char *message, char *headers, char * bt_len++; offset = 0; addr = NULL; - rfc822_parse_adrlist(&addr, tempMailTo, NULL); + rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST"); while (addr) { if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) { PHP_IMAP_BAD_DEST; @@ -4017,7 +4017,7 @@ int _php_imap_mail(char *to, char *subject, char *message, char *headers, char * bt_len++; offset = 0; addr = NULL; - rfc822_parse_adrlist(&addr, tempMailTo, NULL); + rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST"); while (addr) { if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) { PHP_IMAP_BAD_DEST; diff --git a/ext/intl/grapheme/grapheme_util.c b/ext/intl/grapheme/grapheme_util.c index 042092ea596..d81060b5a1f 100644 --- a/ext/intl/grapheme/grapheme_util.c +++ b/ext/intl/grapheme/grapheme_util.c @@ -223,7 +223,7 @@ zend_long grapheme_ascii_check(const unsigned char *day, size_t len) { int ret_len = len; while ( len-- ) { - if ( *day++ > 0x7f ) + if ( *day++ > 0x7f || (*day == '\n' && *(day - 1) == '\r') ) return -1; } diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c index 959a4fd5a01..73fb5eeff66 100644 --- a/ext/intl/msgformat/msgformat_format.c +++ b/ext/intl/msgformat/msgformat_format.c @@ -50,11 +50,10 @@ static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *ret zend_hash_destroy(args_copy); efree(args_copy); - if (formatted && U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) { - efree(formatted); - } - if (U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) { + if (formatted) { + efree(formatted); + } RETURN_FALSE; } else { INTL_METHOD_RETVAL_UTF8(mfo, formatted, formatted_len, 1); diff --git a/ext/intl/tests/bug65732.phpt b/ext/intl/tests/bug65732.phpt new file mode 100644 index 00000000000..b49f884ee42 --- /dev/null +++ b/ext/intl/tests/bug65732.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #65732 (grapheme_*() is not Unicode compliant on CR LF sequence) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +int(1) +string(7) "ef +ghi" +int(2) +==DONE== diff --git a/ext/intl/tests/formatter_fail.phpt b/ext/intl/tests/formatter_fail.phpt index 72335e20220..dcc5cb24fa1 100644 --- a/ext/intl/tests/formatter_fail.phpt +++ b/ext/intl/tests/formatter_fail.phpt @@ -66,7 +66,7 @@ foreach($args as $arg) { ?> --EXPECTF-- -TypeError: NumberFormatter::__construct() expects at least 2 parameters, 0 given in %s on line %d +ArgumentCountError: NumberFormatter::__construct() expects at least 2 parameters, 0 given in %s on line %d 'numfmt_create: unable to parse input parameters: U_ILLEGAL_ARGUMENT_ERROR' Warning: numfmt_create() expects at least 2 parameters, 0 given in %s on line %d diff --git a/ext/intl/tests/msgfmt_fail2.phpt b/ext/intl/tests/msgfmt_fail2.phpt index 5dcd09ccc87..698d19afcef 100644 --- a/ext/intl/tests/msgfmt_fail2.phpt +++ b/ext/intl/tests/msgfmt_fail2.phpt @@ -79,7 +79,7 @@ foreach($args as $arg) { ?> --EXPECTF-- -TypeError: MessageFormatter::__construct() expects exactly 2 parameters, 0 given in %s on line %d +ArgumentCountError: MessageFormatter::__construct() expects exactly 2 parameters, 0 given in %s on line %d 'msgfmt_create: unable to parse input parameters: U_ILLEGAL_ARGUMENT_ERROR' Warning: msgfmt_create() expects exactly 2 parameters, 0 given in %s on line %d @@ -88,7 +88,7 @@ Warning: msgfmt_create() expects exactly 2 parameters, 0 given in %s on line %d Warning: MessageFormatter::create() expects exactly 2 parameters, 0 given in %s on line %d 'msgfmt_create: unable to parse input parameters: U_ILLEGAL_ARGUMENT_ERROR' -TypeError: MessageFormatter::__construct() expects exactly 2 parameters, 1 given in %s on line %d +ArgumentCountError: MessageFormatter::__construct() expects exactly 2 parameters, 1 given in %s on line %d 'msgfmt_create: unable to parse input parameters: U_ILLEGAL_ARGUMENT_ERROR' Warning: msgfmt_create() expects exactly 2 parameters, 1 given in %s on line %d diff --git a/ext/intl/uchar/uchar.c b/ext/intl/uchar/uchar.c index a7e5c173401..1e0041f03c6 100644 --- a/ext/intl/uchar/uchar.c +++ b/ext/intl/uchar/uchar.c @@ -566,8 +566,8 @@ IC_METHOD(getFC_NFKC_Closure) { error = U_ZERO_ERROR; u8str = intl_convert_utf16_to_utf8(closure, closure_len, &error); - efree(closure); INTL_CHECK_STATUS(error, "Failed converting output to UTF8"); + efree(closure); RETVAL_NEW_STR(u8str); } /* }}} */ diff --git a/ext/json/json.c b/ext/json/json.c index 2acfb5e79f9..3bbe532d975 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -186,9 +186,7 @@ static PHP_MINFO_FUNCTION(json) PHP_JSON_API int php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */ { - php_json_encode_zval(buf, val, options); - - return JSON_G(error_code) > 0 ? FAILURE : SUCCESS; + return php_json_encode_zval(buf, val, options); } /* }}} */ diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 7cf76732350..8fd2f23dffb 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -33,7 +33,7 @@ static const char digits[] = "0123456789abcdef"; -static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options); +static int php_json_escape_string(smart_str *buf, char *s, size_t len, int options); static int php_json_determine_array_type(zval *val) /* {{{ */ { @@ -108,7 +108,21 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options) } /* }}} */ -static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ */ +#define PHP_JSON_HASH_APPLY_PROTECTION_INC(_tmp_ht) \ + do { \ + if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(_tmp_ht)) { \ + ZEND_HASH_INC_APPLY_COUNT(_tmp_ht); \ + } \ + } while (0) + +#define PHP_JSON_HASH_APPLY_PROTECTION_DEC(_tmp_ht) \ + do { \ + if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(_tmp_ht)) { \ + ZEND_HASH_DEC_APPLY_COUNT(_tmp_ht); \ + } \ + } while (0) + +static int php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ */ { int i, r, need_comma = 0; HashTable *myht; @@ -124,7 +138,7 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; smart_str_appendl(buf, "null", 4); - return; + return FAILURE; } if (r == PHP_JSON_OUTPUT_ARRAY) { @@ -146,9 +160,7 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) { ZVAL_DEREF(data); tmp_ht = HASH_OF(data); - if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { - ZEND_HASH_INC_APPLY_COUNT(tmp_ht); - } + PHP_JSON_HASH_APPLY_PROTECTION_INC(tmp_ht); if (r == PHP_JSON_OUTPUT_ARRAY) { if (need_comma) { @@ -159,14 +171,11 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ php_json_pretty_print_char(buf, options, '\n'); php_json_pretty_print_indent(buf, options); - php_json_encode(buf, data, options); } else if (r == PHP_JSON_OUTPUT_OBJECT) { if (key) { if (ZSTR_VAL(key)[0] == '\0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) { /* Skip protected and private members. */ - if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { - ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); - } + PHP_JSON_HASH_APPLY_PROTECTION_DEC(tmp_ht); continue; } @@ -180,11 +189,6 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ php_json_pretty_print_indent(buf, options); php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key), options & ~PHP_JSON_NUMERIC_CHECK); - smart_str_appendc(buf, ':'); - - php_json_pretty_print_char(buf, options, ' '); - - php_json_encode(buf, data, options); } else { if (need_comma) { smart_str_appendc(buf, ','); @@ -198,22 +202,26 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ smart_str_appendc(buf, '"'); smart_str_append_long(buf, (zend_long) index); smart_str_appendc(buf, '"'); - smart_str_appendc(buf, ':'); - - php_json_pretty_print_char(buf, options, ' '); - - php_json_encode(buf, data, options); } + + smart_str_appendc(buf, ':'); + php_json_pretty_print_char(buf, options, ' '); } - if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { - ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); + if (php_json_encode(buf, data, options) == FAILURE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { + PHP_JSON_HASH_APPLY_PROTECTION_DEC(tmp_ht); + return FAILURE; } + + PHP_JSON_HASH_APPLY_PROTECTION_DEC(tmp_ht); } ZEND_HASH_FOREACH_END(); } if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) { JSON_G(error_code) = PHP_JSON_ERROR_DEPTH; + if (!(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { + return FAILURE; + } } --JSON_G(encoder_depth); @@ -228,6 +236,8 @@ static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ } else { smart_str_appendc(buf, '}'); } + + return SUCCESS; } /* }}} */ @@ -268,7 +278,7 @@ static int php_json_utf8_to_utf16(unsigned short *utf16, char utf8[], size_t len } /* }}} */ -static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options) /* {{{ */ +static int php_json_escape_string(smart_str *buf, char *s, size_t len, int options) /* {{{ */ { int status; unsigned int us; @@ -276,7 +286,7 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti if (len == 0) { smart_str_appendl(buf, "\"\"", 2); - return; + return SUCCESS; } if (options & PHP_JSON_NUMERIC_CHECK) { @@ -287,10 +297,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { if (type == IS_LONG) { smart_str_append_long(buf, p); - return; + return SUCCESS; } else if (type == IS_DOUBLE && php_json_is_valid_double(d)) { php_json_encode_double(buf, d, options); - return; + return SUCCESS; } } @@ -300,8 +310,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti /* validate UTF-8 string first */ if (php_json_utf8_to_utf16(NULL, s, len) < 0) { JSON_G(error_code) = PHP_JSON_ERROR_UTF8; - smart_str_appendl(buf, "null", 4); - return; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } } @@ -322,8 +334,10 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti ZSTR_LEN(buf->s) = checkpoint; } JSON_G(error_code) = PHP_JSON_ERROR_UTF8; - smart_str_appendl(buf, "null", 4); - return; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } /* Escape U+2028/U+2029 line terminators, UNLESS both JSON_UNESCAPED_UNICODE and @@ -442,10 +456,12 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti } while (pos < len); smart_str_appendc(buf, '"'); + + return SUCCESS; } /* }}} */ -static void php_json_encode_serializable_object(smart_str *buf, zval *val, int options) /* {{{ */ +static int php_json_encode_serializable_object(smart_str *buf, zval *val, int options) /* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(val); zval retval, fname; @@ -460,8 +476,10 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; - smart_str_appendl(buf, "null", 4); - return; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } @@ -470,9 +488,12 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o origin_error_code = JSON_G(error_code); if (FAILURE == call_user_function_ex(EG(function_table), val, &fname, &retval, 0, NULL, 1, NULL) || Z_TYPE(retval) == IS_UNDEF) { zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name)); - smart_str_appendl(buf, "null", sizeof("null") - 1); zval_ptr_dtor(&fname); - return; + + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } JSON_G(error_code) = origin_error_code; @@ -480,8 +501,11 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o /* Error already raised */ zval_ptr_dtor(&retval); zval_ptr_dtor(&fname); - smart_str_appendl(buf, "null", sizeof("null") - 1); - return; + + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } if ((Z_TYPE(retval) == IS_OBJECT) && @@ -495,10 +519,12 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o zval_ptr_dtor(&retval); zval_ptr_dtor(&fname); + + return SUCCESS; } /* }}} */ -void php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */ +int php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */ { again: switch (Z_TYPE_P(val)) @@ -528,18 +554,15 @@ again: break; case IS_STRING: - php_json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options); - break; + return php_json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options); case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce)) { - php_json_encode_serializable_object(buf, val, options); - break; + return php_json_encode_serializable_object(buf, val, options); } /* fallthrough -- Non-serializable object */ case IS_ARRAY: - php_json_encode_array(buf, val, options); - break; + return php_json_encode_array(buf, val, options); case IS_REFERENCE: val = Z_REFVAL_P(val); @@ -547,11 +570,13 @@ again: default: JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE; - smart_str_appendl(buf, "null", 4); - break; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } - return; + return SUCCESS; } /* }}} */ diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 045ca02f4ab..cedb8ae453a 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -22,7 +22,7 @@ #ifndef PHP_JSON_H #define PHP_JSON_H -#define PHP_JSON_VERSION "1.4.0" +#define PHP_JSON_VERSION "1.5.0" #include "zend_smart_str_public.h" extern zend_module_entry json_module_entry; diff --git a/ext/json/php_json_encoder.h b/ext/json/php_json_encoder.h index b10f7a614ad..0fec9174b53 100644 --- a/ext/json/php_json_encoder.h +++ b/ext/json/php_json_encoder.h @@ -22,6 +22,6 @@ #include "php.h" #include "zend_smart_str.h" -void php_json_encode_zval(smart_str *buf, zval *val, int options); +int php_json_encode_zval(smart_str *buf, zval *val, int options); #endif /* PHP_JSON_ENCODER_H */ diff --git a/ext/json/tests/bug68992.phpt b/ext/json/tests/bug68992.phpt new file mode 100644 index 00000000000..0fc41eca492 --- /dev/null +++ b/ext/json/tests/bug68992.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #68992 (json_encode stacks exceptions thrown by JsonSerializable classes) +--SKIPIF-- + +--FILE-- +getMessage(), $e->getCode(), get_class($e)); + } while ($e = $e->getPrevious()); +} +?> +--EXPECT-- +Failed calling MyClass::jsonSerialize() (0) [Exception] +Not implemented! (0) [Exception] diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 48a925cc1c2..0f82354ac9a 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -419,6 +419,7 @@ PHP_FUNCTION(ldap_connect) int urllen = hostlen + sizeof( "ldap://:65535" ); if (port <= 0 || port > 65535) { + efree(ld); php_error_docref(NULL, E_WARNING, "invalid port number: " ZEND_LONG_FMT, port); RETURN_FALSE; } diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index a44a9dade1c..1ddc5ffd02a 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -2934,6 +2934,13 @@ PHP_FUNCTION(mb_substr) RETURN_FALSE; } + if (from > INT_MAX) { + from = INT_MAX; + } + if (len > INT_MAX) { + len = INT_MAX; + } + ret = mbfl_substr(&string, &result, from, len); if (NULL == ret) { RETURN_FALSE; diff --git a/ext/mbstring/tests/bug66797.phpt b/ext/mbstring/tests/bug66797.phpt new file mode 100644 index 00000000000..df9e789be6c --- /dev/null +++ b/ext/mbstring/tests/bug66797.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #66797 (mb_substr only takes 32-bit signed integer) +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECTF-- +string(3) "bar" +string(3) "bar" +string(0) "" +string(0) "" +==DONE== diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 3bd86e60c0e..3490a73e038 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -91,6 +91,15 @@ static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b) zend_op *opcodes = op_array->opcodes; while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP) { + /* check if NOP breaks incorrect smart branch */ + if (b->len == 2 + && (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ + || op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ) + && (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST)) + && b->start > 0 + && zend_is_smart_branch(op_array->opcodes + b->start - 1)) { + break; + } b->start++; b->len--; } @@ -114,6 +123,14 @@ static void strip_nops(zend_op_array *op_array, zend_basic_block *b) } j++; } + if (i + 1 < b->start + b->len + && (op_array->opcodes[i+1].opcode == ZEND_JMPZ + || op_array->opcodes[i+1].opcode == ZEND_JMPNZ) + && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST) + && zend_is_smart_branch(op_array->opcodes + j - 1)) { + /* don't remove NOP, that splits incorrect smart branch */ + j++; + } i++; } b->len = j - b->start; diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a99d50fc417..63faaf62c38 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -149,20 +149,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) i + 1 < op_array->last && (op_array->opcodes[i+1].opcode == ZEND_JMPZ || op_array->opcodes[i+1].opcode == ZEND_JMPNZ) && - (op_array->opcodes[i-1].opcode == ZEND_IS_IDENTICAL || - op_array->opcodes[i-1].opcode == ZEND_IS_NOT_IDENTICAL || - op_array->opcodes[i-1].opcode == ZEND_IS_EQUAL || - op_array->opcodes[i-1].opcode == ZEND_IS_NOT_EQUAL || - op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER || - op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER_OR_EQUAL || - op_array->opcodes[i-1].opcode == ZEND_CASE || - op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_VAR || - op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_STATIC_PROP || - op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ || - op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ || - op_array->opcodes[i-1].opcode == ZEND_INSTANCEOF || - op_array->opcodes[i-1].opcode == ZEND_TYPE_CHECK || - op_array->opcodes[i-1].opcode == ZEND_DEFINED))) { + zend_is_smart_branch(op_array->opcodes + i - 1))) { if (i != target) { op_array->opcodes[target] = op_array->opcodes[i]; ssa->ops[target] = ssa->ops[i]; diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 335ad75827a..f39f9650aee 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -24,11 +24,12 @@ #include "zend_optimizer.h" #include "zend_optimizer_internal.h" -static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend_basic_block *b) /* {{{ */ +static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */ { zend_uchar opcode; zend_basic_block *b0; int successor_0, successor_1; + zend_basic_block *blocks = cfg->blocks; while (1) { b->flags |= ZEND_BB_REACHABLE; @@ -39,7 +40,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend b0 = blocks + successor_0; b0->flags |= ZEND_BB_TARGET; if (!(b0->flags & ZEND_BB_REACHABLE)) { - zend_mark_reachable(opcodes, blocks, b0); + zend_mark_reachable(opcodes, cfg, b0); } ZEND_ASSERT(b->len != 0); @@ -58,8 +59,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend } else { b->flags |= ZEND_BB_FOLLOW; - //TODO: support for stackless CFG??? - if (0/*stackless*/) { + if (cfg->split_at_calls) { if (opcode == ZEND_INCLUDE_OR_EVAL || opcode == ZEND_GENERATOR_CREATE || opcode == ZEND_YIELD || @@ -70,6 +70,12 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend b->flags |= ZEND_BB_ENTRY; } } + if (cfg->split_at_recv) { + if (opcode == ZEND_RECV || + opcode == ZEND_RECV_INIT) { + b->flags |= ZEND_BB_RECV_ENTRY; + } + } } } else { b = blocks + successor_0; @@ -89,7 +95,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * zend_basic_block *blocks = cfg->blocks; blocks[start].flags = ZEND_BB_START; - zend_mark_reachable(op_array->opcodes, blocks, blocks + start); + zend_mark_reachable(op_array->opcodes, cfg, blocks + start); if (op_array->last_live_range || op_array->last_try_catch) { zend_basic_block *b; @@ -109,6 +115,15 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * b = blocks + block_map[live_range->start]; if (b->flags & ZEND_BB_REACHABLE) { while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) { + /* check if NOP breaks incorrect smart branch */ + if (b->len == 2 + && (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ + || op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ) + && (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST)) + && b->start > 0 + && zend_is_smart_branch(op_array->opcodes + b->start - 1)) { + break; + } b->start++; b->len--; } @@ -123,7 +138,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * if (!(b->flags & ZEND_BB_REACHABLE)) { if (cfg->split_at_live_ranges) { changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + zend_mark_reachable(op_array->opcodes, cfg, b); } else { ZEND_ASSERT(!(b->flags & ZEND_BB_UNREACHABLE_FREE)); ZEND_ASSERT(b->start == live_range->end); @@ -161,7 +176,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * if (b->flags & ZEND_BB_REACHABLE) { op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op; changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, blocks + block_map[op_array->try_catch_array[j].try_op]); + zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]); break; } b++; @@ -178,7 +193,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * b->flags |= ZEND_BB_CATCH; if (!(b->flags & ZEND_BB_REACHABLE)) { changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + zend_mark_reachable(op_array->opcodes, cfg, b); } } if (op_array->try_catch_array[j].finally_op) { @@ -186,7 +201,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * b->flags |= ZEND_BB_FINALLY; if (!(b->flags & ZEND_BB_REACHABLE)) { changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + zend_mark_reachable(op_array->opcodes, cfg, b); } } if (op_array->try_catch_array[j].finally_end) { @@ -194,7 +209,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * b->flags |= ZEND_BB_FINALLY_END; if (!(b->flags & ZEND_BB_REACHABLE)) { changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + zend_mark_reachable(op_array->opcodes, cfg, b); } } } else { @@ -273,6 +288,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b zend_bool extra_entry_block = 0; cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0; + cfg->split_at_calls = (build_flags & ZEND_CFG_STACKLESS) != 0; + cfg->split_at_recv = (build_flags & ZEND_CFG_RECV_ENTRY) != 0 && (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0; + cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t)); if (!block_map) { return FAILURE; @@ -283,6 +301,12 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b for (i = 0; i < op_array->last; i++) { zend_op *opline = op_array->opcodes + i; switch(opline->opcode) { + case ZEND_RECV: + case ZEND_RECV_INIT: + if (build_flags & ZEND_CFG_RECV_ENTRY) { + BB_START(i + 1); + } + break; case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h index da908fdbe37..1ffb62add08 100644 --- a/ext/opcache/Optimizer/zend_cfg.h +++ b/ext/opcache/Optimizer/zend_cfg.h @@ -32,13 +32,14 @@ #define ZEND_BB_GEN_VAR (1<<9) /* start of live range */ #define ZEND_BB_KILL_VAR (1<<10) /* end of live range */ #define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */ +#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */ #define ZEND_BB_LOOP_HEADER (1<<16) #define ZEND_BB_IRREDUCIBLE_LOOP (1<<17) #define ZEND_BB_REACHABLE (1<<31) -#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR) +#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR) typedef struct _zend_basic_block { uint32_t flags; @@ -87,6 +88,8 @@ typedef struct _zend_cfg { int *predecessors; uint32_t *map; unsigned int split_at_live_ranges : 1; + unsigned int split_at_calls : 1; + unsigned int split_at_recv : 1; } zend_cfg; /* Build Flags */ @@ -97,6 +100,7 @@ typedef struct _zend_cfg { #define ZEND_SSA_RC_INFERENCE (1<<27) #define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26) #define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25) +#define ZEND_CFG_RECV_ENTRY (1<<24) #define CRT_CONSTANT_EX(op_array, node, rt_constants) \ ((rt_constants) ? \ diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index a611b55cd5b..ed9b6a59d98 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -669,7 +669,7 @@ static void zend_dump_block_info(const zend_cfg *cfg, int n, uint32_t dump_flags if (b->flags & ZEND_BB_EXIT) { fprintf(stderr, " exit"); } - if (b->flags & ZEND_BB_ENTRY) { + if (b->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) { fprintf(stderr, " entry"); } if (b->flags & ZEND_BB_TRY) { diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 174528f2e11..1e65a2577b7 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2350,7 +2350,7 @@ static inline zend_uchar get_compound_assign_op(zend_uchar opcode) { } static inline zend_class_entry *get_class_entry(const zend_script *script, zend_string *lcname) { - zend_class_entry *ce = zend_hash_find_ptr(&script->class_table, lcname); + zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL; if (ce) { return ce; } @@ -2943,7 +2943,7 @@ static void zend_update_type_info(const zend_op_array *op_array, case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_ops[i].result_def); - if ((ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT_EX(op_array, opline->op1, ssa->rt_constants)))) != NULL) { + if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT_EX(op_array, opline->op1, ssa->rt_constants)))) != NULL) { UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def); } break; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 113a1a5f836..3092b9635f3 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -947,12 +947,15 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]); if (func_info && func_info->ssa.var_info) { zend_redo_pass_two_ex(call_graph.op_arrays[i], &func_info->ssa); - ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL); } else { zend_redo_pass_two(call_graph.op_arrays[i]); } } + for (i = 0; i < call_graph.op_arrays_count; i++) { + ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL); + } + zend_arena_release(&ctx.arena, checkpoint); } else #endif diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 3d09c7e5af5..b61a8dafa7e 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -501,7 +501,7 @@ static void place_essa_pis( (opline-1)->op2_type == IS_CONST) { int var = EX_VAR_TO_NUM((opline-1)->op1.var); zend_string *lcname = Z_STR_P(CRT_CONSTANT((opline-1)->op2) + 1); - zend_class_entry *ce = zend_hash_find_ptr(&script->class_table, lcname); + zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL; if (!ce) { ce = zend_hash_find_ptr(CG(class_table), lcname); if (!ce || ce->type != ZEND_INTERNAL_CLASS) { diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c index 3b08db6959e..cdfd90c14b8 100644 --- a/ext/opcache/shared_alloc_win32.c +++ b/ext/opcache/shared_alloc_win32.c @@ -186,7 +186,7 @@ static int zend_shared_alloc_reattach(size_t requested_size, char **error_in) } #endif err = ERROR_INVALID_ADDRESS; - zend_win_error_message(ACCEL_LOG_FATAL, "Base address marks unusable memory region. Please setup opcache.file_cache and opcache.file_cache_callback directives for more convenient Opcache usage", err); + zend_win_error_message(ACCEL_LOG_FATAL, "Base address marks unusable memory region. Please setup opcache.file_cache and opcache.file_cache_fallback directives for more convenient Opcache usage", err); return ALLOC_FAILURE; } diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c index df6abe8519e..db61e1e9d39 100644 --- a/ext/opcache/zend_accelerator_blacklist.c +++ b/ext/opcache/zend_accelerator_blacklist.c @@ -178,7 +178,9 @@ static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist) it->next = NULL; if ((it->re = pcre_compile(regexp, PCRE_NO_AUTO_CAPTURE, &pcre_error, &pcre_error_offset, 0)) == NULL) { + free(it); blacklist_report_regexp_error(pcre_error, pcre_error_offset); + return; } /* prepare for the next iteration */ p = regexp + 2; diff --git a/ext/openssl/tests/openssl_error_string_basic.phpt b/ext/openssl/tests/openssl_error_string_basic.phpt index 23401e542bc..04cc5508a4a 100644 --- a/ext/openssl/tests/openssl_error_string_basic.phpt +++ b/ext/openssl/tests/openssl_error_string_basic.phpt @@ -105,7 +105,7 @@ expect_openssl_errors('openssl_private_decrypt', ['04065072']); // public encrypt and decrypt with failed padding check and padding @openssl_public_encrypt("data", $crypted, $public_key_file, 1000); @openssl_public_decrypt("data", $crypted, $public_key_file); -expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0906D06C', '04068076', '0407006A', '04067072']); +expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0906D06C', '04068076', '04067072']); // X509 echo "X509 errors\n"; diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 4ba5b297729..e10da07ea8f 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1176,6 +1176,11 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su if (UNEXPECTED(pce->name_count > 0)) { subpat_names = make_subpats_table(num_subpats, pce); if (!subpat_names) { + if (size_offsets <= 32) { + free_alloca(offsets, use_heap); + } else { + efree(offsets); + } return NULL; } } diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index d071027e59d..0a55cc4ff74 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -280,16 +280,28 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) switch(attr) { case PDO_ATTR_TIMEOUT: return 0; + + case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: + ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier = zval_get_long(val); + return 1; + default: return 1; } - } static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) { - /* dblib_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */ - return 0; + switch (attr) { + case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: + ZVAL_BOOL(return_value, ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier); + break; + + default: + return 0; + } + + return 1; } static struct pdo_dbh_methods dblib_methods = { @@ -347,6 +359,15 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars); + H = pecalloc(1, sizeof(*H), dbh->is_persistent); + H->login = dblogin(); + H->err.sqlstate = dbh->error_code; + H->stringify_uniqueidentifier = 0; + + if (!H->login) { + goto cleanup; + } + if (driver_options) { int connect_timeout = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_CONNECTION_TIMEOUT, -1); int query_timeout = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_QUERY_TIMEOUT, -1); @@ -361,14 +382,8 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) dbsetlogintime(connect_timeout); /* Connection/Login Timeout */ dbsettime(query_timeout); /* Statement Timeout */ - } - H = pecalloc(1, sizeof(*H), dbh->is_persistent); - H->login = dblogin(); - H->err.sqlstate = dbh->error_code; - - if (!H->login) { - goto cleanup; + H->stringify_uniqueidentifier = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, 0); } DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler); diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index a1055434d37..8ec4f782fd8 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -120,7 +120,7 @@ static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt) dbcancel(H->link); pdo_dblib_err_dtor(&H->err); - + return 1; } @@ -213,7 +213,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) pdo_dblib_db_handle *H = S->H; struct pdo_column_data *col; char *fname; - + if(colno >= stmt->column_count || colno < 0) { return FAILURE; } @@ -376,16 +376,28 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, break; } + #ifdef SQLUNIQUE case SQLUNIQUE: { #else case 36: { /* FreeTDS hack */ #endif - zv = emalloc(sizeof(zval)); - ZVAL_STRINGL(zv, data, 16); /* uniqueidentifier is a 16-byte binary number */ + if (H->stringify_uniqueidentifier) { // 36-char hex string representation + tmp_data_len = 36; + tmp_data = safe_emalloc(tmp_data_len, sizeof(char), 1); + data_len = (unsigned int) dbconvert(NULL, SQLUNIQUE, (BYTE*)data, data_len, SQLCHAR, (BYTE*)tmp_data, tmp_data_len); + php_strtoupper(tmp_data, data_len); + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, tmp_data, data_len); + efree(tmp_data); + } else { // a 16-byte binary representation + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, data, 16); + } break; } + default: { if (dbwillconvert(coltype, SQLCHAR)) { tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ @@ -479,4 +491,3 @@ struct pdo_stmt_methods dblib_stmt_methods = { pdo_dblib_stmt_next_rowset, /* nextrow */ pdo_dblib_stmt_cursor_closer }; - diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c index dd64cbe882c..f1016de1251 100644 --- a/ext/pdo_dblib/pdo_dblib.c +++ b/ext/pdo_dblib/pdo_dblib.c @@ -173,6 +173,7 @@ PHP_MINIT_FUNCTION(pdo_dblib) { REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_CONNECTION_TIMEOUT", (long) PDO_DBLIB_ATTR_CONNECTION_TIMEOUT); REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_QUERY_TIMEOUT", (long) PDO_DBLIB_ATTR_QUERY_TIMEOUT); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER", (long) PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER); if (FAIL == dbinit()) { return FAILURE; diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h index 01586881d55..87a0038ef4c 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -113,6 +113,7 @@ typedef struct { DBPROCESS *link; pdo_dblib_err err; + unsigned stringify_uniqueidentifier:1; } pdo_dblib_db_handle; typedef struct { @@ -142,7 +143,8 @@ ZEND_EXTERN_MODULE_GLOBALS(dblib) enum { PDO_DBLIB_ATTR_CONNECTION_TIMEOUT = PDO_ATTR_DRIVER_SPECIFIC, - PDO_DBLIB_ATTR_QUERY_TIMEOUT + PDO_DBLIB_ATTR_QUERY_TIMEOUT, + PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, }; #endif diff --git a/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt b/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt new file mode 100644 index 00000000000..79847bf2a19 --- /dev/null +++ b/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt @@ -0,0 +1,67 @@ +--TEST-- +PDO_DBLIB: Uniqueidentifier column data type stringifying +--SKIPIF-- + +--FILE-- +setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, true); +var_dump(true === $db->getAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER)); +$db->setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, false); +var_dump(false === $db->getAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER)); + + +//-------------------------------------------------------------------------------- +// 2. Binary +//-------------------------------------------------------------------------------- +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['guid'] === $testGUIDBinary); + + +//-------------------------------------------------------------------------------- +// 3. PDO::ATTR_STRINGIFY_FETCHES must not affect `uniqueidentifier` representation +//-------------------------------------------------------------------------------- +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); + +var_dump($row['guid'] === $testGUIDBinary); + + +//-------------------------------------------------------------------------------- +// 4. Stringifying +// ! With TDS protocol version <7.0 binary will be returned and the test will fail ! +// TODO: something from PDO::ATTR_SERVER_VERSION, PDO::ATTR_CLIENT_VERSION or PDO::ATTR_SERVER_INFO should be used +// to get TDS version and skip this test in this case. +//-------------------------------------------------------------------------------- +$db->setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, true); +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['guid'] === $testGUID); +var_dump($row['guid']); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +string(36) "82A88958-672B-4C22-842F-216E2B88E72A" diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index 871929bcc26..d44b3be2988 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -199,7 +199,6 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest) /* {{{ */ zend_hash_internal_pointer_reset(manifest); while (FAILURE != zend_hash_has_more_elements(manifest)) { - keylen = 0; if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(manifest, &str_key, &unused)) { break; } diff --git a/ext/phar/tests/cache_list/files/frontcontroller17.phar b/ext/phar/tests/cache_list/files/frontcontroller17.phar index b83d41fd5b8..d9b8330e63f 100644 Binary files a/ext/phar/tests/cache_list/files/frontcontroller17.phar and b/ext/phar/tests/cache_list/files/frontcontroller17.phar differ diff --git a/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc b/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc index 85b8729f31c..715479552a2 100644 --- a/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc +++ b/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc @@ -6,7 +6,7 @@ echo "hi"; '; $a->setStub('getMessage() . "\n"); } diff --git a/ext/phar/tests/cache_list/frontcontroller32.phpt b/ext/phar/tests/cache_list/frontcontroller32.phpt index 59116907a59..cb9abb8c198 100644 --- a/ext/phar/tests/cache_list/frontcontroller32.phpt +++ b/ext/phar/tests/cache_list/frontcontroller32.phpt @@ -13,4 +13,4 @@ Content-type: text/html; charset=UTF-8 --FILE_EXTERNAL-- files/frontcontroller17.phar --EXPECTF-- -%ahar error: failed to call rewrite callback \ No newline at end of file +%ahar error: rewrite callback must return a string or false diff --git a/ext/phar/tests/files/frontcontroller17.phar b/ext/phar/tests/files/frontcontroller17.phar index b83d41fd5b8..4dab78a9ec0 100644 Binary files a/ext/phar/tests/files/frontcontroller17.phar and b/ext/phar/tests/files/frontcontroller17.phar differ diff --git a/ext/phar/tests/files/frontcontroller17.phar.inc b/ext/phar/tests/files/frontcontroller17.phar.inc index 85b8729f31c..715479552a2 100644 --- a/ext/phar/tests/files/frontcontroller17.phar.inc +++ b/ext/phar/tests/files/frontcontroller17.phar.inc @@ -6,7 +6,7 @@ echo "hi"; '; $a->setStub('getMessage() . "\n"); } diff --git a/ext/phar/tests/frontcontroller32.phpt b/ext/phar/tests/frontcontroller32.phpt index 58f6fffa00a..032d0f571d2 100644 --- a/ext/phar/tests/frontcontroller32.phpt +++ b/ext/phar/tests/frontcontroller32.phpt @@ -12,4 +12,4 @@ Content-type: text/html; charset=UTF-8 --FILE_EXTERNAL-- files/frontcontroller17.phar --EXPECTF-- -%ahar error: failed to call rewrite callback \ No newline at end of file +%ahar error: rewrite callback must return a string or false diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 82d76457da7..cf861b65d81 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3038,8 +3038,9 @@ ZEND_METHOD(reflection_type, __toString) str = reflection_type_name(param); if (param->arg_info->allow_null) { - str = zend_string_extend(str, ZSTR_LEN(str) + 1, 0); - memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), ZSTR_LEN(str) + 1); + size_t orig_len = ZSTR_LEN(str); + str = zend_string_extend(str, orig_len + 1, 0); + memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), orig_len + 1); ZSTR_VAL(str)[0] = '?'; } diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt index c9d1e6379a9..eec5a3e618e 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt @@ -25,7 +25,7 @@ var_dump($methodWithArgs->invokeArgs($testClassInstance, array())); --EXPECTF-- Method with args: -Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invokeArgs_error1.php:5 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invokeArgs_error1.php:5 Stack trace: #0 [internal function]: TestClass->methodWithArgs() #1 %sReflectionMethod_invokeArgs_error1.php(19): ReflectionMethod->invokeArgs(Object(TestClass), Array) diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt index 60a9ebae974..5dba208bebc 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt @@ -21,7 +21,7 @@ var_dump($methodWithArgs->invoke($testClassInstance)); --EXPECTF-- Method with args: -Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invoke_error2.php:5 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invoke_error2.php:5 Stack trace: #0 [internal function]: TestClass->methodWithArgs() #1 %sReflectionMethod_invoke_error2.php(15): ReflectionMethod->invoke(Object(TestClass)) diff --git a/ext/reflection/tests/ReflectionType_001.phpt b/ext/reflection/tests/ReflectionType_001.phpt index a3175668876..ee2ebb64dd6 100644 --- a/ext/reflection/tests/ReflectionType_001.phpt +++ b/ext/reflection/tests/ReflectionType_001.phpt @@ -73,6 +73,8 @@ foreach ([ var_dump((string)$ra); } } + +?> --EXPECT-- *** functions ** Function 0 - Parameter 0 diff --git a/ext/reflection/tests/bug42976.phpt b/ext/reflection/tests/bug42976.phpt index 2e4ade28476..21aff8d4cca 100644 --- a/ext/reflection/tests/bug42976.phpt +++ b/ext/reflection/tests/bug42976.phpt @@ -27,12 +27,8 @@ echo "Done\n"; string(9) "x.changed" Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 15 - -Warning: ReflectionClass::newInstance(): Invocation of C's constructor failed in %sbug42976.php on line 15 string(10) "x.original" Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 18 - -Warning: ReflectionClass::newInstanceArgs(): Invocation of C's constructor failed in %sbug42976.php on line 18 string(10) "x.original" Done diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index 7cb99fabcc7..24f70b6c4b7 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -643,9 +643,11 @@ PS_GC_FUNC(files) if (data->dirdepth == 0) { *nrdels = ps_files_cleanup_dir(data->basedir, maxlifetime); + } else { + *nrdels = -1; // Cannot process multiple depth save dir } - return SUCCESS; + return *nrdels; } diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c index 3f698975562..3181e1641cc 100644 --- a/ext/session/mod_mm.c +++ b/ext/session/mod_mm.c @@ -468,7 +468,7 @@ PS_GC_FUNC(mm) mm_unlock(data->mm); - return SUCCESS; + return nrdels; } PS_CREATE_SID_FUNC(mm) diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index beddce88835..0cdbaf96f9d 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -176,13 +176,22 @@ PS_DESTROY_FUNC(user) PS_GC_FUNC(user) { zval args[1]; - STDVARS; + zval retval; ZVAL_LONG(&args[0], maxlifetime); ps_call_handler(&PSF(gc), 1, args, &retval); - FINISH; + if (Z_TYPE(retval) == IS_LONG) { + convert_to_long(&retval); + return Z_LVAL(retval); + } + /* This is for older API compatibility */ + if (Z_TYPE(retval) == IS_TRUE) { + return 1; + } + /* Anything else is some kind of error */ + return -1; // Error } PS_CREATE_SID_FUNC(user) diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c index a774d4bf9c2..b132552fafa 100644 --- a/ext/session/mod_user_class.c +++ b/ext/session/mod_user_class.c @@ -148,7 +148,7 @@ PHP_METHOD(SessionHandler, destroy) PHP_METHOD(SessionHandler, gc) { zend_long maxlifetime; - int nrdels; + zend_long nrdels = -1; PS_SANITY_CHECK_IS_OPEN; @@ -156,7 +156,10 @@ PHP_METHOD(SessionHandler, gc) return; } - RETURN_BOOL(SUCCESS == PS(default_mod)->s_gc(&PS(mod_data), maxlifetime, &nrdels)); + if (PS(default_mod)->s_gc(&PS(mod_data), maxlifetime, &nrdels) == FAILURE) { + RETURN_FALSE; + } + RETURN_LONG(nrdels); } /* }}} */ diff --git a/ext/session/php_session.h b/ext/session/php_session.h index b693fd4b87a..da5e48515a4 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -39,7 +39,7 @@ #define PS_READ_ARGS void **mod_data, zend_string *key, zend_string **val, zend_long maxlifetime #define PS_WRITE_ARGS void **mod_data, zend_string *key, zend_string *val, zend_long maxlifetime #define PS_DESTROY_ARGS void **mod_data, zend_string *key -#define PS_GC_ARGS void **mod_data, zend_long maxlifetime, int *nrdels +#define PS_GC_ARGS void **mod_data, zend_long maxlifetime, zend_long *nrdels #define PS_CREATE_SID_ARGS void **mod_data #define PS_VALIDATE_SID_ARGS void **mod_data, zend_string *key #define PS_UPDATE_TIMESTAMP_ARGS void **mod_data, zend_string *key, zend_string *val, zend_long maxlifetime @@ -51,7 +51,7 @@ typedef struct ps_module_struct { int (*s_read)(PS_READ_ARGS); int (*s_write)(PS_WRITE_ARGS); int (*s_destroy)(PS_DESTROY_ARGS); - int (*s_gc)(PS_GC_ARGS); + zend_long (*s_gc)(PS_GC_ARGS); zend_string *(*s_create_sid)(PS_CREATE_SID_ARGS); int (*s_validate_sid)(PS_VALIDATE_SID_ARGS); int (*s_update_timestamp)(PS_UPDATE_TIMESTAMP_ARGS); @@ -65,7 +65,7 @@ typedef struct ps_module_struct { #define PS_READ_FUNC(x) int ps_read_##x(PS_READ_ARGS) #define PS_WRITE_FUNC(x) int ps_write_##x(PS_WRITE_ARGS) #define PS_DESTROY_FUNC(x) int ps_delete_##x(PS_DESTROY_ARGS) -#define PS_GC_FUNC(x) int ps_gc_##x(PS_GC_ARGS) +#define PS_GC_FUNC(x) zend_long ps_gc_##x(PS_GC_ARGS) #define PS_CREATE_SID_FUNC(x) zend_string *ps_create_sid_##x(PS_CREATE_SID_ARGS) #define PS_VALIDATE_SID_FUNC(x) int ps_validate_sid_##x(PS_VALIDATE_SID_ARGS) #define PS_UPDATE_TIMESTAMP_FUNC(x) int ps_update_timestamp_##x(PS_UPDATE_TIMESTAMP_ARGS) diff --git a/ext/session/session.c b/ext/session/session.c index 9024de623f1..235e36b1837 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -353,19 +353,23 @@ PHPAPI int php_session_valid_key(const char *key) /* {{{ */ /* }}} */ -static void php_session_gc(void) /* {{{ */ +static zend_long php_session_gc(zend_bool immediate) /* {{{ */ { int nrand; + zend_long num = -1; /* GC must be done before reading session data. */ - if ((PS(mod_data) || PS(mod_user_implemented)) && PS(gc_probability) > 0) { - int nrdels = -1; - - nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg()); - if (nrand < PS(gc_probability)) { - PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels); + if ((PS(mod_data) || PS(mod_user_implemented))) { + if (immediate) { + PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num); + return num; + } + nrand = (zend_long) ((float) PS(gc_divisor) * php_combined_lcg()); + if (PS(gc_probability) > 0 && nrand < PS(gc_probability)) { + PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num); } } + return num; } /* }}} */ static void php_session_initialize(void) /* {{{ */ @@ -430,7 +434,7 @@ static void php_session_initialize(void) /* {{{ */ } /* GC must be done after read */ - php_session_gc(); + php_session_gc(0); if (PS(session_vars)) { zend_string_release(PS(session_vars)); @@ -1476,52 +1480,50 @@ PHPAPI void php_session_start(void) /* {{{ */ if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) { ppid2sid(ppid); PS(send_cookie) = 0; + PS(define_sid) = 0; } } - - if (PS(define_sid) && !PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_GET", sizeof("_GET") - 1))) { - ZVAL_DEREF(data); - if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) { - ppid2sid(ppid); + /* Initilize session ID from non cookie values */ + if (!PS(use_only_cookies)) { + if (!PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_GET", sizeof("_GET") - 1))) { + ZVAL_DEREF(data); + if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) { + ppid2sid(ppid); + } } - } - - if (PS(define_sid) && !PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_POST", sizeof("_POST") - 1))) { - ZVAL_DEREF(data); - if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) { - ppid2sid(ppid); + if (!PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_POST", sizeof("_POST") - 1))) { + ZVAL_DEREF(data); + if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) { + ppid2sid(ppid); + } } - } - - /* Check the REQUEST_URI symbol for a string of the form - * '=' to allow URLs of the form - * http://yoursite/=/script.php */ - if (PS(define_sid) && !PS(id) && - zend_is_auto_global_str("_SERVER", sizeof("_SERVER") - 1) == SUCCESS && - (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1)) && - Z_TYPE_P(data) == IS_STRING && - (p = strstr(Z_STRVAL_P(data), PS(session_name))) && - p[lensess] == '=' - ) { - char *q; - p += lensess + 1; - if ((q = strpbrk(p, "/?\\"))) { - PS(id) = zend_string_init(p, q - p, 0); + /* Check the REQUEST_URI symbol for a string of the form + * '=' to allow URLs of the form + * http://yoursite/=/script.php */ + if (!PS(id) && zend_is_auto_global_str("_SERVER", sizeof("_SERVER") - 1) == SUCCESS && + (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1)) && + Z_TYPE_P(data) == IS_STRING && + (p = strstr(Z_STRVAL_P(data), PS(session_name))) && + p[lensess] == '=' + ) { + char *q; + p += lensess + 1; + if ((q = strpbrk(p, "/?\\"))) { + PS(id) = zend_string_init(p, q - p, 0); + } + } + /* Check whether the current request was referred to by + * an external site which invalidates the previously found id. */ + if (PS(id) && PS(extern_referer_chk)[0] != '\0' && + !Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER]) && + (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER") - 1)) && + Z_TYPE_P(data) == IS_STRING && + Z_STRLEN_P(data) != 0 && + strstr(Z_STRVAL_P(data), PS(extern_referer_chk)) == NULL + ) { + zend_string_release(PS(id)); + PS(id) = NULL; } - } - - /* Check whether the current request was referred to by - * an external site which invalidates the previously found id. */ - if (PS(define_sid) && PS(id) && - PS(extern_referer_chk)[0] != '\0' && - !Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER]) && - (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER") - 1)) && - Z_TYPE_P(data) == IS_STRING && - Z_STRLEN_P(data) != 0 && - strstr(Z_STRVAL_P(data), PS(extern_referer_chk)) == NULL - ) { - zend_string_release(PS(id)); - PS(id) = NULL; } } @@ -2016,7 +2018,6 @@ static PHP_FUNCTION(session_regenerate_id) /* {{{ proto void session_create_id([string prefix]) Generate new session ID. Intended for user save handlers. */ -#if 0 /* This is not used yet */ static PHP_FUNCTION(session_create_id) { @@ -2038,7 +2039,20 @@ static PHP_FUNCTION(session_create_id) } if (PS(session_status) == php_session_active) { - new_id = PS(mod)->s_create_sid(&PS(mod_data)); + int limit = 3; + while (limit--) { + new_id = PS(mod)->s_create_sid(&PS(mod_data)); + if (!PS(mod)->s_validate_sid) { + break; + } else { + /* Detect collision and retry */ + if (PS(mod)->s_validate_sid(&PS(mod_data), new_id) == FAILURE) { + zend_string_release(new_id); + continue; + } + break; + } + } } else { new_id = php_session_create_id(NULL); } @@ -2053,9 +2067,7 @@ static PHP_FUNCTION(session_create_id) } smart_str_0(&id); RETVAL_NEW_STR(id.s); - smart_str_free(&id); } -#endif /* }}} */ /* {{{ proto string session_cache_limiter([string new_cache_limiter]) @@ -2239,6 +2251,32 @@ static PHP_FUNCTION(session_unset) } /* }}} */ +/* {{{ proto int session_gc(void) + Perform GC and return number of deleted sessions */ +static PHP_FUNCTION(session_gc) +{ + zend_long num; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (PS(session_status) != php_session_active) { + php_error_docref(NULL, E_WARNING, "Session is not active"); + RETURN_FALSE; + } + + num = php_session_gc(1); + if (num < 0) { + php_error_docref(NULL, E_WARNING, "Failed to perfom session GC"); + RETURN_FALSE; + } + + RETURN_LONG(num); +} +/* }}} */ + + /* {{{ proto void session_write_close(void) Write session data and end session */ static PHP_FUNCTION(session_write_close) @@ -2326,6 +2364,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_session_id, 0, 0, 0) ZEND_ARG_INFO(0, id) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_session_create_id, 0, 0, 0) + ZEND_ARG_INFO(0, prefix) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_session_regenerate_id, 0, 0, 0) ZEND_ARG_INFO(0, delete_old_session) ZEND_END_ARG_INFO() @@ -2410,12 +2452,14 @@ static const zend_function_entry session_functions[] = { PHP_FE(session_module_name, arginfo_session_module_name) PHP_FE(session_save_path, arginfo_session_save_path) PHP_FE(session_id, arginfo_session_id) + PHP_FE(session_create_id, arginfo_session_create_id) PHP_FE(session_regenerate_id, arginfo_session_regenerate_id) PHP_FE(session_decode, arginfo_session_decode) PHP_FE(session_encode, arginfo_session_void) PHP_FE(session_start, arginfo_session_void) PHP_FE(session_destroy, arginfo_session_void) PHP_FE(session_unset, arginfo_session_void) + PHP_FE(session_gc, arginfo_session_void) PHP_FE(session_set_save_handler, arginfo_session_set_save_handler) PHP_FE(session_cache_limiter, arginfo_session_cache_limiter) PHP_FE(session_cache_expire, arginfo_session_cache_expire) diff --git a/ext/session/tests/bug72940.phpt b/ext/session/tests/bug72940.phpt new file mode 100644 index 00000000000..5f3c7904052 --- /dev/null +++ b/ext/session/tests/bug72940.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72940 - SID always defined +--INI-- +error_reporting=-1 +session.save_path= +session.name=PHPSESSID +--SKIPIF-- + +--COOKIE-- +PHPSESSID=bug72940test +--GET-- +PHPSESSID=bug72940get +--FILE-- + +--EXPECTF-- +string(12) "bug72940test" +string(0) "" +string(11) "bug72940get" +string(21) "PHPSESSID=bug72940get" diff --git a/ext/session/tests/session_create_id_basic.phpt b/ext/session/tests/session_create_id_basic.phpt new file mode 100644 index 00000000000..490128ee9ce --- /dev/null +++ b/ext/session/tests/session_create_id_basic.phpt @@ -0,0 +1,57 @@ +--TEST-- +Test session_create_id() function : basic functionality +--INI-- +session.save_handler=files +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +*** Testing session_create_id() : basic functionality *** +string(32) "%s" +string(36) "ABCD%s" +string(35) "XYZ%s" +string(0) "" +string(32) "%s" +bool(false) +string(35) "XYZ%s" +string(0) "" +string(35) "XYZ%s" +bool(true) +Done diff --git a/ext/session/tests/session_gc_basic.phpt b/ext/session/tests/session_gc_basic.phpt new file mode 100644 index 00000000000..86e9156ce6f --- /dev/null +++ b/ext/session/tests/session_gc_basic.phpt @@ -0,0 +1,40 @@ +--TEST-- +Test session_gc() function : basic functionality +--SKIPIF-- + +--FILE-- += -1); +var_dump(session_destroy()); +var_dump(session_id()); + +echo "Done"; +ob_end_flush(); +?> +--EXPECTF-- +*** Testing session_gc() : basic functionality *** + +Warning: session_gc(): Session is not active in %s on line %d +bool(false) +bool(true) +int(%d) +bool(true) +bool(true) +string(0) "" +Done + + diff --git a/ext/session/tests/session_id_basic2.phpt b/ext/session/tests/session_id_basic2.phpt index 4421a539102..fd26c0e9ed8 100644 --- a/ext/session/tests/session_id_basic2.phpt +++ b/ext/session/tests/session_id_basic2.phpt @@ -16,7 +16,7 @@ ob_start(); echo "*** Testing session_id() : basic functionality ***\n"; ini_set('session.sid_bits_per_chracter', 6); -ini_set('session.sid_length', 240); +ini_set('session.sid_length', 120); session_start(); var_dump(session_id()); session_commit(); @@ -32,7 +32,7 @@ echo "Done"; ?> --EXPECTF-- *** Testing session_id() : basic functionality *** -string(240) "%s" +string(120) "%s" string(22) "%s" Done diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 622ff3b6ec6..fdda30451d6 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -356,7 +356,10 @@ long_dim: _node_as_zval(sxe, node, rv, newtype, name, sxe->iter.nsprefix, sxe->iter.isprefix); } #else - _node_as_zval(sxe, node, rv, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix); + /* In BP_VAR_IS mode only return a proper node if it actually exists. */ + if (type != BP_VAR_IS || sxe_find_element_by_name(sxe, node->children, (xmlChar *) name)) { + _node_as_zval(sxe, node, rv, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix); + } #endif } } @@ -610,7 +613,7 @@ long_dim: while (node) { SKIP_TEXT(node); - if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { + if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { newnode = node; ++counter; } @@ -803,17 +806,8 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend node = php_sxe_get_first_node(sxe, node); } node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); - } - else { - node = node->children; - while (node) { - xmlNodePtr nnext; - nnext = node->next; - if ((node->type == XML_ELEMENT_NODE) && !xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { - break; - } - node = nnext; - } + } else { + node = sxe_find_element_by_name(sxe, node->children, (xmlChar *)Z_STRVAL_P(member)); } if (node) { exists = 1; @@ -939,7 +933,7 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, SKIP_TEXT(node); - if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { + if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { xmlUnlinkNode(node); php_libxml_node_free_resource(node); } diff --git a/ext/simplexml/tests/bug72957.phpt b/ext/simplexml/tests/bug72957.phpt new file mode 100644 index 00000000000..29ca69fa761 --- /dev/null +++ b/ext/simplexml/tests/bug72957.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #72957: Null coalescing operator doesn't behave as expected with SimpleXMLElement +--SKIPIF-- + +--FILE-- +Text'); + +echo 'elem2 is: ' . ($xml->elem2 ?? 'backup string') . "\n"; +echo 'elem2 is: ' . (isset($xml->elem2) ? $xml->elem2 : 'backup string') . "\n"; + +?> +--EXPECT-- +elem2 is: backup string +elem2 is: backup string diff --git a/ext/simplexml/tests/bug72971.phpt b/ext/simplexml/tests/bug72971.phpt new file mode 100644 index 00000000000..ff7ded02efa --- /dev/null +++ b/ext/simplexml/tests/bug72971.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #72971: SimpleXML isset/unset do not respect namespace +--SKIPIF-- + +--FILE-- +barns:barns:bar2'); +var_dump(isset($xml->foo2)); +unset($xml->foo); +var_dump($xml->children('ns')); + +?> +--EXPECT-- +bool(false) +object(SimpleXMLElement)#2 (2) { + ["foo"]=> + string(6) "ns:bar" + ["foo2"]=> + string(7) "ns:bar2" +} diff --git a/ext/simplexml/tests/bug72971_2.phpt b/ext/simplexml/tests/bug72971_2.phpt new file mode 100644 index 00000000000..aa6e09438c5 --- /dev/null +++ b/ext/simplexml/tests/bug72971_2.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72971 (2): SimpleXML property write does not respect namespace +--SKIPIF-- + +--FILE-- +barns:bar'); + +$xml->foo = 'new-bar'; +var_dump($xml->foo); +var_dump($xml->children('ns')->foo); + +$xml->children('ns')->foo = 'ns:new-bar'; +var_dump($xml->foo); +var_dump($xml->children('ns')->foo); + +?> +--EXPECT-- +object(SimpleXMLElement)#2 (1) { + [0]=> + string(7) "new-bar" +} +object(SimpleXMLElement)#3 (1) { + [0]=> + string(6) "ns:bar" +} +object(SimpleXMLElement)#3 (1) { + [0]=> + string(7) "new-bar" +} +object(SimpleXMLElement)#2 (1) { + [0]=> + string(10) "ns:new-bar" +} diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 7f80b58bd5d..a8f28fbf1ec 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -1958,7 +1958,7 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo xmlNodePtr property; ZEND_HASH_FOREACH_STR_KEY_VAL_IND(prop, str_key, zprop) { - + ZVAL_DEREF(zprop); property = master_to_xml(get_conversion(Z_TYPE_P(zprop)), zprop, style, xmlParam); if (str_key) { @@ -2115,6 +2115,7 @@ static void add_xml_array_elements(xmlNodePtr xmlParam, if (j >= dims[0]) { break; } + ZVAL_DEREF(zdata); if (dimension == 1) { if (enc == NULL) { xparam = master_to_xml(get_conversion(Z_TYPE_P(zdata)), zdata, style, xmlParam); @@ -2678,7 +2679,6 @@ static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodeP if (Z_TYPE_P(data) == IS_ARRAY) { ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(data), int_val, key_val, temp_data) { - item = xmlNewNode(NULL, BAD_CAST("item")); xmlAddChild(xmlParam, item); key = xmlNewNode(NULL, BAD_CAST("key")); @@ -2701,6 +2701,7 @@ static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodeP smart_str_free(&tmp); } + ZVAL_DEREF(temp_data); xparam = master_to_xml(get_conversion(Z_TYPE_P(temp_data)), temp_data, style, item); xmlNodeSetName(xparam, BAD_CAST("value")); } ZEND_HASH_FOREACH_END(); diff --git a/ext/soap/tests/bug71711.phpt b/ext/soap/tests/bug71711.phpt new file mode 100644 index 00000000000..ec3930c6a50 --- /dev/null +++ b/ext/soap/tests/bug71711.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #71711: Soap Server Member variables reference bug +--SKIPIF-- + +--FILE-- + '', 'uri' => 'http://example.org']) extends SoapClient { + public function __doRequest($request, $location, $action, $version, $one_way = 0) { + echo $request; + return ''; + } +}; +$ref = array("foo"); +$data = new stdClass; +$data->prop =& $ref; +$client->foo($data); + +?> +--EXPECT-- + +foo diff --git a/ext/soap/tests/bug71996.phpt b/ext/soap/tests/bug71996.phpt new file mode 100644 index 00000000000..9f341fbc5e9 --- /dev/null +++ b/ext/soap/tests/bug71996.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #71996: Using references in arrays doesn't work like expected +--SKIPIF-- + +--FILE-- + '', 'uri' => 'http://example.org']) extends SoapClient { + public function __doRequest($request, $location, $action, $version, $one_way = 0) { + echo $request, "\n"; + return ''; + } +}; + +$ref = array("foo"); +$data = array(&$ref); +$client->foo($data); + +$ref = array("def" => "foo"); +$data = array("abc" => &$ref); +$client->foo($data); + +?> +--EXPECT-- + +foo + + +abcdeffoo diff --git a/ext/standard/array.c b/ext/standard/array.c index f471f2a7a49..af9734d3d7b 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1976,6 +1976,14 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu ZVAL_COPY(&data, value_ptr); zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data); } + if (zend_string_equals_literal(Z_STR_P(entry), "this")) { + zend_object *object = zend_get_this_object(EG(current_execute_data)); + if (object) { + GC_REFCOUNT(object)++; + ZVAL_OBJ(&data, object); + zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data); + } + } } else if (Z_TYPE_P(entry) == IS_ARRAY) { if ((Z_ARRVAL_P(entry)->u.v.nApplyCount > 1)) { php_error_docref(NULL, E_WARNING, "recursion detected"); @@ -2390,7 +2398,6 @@ static void php_array_data_shuffle(zval *array) /* {{{ */ } } while (--n_left) { - rnd_idx = php_rand(); RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX); if (rnd_idx != n_left) { temp = hash->arData[n_left]; @@ -2416,7 +2423,6 @@ static void php_array_data_shuffle(zval *array) /* {{{ */ } } while (--n_left) { - rnd_idx = php_rand(); RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX); if (rnd_idx != n_left) { temp = hash->arData[n_left]; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ef628cc6cba..58f9b491511 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3484,6 +3484,12 @@ static void basic_globals_ctor(php_basic_globals *basic_globals_p) /* {{{ */ memset(&BG(url_adapt_session_ex), 0, sizeof(BG(url_adapt_session_ex))); memset(&BG(url_adapt_output_ex), 0, sizeof(BG(url_adapt_output_ex))); + BG(url_adapt_session_ex).type = 1; + BG(url_adapt_output_ex).type = 0; + + zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1); + zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1); + #if defined(_REENTRANT) && defined(HAVE_MBRLEN) && defined(HAVE_MBSTATE_T) memset(&BG(mblen_state), 0, sizeof(BG(mblen_state))); #endif @@ -3504,6 +3510,9 @@ static void basic_globals_dtor(php_basic_globals *basic_globals_p) /* {{{ */ zend_hash_destroy(basic_globals_p->url_adapt_output_ex.tags); free(basic_globals_p->url_adapt_output_ex.tags); } + + zend_hash_destroy(&basic_globals_p->url_adapt_session_hosts_ht); + zend_hash_destroy(&basic_globals_p->url_adapt_output_hosts_ht); } /* }}} */ @@ -3878,7 +3887,9 @@ PHP_FUNCTION(constant) } } } else { - php_error_docref(NULL, E_WARNING, "Couldn't find constant %s", ZSTR_VAL(const_name)); + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "Couldn't find constant %s", ZSTR_VAL(const_name)); + } RETURN_NULL(); } } diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index c283ebc6b96..a52ed2501f6 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -115,6 +115,10 @@ static void convert_browscap_pattern(zval *pattern, int persistent) /* {{{ */ t[j++] = '\\'; t[j] = '~'; break; + case '+': + t[j++] = '\\'; + t[j] = '+'; + break; default: t[j] = lc_pattern[i]; break; diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c index f2f778e764b..bb68da082c8 100644 --- a/ext/standard/crypt.c +++ b/ext/standard/crypt.c @@ -158,6 +158,14 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch salt[1] == '2' && salt[3] == '$') { char output[PHP_MAX_SALT_LEN + 1]; + int k = 7; + + while (isalnum(salt[k]) || '.' == salt[k] || '/' == salt[k]) { + k++; + } + if (k != salt_len) { + return NULL; + } memset(output, 0, PHP_MAX_SALT_LEN + 1); diff --git a/ext/standard/file.c b/ext/standard/file.c index c0ba71ca7b4..a5fedb79cb2 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1546,6 +1546,11 @@ PHP_NAMED_FUNCTION(php_if_ftruncate) RETURN_FALSE; } + if (size < 0) { + php_error_docref(NULL, E_WARNING, "Negative size is not supported"); + RETURN_FALSE; + } + PHP_STREAM_TO_ZVAL(stream, fp); if (!php_stream_truncate_supported(stream)) { diff --git a/ext/standard/link_win32.c b/ext/standard/link_win32.c index 1bc5aa9d3df..7d43162a05d 100644 --- a/ext/standard/link_win32.c +++ b/ext/standard/link_win32.c @@ -157,6 +157,7 @@ PHP_FUNCTION(symlink) RETURN_FALSE; } if ((attr = GetFileAttributesW(dstw)) == INVALID_FILE_ATTRIBUTES) { + free(dstw); php_error_docref(NULL, E_WARNING, "Could not fetch file information(error %d)", GetLastError()); RETURN_FALSE; } diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index e443ec64a65..95803c9bbd4 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -753,9 +753,14 @@ PHP_FUNCTION(proc_open) len = (sizeof(COMSPEC_NT) + sizeof(" /c ") + tmp_len + 1); cmdw2 = (wchar_t *)malloc(len * sizeof(wchar_t)); + if (!cmdw2) { + php_error_docref(NULL, E_WARNING, "Command conversion failed"); + goto exit_fail; + } ret = _snwprintf(cmdw2, len, L"%hs /c %s", COMSPEC_NT, cmdw); if (-1 == ret) { + free(cmdw2); php_error_docref(NULL, E_WARNING, "Command conversion failed"); goto exit_fail; } diff --git a/ext/standard/string.c b/ext/standard/string.c index 4ac9143bcff..a3b0add7f01 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -3029,6 +3029,7 @@ static void php_strtr_array(zval *return_value, zend_string *input, HashTable *p } else { len = ZSTR_LEN(str_key); if (UNEXPECTED(len < 1)) { + efree(num_bitset); RETURN_FALSE; } else if (UNEXPECTED(len > slen)) { /* skip long patterns */ diff --git a/ext/standard/tests/array/compact_no_this.phpt b/ext/standard/tests/array/compact_no_this.phpt new file mode 100644 index 00000000000..df294f0525d --- /dev/null +++ b/ext/standard/tests/array/compact_no_this.phpt @@ -0,0 +1,25 @@ +--TEST-- +compact() without object context +--FILE-- +test() +); + +var_dump(compact('this')); + +var_dump((function(){ return compact('this'); })()); + +?> +--EXPECT-- +array(0) { +} +array(0) { +} +array(0) { +} diff --git a/ext/standard/tests/array/compact_order.phpt b/ext/standard/tests/array/compact_order.phpt new file mode 100644 index 00000000000..bf6051cc490 --- /dev/null +++ b/ext/standard/tests/array/compact_order.phpt @@ -0,0 +1,25 @@ +--TEST-- +compact() and hashmap order +--FILE-- + +--EXPECT-- +array(2) { + ["foo"]=> + NULL + ["bar"]=> + NULL +} +array(2) { + ["bar"]=> + NULL + ["foo"]=> + NULL +} diff --git a/ext/standard/tests/array/compact_this.phpt b/ext/standard/tests/array/compact_this.phpt new file mode 100644 index 00000000000..f3677e03e27 --- /dev/null +++ b/ext/standard/tests/array/compact_this.phpt @@ -0,0 +1,46 @@ +--TEST-- +compact() with object context +--FILE-- +test() +); + +var_dump( + (new class { + function test(){ + return compact([['this']]); + } + })->test() +); + +var_dump( + (new class { + function test(){ + return (function(){ return compact('this'); })(); + } + })->test() +); + +?> +--EXPECT-- +array(1) { + ["this"]=> + object(class@anonymous)#1 (0) { + } +} +array(1) { + ["this"]=> + object(class@anonymous)#1 (0) { + } +} +array(1) { + ["this"]=> + object(class@anonymous)#1 (0) { + } +} diff --git a/ext/standard/tests/assert/assert_error2.phpt b/ext/standard/tests/assert/assert_error2.phpt index 7861d435c83..f9018db05b0 100644 --- a/ext/standard/tests/assert/assert_error2.phpt +++ b/ext/standard/tests/assert/assert_error2.phpt @@ -24,7 +24,7 @@ int(0) Warning: assert(): Assertion "0 != 0" failed in %s on line 9 -Fatal error: Uncaught Error: Too few arguments to function f1(), 3 passed and exactly 4 expected in %sassert_error2.php:2 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f1(), 3 passed and exactly 4 expected in %sassert_error2.php:2 Stack trace: #0 [internal function]: f1('%s', 9, '0 != 0') #1 %sassert_error2.php(9): assert('0 != 0') diff --git a/ext/standard/tests/file/bug38450_3.phpt b/ext/standard/tests/file/bug38450_3.phpt index 07c5958ab4e..a72a00310dc 100644 --- a/ext/standard/tests/file/bug38450_3.phpt +++ b/ext/standard/tests/file/bug38450_3.phpt @@ -104,7 +104,7 @@ echo "Done\n"; --EXPECTF-- Warning: fopen(var://myvar): failed to open stream: "VariableStream::stream_open" call failed in %sbug38450_3.php on line %d -Fatal error: Uncaught Error: Too few arguments to function VariableStream::__construct(), 0 passed and exactly 1 expected in %sbug38450_3.php:7 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function VariableStream::__construct(), 0 passed and exactly 1 expected in %sbug38450_3.php:7 Stack trace: #0 [internal function]: VariableStream->__construct() #1 %s(%d): fopen('var://myvar', 'r+') diff --git a/ext/standard/tests/file/bug71882.phpt b/ext/standard/tests/file/bug71882.phpt new file mode 100644 index 00000000000..c132aa95c73 --- /dev/null +++ b/ext/standard/tests/file/bug71882.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #71882 (Negative ftruncate() on php://memory exhausts memory) +--FILE-- + +==DONE== +--EXPECTF-- +Warning: ftruncate(): Negative size is not supported in %s%ebug71882.php on line %d +bool(false) +==DONE== diff --git a/ext/standard/tests/file/filesize_variation3-win32.phpt b/ext/standard/tests/file/filesize_variation3-win32.phpt index f46695954c6..ab38c7d1c34 100644 --- a/ext/standard/tests/file/filesize_variation3-win32.phpt +++ b/ext/standard/tests/file/filesize_variation3-win32.phpt @@ -65,6 +65,8 @@ bool(true) int(1200) bool(true) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) *** Done *** diff --git a/ext/standard/tests/file/filesize_variation3.phpt b/ext/standard/tests/file/filesize_variation3.phpt index 3ae06fa8717..67d46998d2a 100644 --- a/ext/standard/tests/file/filesize_variation3.phpt +++ b/ext/standard/tests/file/filesize_variation3.phpt @@ -65,6 +65,8 @@ bool(true) int(1200) bool(true) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) *** Done *** diff --git a/ext/standard/tests/file/ftruncate.phpt b/ext/standard/tests/file/ftruncate.phpt index 8954ef12f24..acc4e8afa30 100644 Binary files a/ext/standard/tests/file/ftruncate.phpt and b/ext/standard/tests/file/ftruncate.phpt differ diff --git a/ext/standard/tests/file/ftruncate_variation4-win32.phpt b/ext/standard/tests/file/ftruncate_variation4-win32.phpt index ae9e5a47435..5bf5f679b6f 100644 --- a/ext/standard/tests/file/ftruncate_variation4-win32.phpt +++ b/ext/standard/tests/file/ftruncate_variation4-win32.phpt @@ -77,6 +77,8 @@ echo "Done\n"; -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -85,6 +87,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -93,6 +97,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -101,6 +107,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -109,6 +117,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -117,6 +127,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -125,6 +137,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -133,6 +147,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -141,6 +157,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -149,6 +167,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -157,6 +177,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -165,6 +187,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -173,6 +197,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -181,6 +207,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -189,6 +217,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -197,6 +227,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -205,6 +237,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -213,6 +247,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -221,6 +257,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -229,6 +267,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -237,6 +277,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -245,6 +287,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -253,6 +297,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -261,6 +307,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -271,6 +319,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -279,6 +329,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -287,6 +339,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -295,6 +349,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -303,6 +359,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -311,6 +369,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -319,6 +379,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -327,6 +389,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -335,6 +399,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1137) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -343,6 +409,8 @@ int(1137) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -351,6 +419,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -359,6 +429,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1137) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -367,6 +439,8 @@ int(1137) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -375,6 +449,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -383,6 +459,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1137) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -391,6 +469,8 @@ int(1137) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -399,6 +479,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -407,6 +489,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1137) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -415,6 +499,8 @@ int(1137) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -423,6 +509,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -431,6 +519,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -439,6 +529,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -447,6 +539,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -455,6 +549,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) diff --git a/ext/standard/tests/file/ftruncate_variation4.phpt b/ext/standard/tests/file/ftruncate_variation4.phpt index 4a5a36236c1..ef0ee219962 100644 --- a/ext/standard/tests/file/ftruncate_variation4.phpt +++ b/ext/standard/tests/file/ftruncate_variation4.phpt @@ -77,6 +77,8 @@ echo "Done\n"; -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -85,6 +87,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -93,6 +97,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -101,6 +107,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -109,6 +117,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -117,6 +127,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -125,6 +137,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -133,6 +147,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -141,6 +157,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -149,6 +167,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -157,6 +177,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -165,6 +187,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -173,6 +197,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -181,6 +207,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -189,6 +217,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -197,6 +227,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -205,6 +237,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -213,6 +247,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -221,6 +257,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -229,6 +267,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -237,6 +277,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -245,6 +287,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -253,6 +297,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -261,6 +307,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -271,6 +319,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -279,6 +329,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -287,6 +339,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -295,6 +349,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -303,6 +359,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -311,6 +369,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -319,6 +379,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -327,6 +389,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -335,6 +399,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -343,6 +409,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -351,6 +419,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -359,6 +429,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -367,6 +439,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -375,6 +449,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -383,6 +459,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -391,6 +469,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -399,6 +479,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -407,6 +489,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -415,6 +499,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -423,6 +509,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -431,6 +519,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -439,6 +529,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -447,6 +539,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) @@ -455,6 +549,8 @@ int(1024) -- Testing ftruncate(): try truncating file to a negative size -- int(1024) int(0) + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) int(0) bool(false) diff --git a/ext/standard/tests/file/userstreams_005.phpt b/ext/standard/tests/file/userstreams_005.phpt index 2d39be25d68..a2af1b4086e 100644 --- a/ext/standard/tests/file/userstreams_005.phpt +++ b/ext/standard/tests/file/userstreams_005.phpt @@ -55,6 +55,8 @@ bool(true) truncation with new_size=10 bool(true) ------ stream_truncate negative size: ------- + +Warning: ftruncate(): Negative size is not supported in %s on line %d bool(false) ------ stream_truncate bad return: ------- truncation with new_size=0 diff --git a/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt b/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt index 9550857b549..1033c0e3e63 100644 --- a/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt @@ -25,11 +25,13 @@ create_verify_file($prefix, "Ελλάδα.txt", ""); create_verify_file($prefix, "привет", "opened an utf8 filename for reading"); create_verify_file($prefix, "テストマルチバイト・パス", $content); create_verify_file($prefix, "測試多字節路徑", $content); +create_verify_file($prefix, "żółć.txt", $content); create_verify_dir($prefix, "tschüß3"); create_verify_dir($prefix, "Voláçao3"); create_verify_dir($prefix, "привет3"); create_verify_dir($prefix, "テストマルチバイト・パス42"); create_verify_dir($prefix, "測試多字節路徑5"); +create_verify_dir($prefix, "żółć"); $dirw = $prefix . DIRECTORY_SEPARATOR; @@ -64,6 +66,8 @@ filename: Voláçao : filetype: file filename: Voláçao3 : filetype: dir filename: českýtestování.inc : filetype: file filename: š.txt : filetype: file +filename: żółć : filetype: dir +filename: żółć.txt : filetype: file filename: Ελλάδα.txt : filetype: file filename: привет : filetype: file filename: привет3 : filetype: dir diff --git a/ext/standard/tests/general_functions/bug41970.phpt b/ext/standard/tests/general_functions/bug41970.phpt index 4bce3ac7f73..6f05137afc1 100644 --- a/ext/standard/tests/general_functions/bug41970.phpt +++ b/ext/standard/tests/general_functions/bug41970.phpt @@ -14,13 +14,13 @@ echo "Done\n"; ?> --EXPECTF-- Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 5 -NULL +bool(true) Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 6 NULL Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 7 -NULL +bool(true) Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 8 NULL diff --git a/ext/standard/tests/general_functions/bug72920.phpt b/ext/standard/tests/general_functions/bug72920.phpt new file mode 100644 index 00000000000..b5ca4760c30 --- /dev/null +++ b/ext/standard/tests/general_functions/bug72920.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72920 (Accessing a private constant using constant() creates an exception AND warning) +--FILE-- +getMessage()); +} +--EXPECT-- +string(35) "Cannot access private const Foo::C1" diff --git a/ext/standard/tests/math/rand_variation1.phpt b/ext/standard/tests/math/rand_variation1.phpt index 7019a99d57c..f14ada87f58 100644 --- a/ext/standard/tests/math/rand_variation1.phpt +++ b/ext/standard/tests/math/rand_variation1.phpt @@ -97,17 +97,13 @@ int(%i) int(%i) -- Iteration 3 -- - -Warning: rand(): max(100) is smaller than min(12345) in %s on line %d -bool(false) +int(%i) -- Iteration 4 -- int(%i) -- Iteration 5 -- - -Warning: rand(): max(100) is smaller than min(2147483647) in %s on line %d -bool(false) +int(%i) -- Iteration 6 -- int(%i) diff --git a/ext/standard/tests/math/rand_variation2.phpt b/ext/standard/tests/math/rand_variation2.phpt index 04ee2051912..824b47b0cb5 100644 --- a/ext/standard/tests/math/rand_variation2.phpt +++ b/ext/standard/tests/math/rand_variation2.phpt @@ -91,35 +91,25 @@ fclose($fp); *** Testing rand) : usage variations *** -- Iteration 1 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 2 -- - -Warning: rand(): max(1) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 3 -- int(%i) -- Iteration 4 -- - -Warning: rand(): max(-2345) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 5 -- int(%i) -- Iteration 6 -- - -Warning: rand(): max(10) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 7 -- - -Warning: rand(): max(-10) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 8 -- @@ -127,44 +117,28 @@ Warning: rand() expects parameter 2 to be integer, float given in %s on line %d NULL -- Iteration 9 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 10 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 11 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 12 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 13 -- - -Warning: rand(): max(1) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 14 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 15 -- - -Warning: rand(): max(1) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 16 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 17 -- @@ -202,14 +176,10 @@ Warning: rand() expects parameter 2 to be integer, object given in %s on line %d NULL -- Iteration 24 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 25 -- - -Warning: rand(): max(0) is smaller than min(100) in %s on line %d -bool(false) +int(%i) -- Iteration 26 -- diff --git a/ext/standard/tests/misc/bug65550.phpt b/ext/standard/tests/misc/bug65550.phpt new file mode 100644 index 00000000000..41967426fa3 --- /dev/null +++ b/ext/standard/tests/misc/bug65550.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #65550 (get_browser() incorrectly parses entries with "+" sign) +--INI-- +browscap={PWD}/browscap.ini +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +string(7) "OmniWeb" +string(3) "5.6" +==DONE== diff --git a/ext/standard/tests/streams/bug72771.phpt b/ext/standard/tests/streams/bug72771.phpt new file mode 100644 index 00000000000..b38ccbdda82 --- /dev/null +++ b/ext/standard/tests/streams/bug72771.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #72771. FTPS to FTP downgrade not allowed when server doesn't support AUTH TLS or AUTH SSL. +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECTF-- +Warning: opendir(ftps://127.0.0.1:%d/): failed to open dir: Server doesn't support FTPS. in %s on line %d +bool(false) +==DONE== diff --git a/ext/standard/tests/strings/bug72703.phpt b/ext/standard/tests/strings/bug72703.phpt new file mode 100644 index 00000000000..5e3bf4875d9 --- /dev/null +++ b/ext/standard/tests/strings/bug72703.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72703 Out of bounds global memory read in BF_crypt triggered by password_verify +--SKIPIF-- + +--FILE-- + +==OK== +--EXPECT-- +bool(false) +==OK== + diff --git a/ext/standard/url_scanner_ex.c b/ext/standard/url_scanner_ex.c index 880332ead70..a798b5ccba6 100644 --- a/ext/standard/url_scanner_ex.c +++ b/ext/standard/url_scanner_ex.c @@ -1444,17 +1444,6 @@ PHPAPI int php_url_scanner_reset_var(zend_string *name, int encode) PHP_MINIT_FUNCTION(url_scanner) { - BG(url_adapt_session_ex).tags = NULL; - BG(url_adapt_session_ex).form_app.s = BG(url_adapt_session_ex).url_app.s = NULL; - zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1); - - BG(url_adapt_output_ex).tags = NULL; - BG(url_adapt_output_ex).form_app.s = BG(url_adapt_output_ex).url_app.s = NULL; - zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1); - - BG(url_adapt_session_ex).type = 1; - BG(url_adapt_output_ex).type = 0; - REGISTER_INI_ENTRIES(); return SUCCESS; } diff --git a/ext/standard/url_scanner_ex.re b/ext/standard/url_scanner_ex.re index e0e74d03fad..2f847262ff2 100644 --- a/ext/standard/url_scanner_ex.re +++ b/ext/standard/url_scanner_ex.re @@ -962,17 +962,6 @@ PHPAPI int php_url_scanner_reset_var(zend_string *name, int encode) PHP_MINIT_FUNCTION(url_scanner) { - BG(url_adapt_session_ex).tags = NULL; - BG(url_adapt_session_ex).form_app.s = BG(url_adapt_session_ex).url_app.s = NULL; - zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1); - - BG(url_adapt_output_ex).tags = NULL; - BG(url_adapt_output_ex).form_app.s = BG(url_adapt_output_ex).url_app.s = NULL; - zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1); - - BG(url_adapt_session_ex).type = 1; - BG(url_adapt_output_ex).type = 0; - REGISTER_INI_ENTRIES(); return SUCCESS; } diff --git a/ext/xml/tests/bug72714.phpt b/ext/xml/tests/bug72714.phpt new file mode 100644 index 00000000000..7b44e1fd117 --- /dev/null +++ b/ext/xml/tests/bug72714.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72714 (_xml_startElementHandler() segmentation fault) +--SKIPIF-- + +--FILE-- +867'; + + $xml_parser = xml_parser_create(); + xml_set_element_handler($xml_parser, 'startElement', 'endElement'); + + xml_parser_set_option($xml_parser, XML_OPTION_SKIP_TAGSTART, $tagstart); + xml_parse($xml_parser, $xml); + + xml_parser_free($xml_parser); +} + +parse(3015809298423721); +parse(20); +?> +===DONE=== +--EXPECTF-- +Notice: xml_parser_set_option(): tagstart ignored, because it is out of range in %s%ebug72714.php on line %d +string(9) "NS1:TOTAL" +string(0) "" +===DONE=== diff --git a/ext/xml/xml.c b/ext/xml/xml.c index c08e3818d53..f0da47dc5b4 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -69,6 +69,10 @@ ZEND_GET_MODULE(xml) #endif /* COMPILE_DL_XML */ /* }}} */ + +#define SKIP_TAGSTART(str) ((str) + (parser->toffset > strlen(str) ? strlen(str) : parser->toffset)) + + /* {{{ function prototypes */ PHP_MINIT_FUNCTION(xml); PHP_MINFO_FUNCTION(xml); @@ -727,7 +731,7 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch if (!Z_ISUNDEF(parser->startElementHandler)) { ZVAL_COPY(&args[0], &parser->index); - ZVAL_STRING(&args[1], ZSTR_VAL(tag_name) + parser->toffset); + ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name))); array_init(&args[2]); while (attributes && *attributes) { @@ -758,7 +762,7 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset); - add_assoc_string(&tag, "tag", ZSTR_VAL(tag_name) + parser->toffset); /* cast to avoid gcc-warning */ + add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ add_assoc_string(&tag, "type", "open"); add_assoc_long(&tag, "level", parser->level); @@ -812,7 +816,7 @@ void _xml_endElementHandler(void *userData, const XML_Char *name) if (!Z_ISUNDEF(parser->endElementHandler)) { ZVAL_COPY(&args[0], &parser->index); - ZVAL_STRING(&args[1], ZSTR_VAL(tag_name) + parser->toffset); + ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name))); xml_call_handler(parser, &parser->endElementHandler, parser->endElementPtr, 2, args, &retval); zval_ptr_dtor(&retval); @@ -828,7 +832,7 @@ void _xml_endElementHandler(void *userData, const XML_Char *name) _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset); - add_assoc_string(&tag, "tag", ZSTR_VAL(tag_name) + parser->toffset); /* cast to avoid gcc-warning */ + add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ add_assoc_string(&tag, "type", "close"); add_assoc_long(&tag, "level", parser->level); @@ -922,9 +926,9 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) if (parser->level <= XML_MAXLEVEL && parser->level > 0) { array_init(&tag); - _xml_add_to_info(parser,parser->ltags[parser->level-1] + parser->toffset); + _xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1])); - add_assoc_string(&tag, "tag", parser->ltags[parser->level-1] + parser->toffset); + add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1])); add_assoc_str(&tag, "value", decoded_value); add_assoc_string(&tag, "type", "cdata"); add_assoc_long(&tag, "level", parser->level); @@ -1601,6 +1605,10 @@ PHP_FUNCTION(xml_parser_set_option) case PHP_XML_OPTION_SKIP_TAGSTART: convert_to_long_ex(val); parser->toffset = Z_LVAL_P(val); + if (parser->toffset < 0) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "tagstart ignored, because it is out of range"); + parser->toffset = 0; + } break; case PHP_XML_OPTION_SKIP_WHITE: convert_to_long_ex(val); diff --git a/run-tests.php b/run-tests.php index 0dcf21bcbf5..80757edd908 100755 --- a/run-tests.php +++ b/run-tests.php @@ -269,7 +269,7 @@ More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n" @unlink($info_file); // load list of enabled extensions - save_text($info_file, ''); + save_text($info_file, ''); $exts_to_test = explode(',',`$php $pass_options $info_params $no_file_cache "$info_file"`); // check for extensions that need special handling and regenerate $info_params_ex = array( diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index 2182a33a48c..e6b7e80efd4 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -69,6 +69,19 @@ #define SAPI_LSAPI_MAX_HEADER_LENGTH 2048 +/* Key for each cache entry is dirname(PATH_TRANSLATED). + * + * NOTE: Each cache entry config_hash contains the combination from all user ini files found in + * the path starting from doc_root throught to dirname(PATH_TRANSLATED). There is no point + * storing per-file entries as it would not be possible to detect added / deleted entries + * between separate files. + */ +typedef struct _user_config_cache_entry { + time_t expires; + HashTable user_config; +} user_config_cache_entry; +static HashTable user_config_cache; + static int lsapi_mode = 0; static char *php_self = ""; static char *script_filename = ""; @@ -76,6 +89,7 @@ static int source_highlight = 0; static int ignore_php_ini = 0; static char * argv0 = NULL; static int engine = 1; +static int parse_user_ini = 0; #ifdef ZTS zend_compiler_globals *compiler_globals; zend_executor_globals *executor_globals; @@ -86,6 +100,14 @@ void ***tsrm_ls; zend_module_entry litespeed_module_entry; +static void init_sapi_from_env(sapi_module_struct *sapi_module) +{ + char *p; + p = getenv("LSPHPRC"); + if (p) + sapi_module->php_ini_path_override = p; +} + /* {{{ php_lsapi_startup */ static int php_lsapi_startup(sapi_module_struct *sapi_module) @@ -196,46 +218,19 @@ static char *sapi_lsapi_getenv( char * name, size_t name_len ) /* }}} */ - - static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { -#if PHP_MAJOR_VERSION >= 7 - int filter_arg = (Z_ARR_P((zval *)arg) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV])) + int filter_arg = (Z_ARR_P((zval *)arg) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV])) ? PARSE_ENV : PARSE_SERVER; -#else - int filter_arg = (arg == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER; -#endif char * new_val = (char *) pValue; size_t new_val_len; if (sapi_module.input_filter(filter_arg, (char *)pKey, &new_val, valLen, &new_val_len)) { php_register_variable_safe((char *)pKey, new_val, new_val_len, (zval *)arg ); } - return 1; -} - -/* -static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen, - void * arg ) -{ - zval * gpc_element, **gpc_element_p; - HashTable * symtable1 = Z_ARRVAL_P((zval * )arg); - register char * pKey1 = (char *)pKey; - - MAKE_STD_ZVAL(gpc_element); - Z_STRLEN_P( gpc_element ) = valLen; - Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen); - Z_TYPE_P( gpc_element ) = IS_STRING; -#if PHP_MAJOR_VERSION > 4 - zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); -#else - zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); -#endif return 1; } -*/ static void litespeed_php_import_environment_variables(zval *array_ptr) { @@ -244,7 +239,6 @@ static void litespeed_php_import_environment_variables(zval *array_ptr) size_t alloc_size = sizeof(buf); unsigned long nlen; /* ptrdiff_t is not portable */ -#if PHP_MAJOR_VERSION >= 7 if (Z_TYPE(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY && Z_ARR_P(array_ptr) != Z_ARR(PG(http_globals)[TRACK_VARS_ENV]) && zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV])) > 0 @@ -260,29 +254,6 @@ static void litespeed_php_import_environment_variables(zval *array_ptr) ZVAL_DUP(array_ptr, &PG(http_globals)[TRACK_VARS_SERVER]); return; } -#else - if (PG(http_globals)[TRACK_VARS_ENV] && - array_ptr != PG(http_globals)[TRACK_VARS_ENV] && - Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY && - zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0 - ) { - zval_dtor(array_ptr); - *array_ptr = *PG(http_globals)[TRACK_VARS_ENV]; - INIT_PZVAL(array_ptr); - zval_copy_ctor(array_ptr); - return; - } else if (PG(http_globals)[TRACK_VARS_SERVER] && - array_ptr != PG(http_globals)[TRACK_VARS_SERVER] && - Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY && - zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0 - ) { - zval_dtor(array_ptr); - *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER]; - INIT_PZVAL(array_ptr); - zval_copy_ctor(array_ptr); - return; - } -#endif for (env = environ; env != NULL && *env != NULL; env++) { p = strchr(*env, '='); @@ -412,13 +383,33 @@ static void sapi_lsapi_log_message(char *message, int syslog_type_int) } /* }}} */ +/* Set to 1 to turn on log messages useful during development: + */ +#if 0 +static void log_message (const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + char buf[0x100]; + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + sapi_lsapi_log_message(buf +#if PHP_MAJOR_VERSION > 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION >= 1) + , 0 +#endif + ); +} +#define DEBUG_MESSAGE(fmt, ...) log_message("LS:%d " fmt "\n", __LINE__, ##__VA_ARGS__) +#else +#define DEBUG_MESSAGE(fmt, ...) +#endif /* {{{ sapi_module_struct cgi_sapi_module */ static sapi_module_struct lsapi_sapi_module = { "litespeed", - "LiteSpeed V6.9", + "LiteSpeed V6.10", php_lsapi_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ @@ -549,6 +540,7 @@ static int lsapi_execute_script( zend_file_handle * file_handle) } +static int lsapi_activate_user_ini(); static int lsapi_module_main(int show_source) { @@ -557,6 +549,11 @@ static int lsapi_module_main(int show_source) if (php_request_startup() == FAILURE ) { return -1; } + + if (parse_user_ini && lsapi_activate_user_ini() == FAILURE) { + return -1; + } + if (show_source) { zend_syntax_highlighter_ini syntax_highlighter_ini; @@ -577,7 +574,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va void * arg ) { #if PHP_MAJOR_VERSION >= 7 - zend_string * psKey; + zend_string * psKey; #endif int type = ZEND_INI_PERDIR; if ( '\001' == *pKey ) { @@ -593,7 +590,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va engine = 0; } else - { + { #if PHP_MAJOR_VERSION >= 7 --keyLen; psKey = zend_string_init(pKey, keyLen, 1); @@ -606,11 +603,293 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va (char *)pValue, valLen, type, PHP_INI_STAGE_ACTIVATE); #endif - } + } } return 1; } +static void user_config_cache_entry_dtor(zval *el) +{ + user_config_cache_entry *entry = (user_config_cache_entry *)Z_PTR_P(el); + zend_hash_destroy(&entry->user_config); + free(entry); +} + +static void user_config_cache_init() +{ + zend_hash_init(&user_config_cache, 0, NULL, user_config_cache_entry_dtor, 1); +} + +static int pathlen_without_trailing_slash(char *path) +{ + int len = (int)strlen(path); + while (len > 1 && /* mind "/" as root dir */ + path[len-1] == DEFAULT_SLASH) + { + --len; + } + return len; +} + +static inline char* skip_slash(char *s) +{ + while (*s == DEFAULT_SLASH) { + ++s; + } + return s; +} + +/** + * Walk down the path_stop starting at path_start. + * + * If path_start = "/path1" and path_stop = "/path1/path2/path3" + * the callback will be called 3 times with the next args: + * + * 1. "/path1/path2/path3" + * ^ end + * ^ start + * 2. "/path1/path2/path3" + * ^ end + * ^ start + * 3. "/path1/path2/path3" + * ^ end + * ^ start + * + * path_stop has to be a subdir of path_start + * or to be path_start itself. + * + * Both path args have to be absolute. + * Trailing slashes are allowed. + * NULL or empty string args are not allowed. + */ +static void walk_down_the_path(char* path_start, + char* path_stop, + void (*cb)(char* begin, + char* end, + void* data), + void* data) +{ + char *pos = path_stop + pathlen_without_trailing_slash(path_start); + cb(path_stop, pos, data); + + while ((pos = skip_slash(pos))[0]) { + pos = strchr(pos, DEFAULT_SLASH); + if (!pos) { + /* The last token without trailing slash + */ + cb(path_stop, path_stop + strlen(path_stop), data); + return; + } + cb(path_stop, pos, data); + } +} + + +typedef struct { + char *path; + uint path_len; + char *doc_root; + user_config_cache_entry *entry; +} _lsapi_activate_user_ini_ctx; + +typedef int (*fn_activate_user_ini_chain_t) + (_lsapi_activate_user_ini_ctx *ctx, void* next); + +static int lsapi_activate_user_ini_basic_checks(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + int rc = SUCCESS; + fn_activate_user_ini_chain_t *fn_next = next; + + if (!PG(user_ini_filename) || !*PG(user_ini_filename)) { + return SUCCESS; + } + + /* PATH_TRANSLATED should be defined at this stage */ + ctx->path = SG(request_info).path_translated; + if (!ctx->path || !*ctx->path) { + return FAILURE; + } + + ctx->doc_root = sapi_lsapi_getenv("DOCUMENT_ROOT", 0); + DEBUG_MESSAGE("doc_root: %s", ctx->doc_root); + + if (*fn_next) { + rc = (*fn_next)(ctx, fn_next + 1); + } + + return rc; +} + +static int lsapi_activate_user_ini_mk_path(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + char *path; + int rc = SUCCESS; + fn_activate_user_ini_chain_t *fn_next = next; + + /* Extract dir name from path_translated * and store it in 'path' */ + ctx->path_len = strlen(ctx->path); + path = ctx->path = estrndup(SG(request_info).path_translated, ctx->path_len); + if (!path) + return FAILURE; + ctx->path_len = zend_dirname(path, ctx->path_len); + DEBUG_MESSAGE("dirname: %s", ctx->path); + + if (*fn_next) { + rc = (*fn_next)(ctx, fn_next + 1); + } + + efree(path); + return rc; +} + +static int lsapi_activate_user_ini_mk_realpath(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + char *real_path; + int rc = SUCCESS; + fn_activate_user_ini_chain_t *fn_next = next; + + if (!IS_ABSOLUTE_PATH(ctx->path, ctx->path_len)) { + real_path = tsrm_realpath(ctx->path, NULL); + if (!real_path) { + return SUCCESS; + } + ctx->path = real_path; + ctx->path_len = strlen(ctx->path); + DEBUG_MESSAGE("calculated tsrm realpath: %s", real_path); + } else { + DEBUG_MESSAGE("%s is an absolute path", ctx->path); + real_path = NULL; + } + + if (*fn_next) { + rc = (*fn_next)(ctx, fn_next + 1); + } + + if (real_path) + efree(real_path); + return rc; +} + +static int lsapi_activate_user_ini_mk_user_config(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + fn_activate_user_ini_chain_t *fn_next = next; + + /* Find cached config entry: If not found, create one */ + ctx->entry = zend_hash_str_find_ptr(&user_config_cache, ctx->path, ctx->path_len); + + if (ctx->entry) { + DEBUG_MESSAGE("found entry for %s", ctx->path); + } else { + DEBUG_MESSAGE("entry for %s not found, creating new entry", ctx->path); + ctx->entry = pemalloc(sizeof(user_config_cache_entry), 1); + ctx->entry->expires = 0; + zend_hash_init(&ctx->entry->user_config, 0, NULL, + config_zval_dtor, 1); + zend_hash_str_update_ptr(&user_config_cache, ctx->path, + ctx->path_len, ctx->entry); + } + + if (*fn_next) { + return (*fn_next)(ctx, fn_next + 1); + } else { + return SUCCESS; + } +} + +static void walk_down_the_path_callback(char* begin, + char* end, + void* data) +{ + _lsapi_activate_user_ini_ctx *ctx = data; + char tmp = end[0]; + end[0] = 0; + DEBUG_MESSAGE("parsing %s%c%s", begin, DEFAULT_SLASH, PG(user_ini_filename)); + php_parse_user_ini_file(begin, PG(user_ini_filename), &ctx->entry->user_config); + end[0] = tmp; +} + +static int lsapi_activate_user_ini_walk_down_the_path(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + time_t request_time = sapi_get_request_time(); + uint path_len, docroot_len; + int rc = SUCCESS; + fn_activate_user_ini_chain_t *fn_next = next; + + if (!ctx->entry->expires || request_time > ctx->entry->expires) + { + docroot_len = ctx->doc_root && ctx->doc_root[0] + ? pathlen_without_trailing_slash(ctx->doc_root) + : 0; + + int is_outside_of_docroot = !docroot_len || + ctx->path_len < docroot_len || + strncmp(ctx->path, ctx->doc_root, docroot_len) != 0; + + if (is_outside_of_docroot) { + php_parse_user_ini_file(ctx->path, PG(user_ini_filename), + &ctx->entry->user_config); + } else { + walk_down_the_path(ctx->doc_root, ctx->path, + &walk_down_the_path_callback, ctx); + } + + ctx->entry->expires = request_time + PG(user_ini_cache_ttl); + } + + if (*fn_next) { + rc = (*fn_next)(ctx, fn_next + 1); + } + + return rc; +} + +static int lsapi_activate_user_ini_finally(_lsapi_activate_user_ini_ctx *ctx, + void* next) +{ + int rc = SUCCESS; + fn_activate_user_ini_chain_t *fn_next = next; + + DEBUG_MESSAGE("calling php_ini_activate_config()"); + php_ini_activate_config(&ctx->entry->user_config, PHP_INI_PERDIR, + PHP_INI_STAGE_HTACCESS); + + if (*fn_next) { + rc = (*fn_next)(ctx, fn_next + 1); + } + + return rc; +} + +static int lsapi_activate_user_ini(TSRMLS_D) +{ + _lsapi_activate_user_ini_ctx ctx; + /** + * The reason to have this function list stacked + * is each function now can define a scoped destructor. + * + * Passing control via function pointer is a sign of low coupling, + * which means dependencies between these functions are to be + * controlled from a single place + * (here below, by modifying this function list order) + */ + static const fn_activate_user_ini_chain_t fn_chain[] = { + &lsapi_activate_user_ini_basic_checks, + &lsapi_activate_user_ini_mk_path, + &lsapi_activate_user_ini_mk_realpath, + &lsapi_activate_user_ini_mk_user_config, + &lsapi_activate_user_ini_walk_down_the_path, + &lsapi_activate_user_ini_finally, + NULL + }; + + return fn_chain[0](&ctx, (fn_activate_user_ini_chain_t*)(fn_chain + 1)); +} + static void override_ini() { @@ -804,9 +1083,9 @@ static int cli_main( int argc, char * argv[] ) case 'v': if (php_request_startup() != FAILURE) { #if ZEND_DEBUG - php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2015 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #else - php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2015 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #endif #ifdef PHP_OUTPUT_NEWAPI php_output_end_all(); @@ -1030,6 +1309,11 @@ int main( int argc, char * argv[] ) lsapi_sapi_module.executable_location = argv[0]; + /* Initialize from environment variables before processing command-line + * options: the latter override the former. + */ + init_sapi_from_env(&lsapi_sapi_module); + if ( ignore_php_ini ) lsapi_sapi_module.php_ini_ignore = 1; @@ -1135,6 +1419,12 @@ zend_function_entry litespeed_functions[] = { static PHP_MINIT_FUNCTION(litespeed) { + user_config_cache_init(); + + const char *p = getenv("LSPHP_ENABLE_USER_INI"); + if (p && 0 == strcasecmp(p, "on")) + parse_user_ini = 1; + /* REGISTER_INI_ENTRIES(); */ return SUCCESS; } @@ -1142,6 +1432,8 @@ static PHP_MINIT_FUNCTION(litespeed) static PHP_MSHUTDOWN_FUNCTION(litespeed) { + zend_hash_destroy(&user_config_cache); + /* UNREGISTER_INI_ENTRIES(); */ return SUCCESS; } diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.c b/sapi/phpdbg/phpdbg_webdata_transfer.c index 1805519a75b..2deb1607c56 100644 --- a/sapi/phpdbg/phpdbg_webdata_transfer.c +++ b/sapi/phpdbg/phpdbg_webdata_transfer.c @@ -23,7 +23,7 @@ static int phpdbg_is_auto_global(char *name, int len) { int ret; zend_string *str = zend_string_init(name, len, 0); ret = zend_is_auto_global(str); - efree(str); + zend_string_free(str); return ret; } diff --git a/tests/classes/constants_visibility_002.phpt b/tests/classes/constants_visibility_002.phpt index 82bdd6df1fc..6ec99012694 100644 --- a/tests/classes/constants_visibility_002.phpt +++ b/tests/classes/constants_visibility_002.phpt @@ -21,8 +21,6 @@ constant('A::protectedConst'); string(14) "protectedConst" string(14) "protectedConst" -Warning: constant(): Couldn't find constant A::protectedConst in %s on line 14 - Fatal error: Uncaught Error: Cannot access protected const A::protectedConst in %s:14 Stack trace: #0 %s(14): constant('A::protectedCon...') diff --git a/tests/classes/constants_visibility_003.phpt b/tests/classes/constants_visibility_003.phpt index 7f049abffb9..9c7bcfb21c3 100644 --- a/tests/classes/constants_visibility_003.phpt +++ b/tests/classes/constants_visibility_003.phpt @@ -21,8 +21,6 @@ constant('A::privateConst'); string(12) "privateConst" string(12) "privateConst" -Warning: constant(): Couldn't find constant A::privateConst in %s on line 14 - Fatal error: Uncaught Error: Cannot access private const A::privateConst in %s:14 Stack trace: #0 %s(14): constant('A::privateConst') diff --git a/tests/classes/interfaces_003.phpt b/tests/classes/interfaces_003.phpt index e66a86491c2..28680096c5b 100644 --- a/tests/classes/interfaces_003.phpt +++ b/tests/classes/interfaces_003.phpt @@ -23,7 +23,7 @@ $obj = new MyTestClass; ===DONE=== --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function MyTestClass::__construct(), 0 passed in %sinterfaces_003.php on line 17 and exactly 1 expected in %sinterfaces_003.php:12 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function MyTestClass::__construct(), 0 passed in %sinterfaces_003.php on line 17 and exactly 1 expected in %sinterfaces_003.php:12 Stack trace: #0 %s(%d): MyTestClass->__construct() #1 {main} diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 58b1420b898..5c892899bbd 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -212,11 +212,44 @@ if (PHP_SECURITY_FLAGS == "yes") { ADD_FLAG("LDFLAGS", "/NXCOMPAT /DYNAMICBASE "); } -/* XXX add and implement clang keyword for clang analyzer */ -ARG_WITH("analyzer", "Enable static analyzer. Pass vs for Visual Studio, pvs for PVS-Studio", "no"); +ARG_WITH("analyzer", "Enable static analyzer. Pass vs for Visual Studio, clang for clang, cppcheck for Cppcheck, pvs for PVS-Studio", "no"); if (PHP_ANALYZER == "vs") { ADD_FLAG("CFLAGS", " /analyze "); ADD_FLAG("CFLAGS", " /wd6308 "); +} else if (PHP_ANALYZER == "clang") { + var clang_cl = false; + + if (FSO.FileExists(PROGRAM_FILES + "\\LLVM\\bin\\clang-cl.exe")) { + clang_cl = PROGRAM_FILES + "\\LLVM\\bin\\clang-cl.exe"; + } else if (FSO.FileExists(PROGRAM_FILESx86 + "\\LLVM\\bin\\clang-cl.exe")) { + clang_cl = PROGRAM_FILESx86 + "\\LLVM\\bin\\clang-cl.exe"; + } + + if (!clang_cl) { + if (false == PATH_PROG('clang-cl', null, 'CLANG_CL')) { + WARNING("Couldn't find clang binaries, static analyze was disabled"); + PHP_ANALYZER = "no"; + } + } else { + DEFINE("CLANG_CL", clang_cl); + } +} else if (PHP_ANALYZER == "cppcheck") { + + var cppcheck = false; + + if (FSO.FileExists(PROGRAM_FILES + "\\Cppcheck\\cppcheck.exe")) { + cppcheck = PROGRAM_FILES + "\\Cppcheck\\cppcheck.exe"; + } else if (FSO.FileExists(PROGRAM_FILESx86 + "\\Cppcheck\\cppcheck.exe")) { + cppcheck = PROGRAM_FILESx86 + "\\Cppcheck\\cppcheck.exe"; + } + if (!cppcheck) { + if (false == PATH_PROG('cppcheck', null, 'CPPCHECK')) { + WARNING("Couldn't find Cppcheck binaries, static analyze was disabled"); + PHP_ANALYZER = "no"; + } + } else { + DEFINE("CPPCHECK", cppcheck); + } } else if (PHP_ANALYZER == "pvs") { var pvs_studio = false; diff --git a/win32/build/confutils.js b/win32/build/confutils.js index 038692911c7..5014330b3af 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -1526,19 +1526,72 @@ function ADD_SOURCES(dir, file_list, target, obj_dir) ADD_FLAG(bd_flags_name, "/Fd" + sub_build + d); } + if (PHP_ANALYZER == "clang") { + var analyzer_base_args = X64 ? "-m64" : "-m32"; + var analyzer_base_flags = ""; + + analyzer_base_args += " --analyze"; + + var vc_ver; + if (VS_TOOLSET) { + vc_ver = VCVERS; + } else { + vc_ver = probe_binary(PATH_PROG('cl', null)); + } + + analyzer_base_args += " -fms-compatibility -fms-compatibility-version=" + vc_ver + " -fms-extensions"; + } else if (PHP_ANALYZER == "cppcheck") { + var analyzer_base_args = ""; + var analyzer_base_flags = ""; + + if (VS_TOOLSET) { + analyzer_base_flags += " -D _MSC_VER=" + VCVERS; + } else { + analyzer_base_flags += " -D _MSC_VER=" + probe_binary(PATH_PROG('cl', null)); + } + + if (X64) { + analyzer_base_flags += " -D _M_X64 -D _WIN64"; + } else { + analyzer_base_flags += " -D _M_IX86 "; + } + analyzer_base_flags += " -D _WIN32 -D WIN32 -D _WINDOWS"; + + var vc_incs = WshShell.Environment("Process").Item("INCLUDE").split(";") + for (i in vc_incs) { + analyzer_base_flags += " -I " + "\"" + vc_incs[i] + "\""; + } + + var cppcheck_platform = X64 ? "win64" : "win32A"; + var cppcheck_lib = "win32\\build\\cppcheck_" + (X64 ? "x64" : "x86") + ".cfg"; + analyzer_base_args += "--enable=warning,performance,portability,information,missingInclude " + + "--platform=" + cppcheck_platform + " " + + "--library=windows.cfg --library=microsoft_sal.cfg " + + "--library=win32\\build\\cppcheck.cfg " + + "--library=" + cppcheck_lib + " " + + /* "--rule-file=win32\build\cppcheck_rules.xml " + */ + " --std=c89 --std=c++11 " + + "--quiet --inconclusive --template=vs "; + } + 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); + + if ("clang" == PHP_ANALYZER) { + MFO.WriteLine("\t\"@$(CLANG_CL)\" " + analyzer_base_args + " $(" + flags + "_ANALYZER) $(CFLAGS_ANALYZER) $(" + bd_flags_name + "_ANALYZER) " + dir + "\\" + src); + } else if ("cppcheck" == PHP_ANALYZER) { + MFO.WriteLine("\t\"@$(CPPCHECK)\" " + analyzer_base_args + " $(" + flags + "_ANALYZER) $(CFLAGS_ANALYZER) $(" + bd_flags_name + "_ANALYZER) " + analyzer_base_flags + " " + dir + "\\" + src); + }else 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\" "); + } } } else { /* TODO create a response file at least for the source files to work around the cmd line length limit. */ @@ -1548,6 +1601,12 @@ function ADD_SOURCES(dir, file_list, target, obj_dir) } MFO.WriteLine("\t$(CC) $(" + flags + ") $(CFLAGS) /Fo" + sub_build + d + " $(" + bd_flags_name + ") /c " + src_line); + + if ("clang" == PHP_ANALYZER) { + MFO.WriteLine("\t\"$(CLANG_CL)\" " + analyzer_base_args + " $(" + flags + "_ANALYZER) $(CFLAGS_ANALYZER) $(" + bd_flags_name + "_ANALYZER) " + src_line); + } else if ("cppcheck" == PHP_ANALYZER) { + MFO.WriteLine("\t\"$(CPPCHECK)\" " + analyzer_base_args + " $(" + flags + "_ANALYZER) $(CFLAGS_ANALYZER) $(" + bd_flags_name + "_ANALYZER) " + analyzer_base_flags + " " + src_line); + } } } @@ -1729,6 +1788,10 @@ function write_summary() } if (PHP_ANALYZER == "vs") { ar[5] = ['Static analyzer', 'Visual Studio']; + } else if (PHP_ANALYZER == "clang") { + ar[5] = ['Static analyzer', 'clang']; + } else if (PHP_ANALYZER == "cppcheck") { + ar[5] = ['Static analyzer', 'Cppcheck']; } else if (PHP_ANALYZER == "pvs") { ar[5] = ['Static analyzer', 'PVS-Studio']; } else { @@ -2057,6 +2120,124 @@ function generate_phpize() CJ.Close(); } +function extract_convert_style_line(val, match_sw, to_sw, keep_mkfile_vars) +{ + var ret = ""; + + /*var re = new RegExp(match_sw + "(.*)", "g"); + var r; + + while (r = re.execute(val)) { + WARNING(r); + } + return ret;*/ + + var cf = val.replace(/\s+/g, " ").split(" "); + + var i_val = false; + for (var i in cf) { + var r; + + if (keep_mkfile_vars) { + r = cf[i].match(/^\$\((.*)\)/); + if (!!r) { + ret += " " + r[0]; + continue; + } + } + + if (i_val && !!cf[i]) { + i_val = false; + ret += " " + to_sw + " " + cf[i]; + continue; + } + + var re; + + re = new RegExp(match_sw + "(.*)"); + r = cf[i].match(re); + if (!!r && r.length > 1 && !!r[1]) { + /* The value is not ws separated from the switch. */ + ret += " " + to_sw + " " + r[1]; + continue; + } + + r = cf[i].match(match_sw); + if (!!r) { + //WARNING(cf[i]); + /* Value is going to be added in the next iteration. */ + i_val = true; + } + } + + return ret; +} + +function handle_analyzer_makefile_flags(fd, key, val) +{ + var relevant = false; + + /* VS integrates /analyze with the bulid process, + no further action is required. */ + if ("no" == PHP_ANALYZER || "vs" == PHP_ANALYZER) { + return; + } + + if (key.match("CFLAGS")) { + var new_val = val; + var reg = /\$\(([^\)]+)\)/g; + var r; + while (r = reg.exec(val)) { + var repl = "$(" + r[1] + "_ANALYZER)" + new_val = new_val.replace(r[0], repl); + } + val = new_val; + + if ("clang" == PHP_ANALYZER) { + val = val.replace(/\/FD /, "") + .replace(/\/Fp.+? /, "") + .replace(/\/Fo.+? /, "") + .replace(/\/Fd.+? /, "") + //.replace(/\/Fd.+?/, " ") + .replace(/\/FR.+? /, "") + .replace("/guard:cf ", "") + .replace(/\/MP \d+ /, "") + .replace(/\/MP /, "") + .replace("/LD ", ""); + } else if ("cppcheck" == PHP_ANALYZER) { + new_val = ""; + + new_val += extract_convert_style_line(val, "/I", "-I", true); + new_val += extract_convert_style_line(val, "/D", "-D", false); + + val = new_val; + } + + relevant = true; + } else if (key.match("BASE_INCLUDES")) { + if ("cppcheck" == PHP_ANALYZER) { + new_val = ""; + + new_val += extract_convert_style_line(val, "/I", "-I", true); + new_val += extract_convert_style_line(val, "/D", "-D", false); + + val = new_val; + } + + relevant = true; + } + + if (!relevant) { + return; + } + + key += "_ANALYZER"; + //WARNING("KEY: " + key + " VAL: " + val); + + fd.WriteLine(key + "=" + val + " "); + fd.WriteBlankLines(1); +} + /* Generate the Makefile */ function generate_makefile() { @@ -2072,12 +2253,16 @@ function generate_makefile() // The trailing space is needed to prevent the trailing backslash // that is part of the build dir flags (CFLAGS_BD_XXX) from being // seen as a line continuation character - MF.WriteLine(keys[i] + "=" + - /* \s+\/ eliminates extra whitespace caused when using \ for string continuation, - whereby \/ is the start of the next compiler switch */ - trim(configure_subst.Item(keys[i])).replace(/\s+\//gm, " /") + " " - ); + + /* \s+\/ eliminates extra whitespace caused when using \ for string continuation, + whereby \/ is the start of the next compiler switch */ + var val = trim(configure_subst.Item(keys[i])).replace(/\s+\//gm, " /"); + + MF.WriteLine(keys[i] + "=" + val + " "); MF.WriteBlankLines(1); + + /* If static analyze is enabled, add analyzer specific stuff to the Makefile. */ + handle_analyzer_makefile_flags(MF, keys[i], val); } MF.WriteBlankLines(1); @@ -2714,7 +2899,7 @@ function toolset_setup_common_cflags() ADD_FLAG("CFLAGS", " /fallback "); var vc_ver = probe_binary(PATH_PROG('cl', null)); - ADD_FLAG("CFLAGS", "-fms-compatibility-version=" + vc_ver); + ADD_FLAG("CFLAGS"," -fms-compatibility -fms-compatibility-version=" + vc_ver + " -fms-extensions"); } } diff --git a/win32/build/cppcheck.cfg b/win32/build/cppcheck.cfg new file mode 100644 index 00000000000..328680aa537 --- /dev/null +++ b/win32/build/cppcheck.cfg @@ -0,0 +1,430 @@ + + + + + false + + + + false + + + + false + + + + + + + false + + + + + + + + + + + + + false + + + + + + + + + + false + + + + + + false + + + + + + false + + + + false + + + + + + + + + + false + + + + false + + + + false + + + + false + + + + false + + + false + + + + + false + + + + + + + false + + + + + + + + false + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _emalloc + _safe_emalloc + _ecalloc + _estrdup + _estrndup + _efree + + + _emalloc_large + _efree_large + + + _emalloc_huge + _efree_huge + + + __zend_malloc + __zend_calloc + _safe_malloc + zend_strndup + free + + + _zend_mm_malloc + _zend_mm_calloc + _zend_mm_free + + + + true + + + + true + + + + true + + + + true + + + + true + + + + + false + + + + + + + + + + false + + + + + + + + false + + + + + + false + + + + + + + + + + + + + false + + + + zend_str_alloc + zend_str_free + + + false + + + + + + + false + + + + + + + + _php_stream_alloc + _php_stream_free + + + false + + + false + + + false + + + + + + + false + + + + + + + zend_init_rsrc_list + zend_init_rsrc_plist + zend_close_rsrc_plist + zend_destroy_rsrc_plist + + + false + + + false + + + zend_init_rsrc_list_dtors + zend_destroy_rsrc_list_dtors + + + false + + + + + + + + false + + + + + + + zend_list_insert + zend_list_close + + diff --git a/win32/build/cppcheck_x64.cfg b/win32/build/cppcheck_x64.cfg new file mode 100644 index 00000000000..4c221a6fcd3 --- /dev/null +++ b/win32/build/cppcheck_x64.cfg @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/win32/build/cppcheck_x86.cfg b/win32/build/cppcheck_x86.cfg new file mode 100644 index 00000000000..a7934704fc5 --- /dev/null +++ b/win32/build/cppcheck_x86.cfg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/win32/codepage.c b/win32/codepage.c index d9291305bce..cddd94687de 100644 --- a/win32/codepage.c +++ b/win32/codepage.c @@ -35,7 +35,7 @@ __forceinline static wchar_t *php_win32_cp_to_w_int(const char* in, size_t in_le SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); return NULL; } - assert(in_len ? in[in_len] == L'\0' : 1); + assert(in_len ? (in[in_len] == L'\0') : 1); tmp_len = !in_len ? -1 : (int)in_len + 1; diff --git a/win32/ioutil.c b/win32/ioutil.c index b661a150af5..8f851401702 100644 --- a/win32/ioutil.c +++ b/win32/ioutil.c @@ -193,7 +193,7 @@ PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...) int fd; mode_t mode = 0; - PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0) if (flags & O_CREAT) { va_list arg; @@ -291,7 +291,7 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode) int ret = 0; DWORD err = 0; - PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0) /* TODO extend with mode usage */ if (!CreateDirectoryW(path, NULL)) { @@ -316,7 +316,7 @@ PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) if (!CreateDirectoryW(pathw, NULL)) { err = GetLastError(); @@ -336,7 +336,7 @@ PW32IO int php_win32_ioutil_unlink_w(const wchar_t *path) int ret = 0; DWORD err = 0; - PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0) if (!DeleteFileW(path)) { err = GetLastError(); @@ -352,7 +352,7 @@ PW32IO int php_win32_ioutil_rmdir_w(const wchar_t *path) int ret = 0; DWORD err = 0; - PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0) if (!RemoveDirectoryW(path)) { err = GetLastError(); @@ -382,8 +382,8 @@ PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newn int ret = 0; DWORD err = 0; - PHP_WIN32_IOUTIL_CHECK_PATH_W(oldname, -1) - PHP_WIN32_IOUTIL_CHECK_PATH_W(newname, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(oldname, -1, 0) + PHP_WIN32_IOUTIL_CHECK_PATH_W(newname, -1, 0) if (!MoveFileExW(oldname, newname, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)) { @@ -425,6 +425,7 @@ PW32IO wchar_t *php_win32_ioutil_getcwd_w(const wchar_t *buf, int len) if (!GetCurrentDirectoryW(len, buf)) { err = GetLastError(); SET_ERRNO_FROM_WIN32_CODE(err); + free(tmp_buf); return NULL; } @@ -466,6 +467,7 @@ PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len) endw--; } if (endw < pathw) { + free(startw); /* The path only contained slashes */ path[0] = PHP_WIN32_IOUTIL_DEFAULT_SLASH; path[1] = '\0'; @@ -477,6 +479,7 @@ PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len) endw--; } if (endw < pathw) { + free(startw); path[0] = '.'; path[1] = '\0'; return 1 + len_adjust; @@ -487,6 +490,7 @@ PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len) endw--; } if (endw < pathw) { + free(startw); path[0] = PHP_WIN32_IOUTIL_DEFAULT_SLASH; path[1] = '\0'; return 1 + len_adjust; diff --git a/win32/ioutil.h b/win32/ioutil.h index ea40db4c663..15c8f0e3395 100644 --- a/win32/ioutil.h +++ b/win32/ioutil.h @@ -128,11 +128,15 @@ typedef enum { pathw = php_win32_ioutil_any_to_w(path); \ } while (0); -#define PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, ret) do { \ - size_t len = wcslen(pathw); \ - if (len >= 1 && L' ' == pathw[len-1] || \ - len > 1 && !PHP_WIN32_IOUTIL_IS_SLASHW(pathw[len-2]) && L'.' != pathw[len-2] && L'.' == pathw[len-1] \ - ) { \ +#define PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, len) \ + (!((len) >= 1 && L' ' == pathw[(len)-1] || \ + (len) > 1 && !PHP_WIN32_IOUTIL_IS_SLASHW(pathw[(len)-2]) && L'.' != pathw[(len)-2] && L'.' == pathw[(len)-1])) + +#define PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, ret, dealloc) do { \ + if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, wcslen(pathw))) { \ + if (dealloc) { \ + free(pathw); \ + } \ SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED); \ return ret; \ } \ @@ -237,7 +241,7 @@ __forceinline static int php_win32_ioutil_access(const char *path, mode_t mode) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) ret = _waccess(pathw, mode); _get_errno(&err); @@ -262,7 +266,7 @@ __forceinline static int php_win32_ioutil_open(const char *path, int flags, ...) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) if (flags & O_CREAT) { va_list arg; @@ -294,7 +298,7 @@ __forceinline static int php_win32_ioutil_unlink(const char *path) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) if (!DeleteFileW(pathw)) { err = GetLastError(); @@ -320,7 +324,7 @@ __forceinline static int php_win32_ioutil_rmdir(const char *path) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) if (!RemoveDirectoryW(pathw)) { err = GetLastError(); @@ -342,18 +346,24 @@ fdopen() might be the way, if we learn how to convert the mode options (maybe gr __forceinline static FILE *php_win32_ioutil_fopen(const char *patha, const char *modea) {/*{{{*/ FILE *ret; - wchar_t *pathw = php_win32_ioutil_any_to_w(patha); - wchar_t *modew = php_win32_ioutil_ascii_to_w(modea); + wchar_t *pathw; + wchar_t *modew; int err = 0; - if (!pathw || !modew) { - free(pathw); - free(modew); + pathw = php_win32_ioutil_any_to_w(patha); + if (!pathw) { SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); return NULL; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, NULL) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, NULL, 1) + + modew = php_win32_ioutil_ascii_to_w(modea); + if (!modew) { + free(pathw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return NULL; + } ret = _wfopen(pathw, modew); _get_errno(&err); @@ -368,20 +378,29 @@ __forceinline static FILE *php_win32_ioutil_fopen(const char *patha, const char __forceinline static int php_win32_ioutil_rename(const char *oldnamea, const char *newnamea) {/*{{{*/ - wchar_t *oldnamew = php_win32_ioutil_any_to_w(oldnamea); - wchar_t *newnamew = php_win32_ioutil_any_to_w(newnamea); + wchar_t *oldnamew; + wchar_t *newnamew; int ret; DWORD err = 0; - if (!oldnamew || !newnamew) { - free(oldnamew); - free(newnamew); + oldnamew = php_win32_ioutil_any_to_w(oldnamea); + if (!oldnamew) { SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); return -1; } + PHP_WIN32_IOUTIL_CHECK_PATH_W(oldnamew, -1, 1) - PHP_WIN32_IOUTIL_CHECK_PATH_W(oldnamew, -1) - PHP_WIN32_IOUTIL_CHECK_PATH_W(newnamew, -1) + newnamew = php_win32_ioutil_any_to_w(newnamea); + if (!newnamew) { + free(oldnamew); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } else if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(newnamew, wcslen(newnamew))) { + free(oldnamew); + free(newnamew); + SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED); + return -1; + } ret = php_win32_ioutil_rename_w(oldnamew, newnamew); err = GetLastError(); @@ -471,7 +490,7 @@ __forceinline static int php_win32_ioutil_chmod(const char *patha, int mode) return -1; } - PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1) + PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1) ret = _wchmod(pathw, mode); _get_errno(&err); diff --git a/win32/readdir.c b/win32/readdir.c index 35afea429bc..4a6d65932f6 100644 --- a/win32/readdir.c +++ b/win32/readdir.c @@ -54,12 +54,14 @@ DIR *opendir(const char *dir) resolvedw = php_win32_ioutil_conv_any_to_w(resolved_path_buff, PHP_WIN32_CP_IGNORE_LEN, &resolvedw_len); if (!resolvedw) { + free(dp); return NULL; } filespecw_len = resolvedw_len + 2; filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t)); if (filespecw == NULL) { + free(dp); free(resolvedw); return NULL; }