diff --git a/NEWS b/NEWS index cb70bda237ff..d90af7f5e64d 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,13 @@ PHP NEWS error handler instead of emitting a warning and continuing with an empty string. (Weilin Du) +- Standard: + . The following functions now raise a ValueError when the $filename argument + contains NUL bytes: fileperms(), fileinode(), filesize(), fileowner(), + filegroup(), fileatime(), filemtime(), filectime(), filetype(), + is_writable(), is_readable(), is_executable(), is_file(), is_dir(), + is_link(), file_exists(), lstat(), stat(). (Girgias) + 30 Jul 2026, PHP 8.6.0alpha3 - Core: diff --git a/UPGRADING b/UPGRADING index 599ae2290d6e..b516f24db97f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -228,6 +228,26 @@ PHP 8.6 UPGRADE NOTES bytes. . base_convert(), bindex(), hexdec() and octdec() now raise a notice when they cannot precisely convert the given number. + . The following functions now raise a ValueError when the $filename argument + contains NUL bytes: + - fileperms() + - fileinode() + - filesize() + - fileowner() + - filegroup() + - fileatime() + - filemtime() + - filectime() + - filetype() + - is_writable() + - is_readable() + - is_executable() + - is_file() + - is_dir() + - is_link() + - file_exists() + - lstat() + - stat() - Sysvshm: . shm_attach() now raises a ValueError when the $key argument is outside the diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 2a9353c9b86e..88d012149beb 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -419,7 +419,6 @@ static const func_info_t func_infos[] = { #if defined(HAVE_NANOSLEEP) F1("time_nanosleep", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_BOOL), #endif - F1("get_current_user", MAY_BE_STRING), FN("get_cfg_var", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE), F1("error_get_last", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_NULL), F1("highlight_file", MAY_BE_STRING|MAY_BE_BOOL), diff --git a/Zend/tests/arginfo_zpp_mismatch.phpt b/Zend/tests/arginfo_zpp_mismatch.phpt index d7aefc6f374f..94f6b070900e 100644 --- a/Zend/tests/arginfo_zpp_mismatch.phpt +++ b/Zend/tests/arginfo_zpp_mismatch.phpt @@ -10,6 +10,36 @@ if (getenv('SKIP_MSAN')) die("skip msan misses interceptors for some functions") require __DIR__ . "/arginfo_zpp_mismatch.inc"; +function testWeakSysvIpcFunction($function): bool { + if (!in_array($function, ['msg_queue_exists', 'msg_get_queue', 'sem_get', 'shm_attach'], true)) { + return false; + } + + for ($argumentCount = 0; $argumentCount <= 8; $argumentCount++) { + $arguments = array_fill(0, $argumentCount, null); + if ($function === 'msg_queue_exists' && $argumentCount >= 1) { + $arguments[0] = 1; + } + if (($function === 'sem_get' || $function === 'shm_attach') && $argumentCount >= 3) { + $arguments[2] = 0600; + } + + try { + $result = @$function(...$arguments); + if ($result instanceof SysvMessageQueue) { + msg_remove_queue($result); + } elseif ($result instanceof SysvSemaphore) { + sem_remove($result); + } elseif ($result instanceof SysvSharedMemory) { + shm_remove($result); + } + } catch (Throwable) { + } + } + + return true; +} + function test($function) { if (skipFunction($function)) { return; @@ -21,6 +51,10 @@ function test($function) { } else { echo "Testing " . get_class($function[0]) . "::$function[1]\n"; } + if (testWeakSysvIpcFunction($function)) { + ob_end_clean(); + return; + } try { @$function(); } catch (Throwable) { diff --git a/Zend/tests/partial_application/constexpr_015.phpt b/Zend/tests/partial_application/constexpr_015.phpt index 2449adb9e4b7..22bc8dc720e8 100644 --- a/Zend/tests/partial_application/constexpr_015.phpt +++ b/Zend/tests/partial_application/constexpr_015.phpt @@ -5,6 +5,7 @@ opcache.enable=1 opcache.enable_cli=1 opcache.optimization_level=-1 opcache.preload={PWD}/constexpr_015.inc +opcache.file_cache_only=0 --SKIPIF-- size = 0; - fcc->function_handler = 0; - break; - } - - if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error) == SUCCESS) { + if (EXPECTED(zend_parse_arg_func(arg, fci, fcc, check_null, &is_callable_error, c == 'f'))) { ZEND_ASSERT(!is_callable_error); - if (c == 'f') { - /* Release call trampolines: The function may not get called, in which case - * the trampoline will leak. Force it to be refetched during - * zend_call_function instead. */ - zend_release_fcall_info_cache(fcc); - } break; } diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 22af1c15a833..b8ae31040c8b 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -269,6 +269,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, if (EG(exception)) { PHP_JSON_HASH_UNPROTECT_RECURSION(recursion_rc); zend_release_properties(prop_ht); + zval_ptr_dtor(&tmp); return FAILURE; } } diff --git a/ext/json/tests/json_encode_hooked_property_throwing_getter.phpt b/ext/json/tests/json_encode_hooked_property_throwing_getter.phpt new file mode 100644 index 000000000000..63fc8cf42c0e --- /dev/null +++ b/ext/json/tests/json_encode_hooked_property_throwing_getter.phpt @@ -0,0 +1,44 @@ +--TEST-- +json_encode() releases the hooked property value when the get hook throws +--FILE-- +getMessage(), "\n"; +} + +echo "done\n"; + +?> +--EXPECT-- +Value::__destruct +Exception: thrown while freeing the get hook frame +done diff --git a/ext/mysqli/tests/bug36802.phpt b/ext/mysqli/tests/bug36802.phpt index 47642087acb3..fdfc37d862be 100644 --- a/ext/mysqli/tests/bug36802.phpt +++ b/ext/mysqli/tests/bug36802.phpt @@ -18,7 +18,7 @@ mysqli try { $mysql->set_charset('utf8'); } catch (Error $exception) { - echo $exception->getMessage() . "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } } else { $x[0] = false; @@ -27,7 +27,7 @@ mysqli try { $mysql->query("SELECT 'foo' FROM DUAL"); } catch (Error $exception) { - echo $exception->getMessage() . "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } /* following operations should work */ @@ -39,8 +39,8 @@ mysqli var_dump($x); ?> --EXPECT-- -mysqli object is not fully initialized -mysqli object is not fully initialized +Error: mysqli object is not fully initialized +Error: mysqli object is not fully initialized array(2) { [1]=> string(0) "" diff --git a/ext/mysqli/tests/bug62885.phpt b/ext/mysqli/tests/bug62885.phpt index 8666795bd87c..9d2585b2fce7 100644 --- a/ext/mysqli/tests/bug62885.phpt +++ b/ext/mysqli/tests/bug62885.phpt @@ -13,19 +13,19 @@ $tablica = array(); try { $test1 = mysqli_poll($test2, $test3, $tablica, 0); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } $test2 = array(); try { $test1 = mysqli_poll($test2, $test3, $tablica, 0); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } echo "okey"; ?> --EXPECTF-- -No stream arrays were passed +ValueError: No stream arrays were passed Warning: mysqli_poll(): No stream arrays were passed in %s on line %d okey diff --git a/ext/mysqli/tests/gh17900.phpt b/ext/mysqli/tests/gh17900.phpt index ed099fa7e852..90aa3d7edfe0 100644 --- a/ext/mysqli/tests/gh17900.phpt +++ b/ext/mysqli/tests/gh17900.phpt @@ -9,8 +9,8 @@ $mysqli = new mysqli(); try { $mysqli->__construct('doesnotexist'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot call constructor twice +Error: Cannot call constructor twice diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt index 666f47f4199f..84c38dd862db 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt @@ -18,7 +18,7 @@ try { $info = mysqli_info($conn); var_dump($info); } catch (Exception $e) { - echo $e->getMessage() . PHP_EOL; + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } $process->terminate(); @@ -33,5 +33,5 @@ print "done!"; [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d -Unknown error while trying to connect via tcp://127.0.0.1:%d +mysqli_sql_exception: Unknown error while trying to connect via tcp://127.0.0.1:%d done! diff --git a/ext/mysqli/tests/mysqli_driver/write_property.phpt b/ext/mysqli/tests/mysqli_driver/write_property.phpt index 456dd40c81df..7bb41440b39f 100644 --- a/ext/mysqli/tests/mysqli_driver/write_property.phpt +++ b/ext/mysqli/tests/mysqli_driver/write_property.phpt @@ -10,7 +10,7 @@ try { /* Read-only property */ $driver->client_info = 'test'; } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $driver->report_mode = "1"; @@ -18,11 +18,11 @@ var_dump($driver->report_mode); try { $driver->report_mode = []; } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot write read-only property mysqli_driver::$client_info +Error: Cannot write read-only property mysqli_driver::$client_info int(1) -Cannot assign array to property mysqli_driver::$report_mode of type int +TypeError: Cannot assign array to property mysqli_driver::$report_mode of type int diff --git a/ext/mysqli/tests/mysqli_driver/write_property_strict.phpt b/ext/mysqli/tests/mysqli_driver/write_property_strict.phpt index 41645ff61c28..996048ac1f34 100644 --- a/ext/mysqli/tests/mysqli_driver/write_property_strict.phpt +++ b/ext/mysqli/tests/mysqli_driver/write_property_strict.phpt @@ -12,16 +12,16 @@ try { /* Read-only property */ $driver->client_info = 42; } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $driver->report_mode = "1"; } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot write read-only property mysqli_driver::$client_info -Cannot assign string to property mysqli_driver::$report_mode of type int +Error: Cannot write read-only property mysqli_driver::$client_info +TypeError: Cannot assign string to property mysqli_driver::$report_mode of type int diff --git a/ext/mysqli/tests/mysqli_driver_unclonable.phpt b/ext/mysqli/tests/mysqli_driver_unclonable.phpt index 7041a024f67c..94065a1379df 100644 --- a/ext/mysqli/tests/mysqli_driver_unclonable.phpt +++ b/ext/mysqli/tests/mysqli_driver_unclonable.phpt @@ -9,7 +9,7 @@ try { $driver = new mysqli_driver; $driver_clone = clone $driver; } catch (Throwable $e) { - echo $e::class, ": ", $e->getMessage(), PHP_EOL; + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } ?> diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 77d73a2326d7..c6e53c408aa8 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -3179,8 +3179,7 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl) unsigned char digest[16]; size_t len = strlen(SOAP_GLOBAL(cache_dir)); time_t cached; - char *user = php_get_current_user(); - size_t user_len = user ? strlen(user) + 1 : 0; + zend_string *user = php_get_current_user(); /* System architecture identification (see bug #70951) */ static const char ids[] = {SIZEOF_ZEND_LONG, SOAP_BIG_ENDIAN}; @@ -3191,13 +3190,13 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl) PHP_MD5Update(&md5_context, ids, sizeof(ids)); PHP_MD5Final(digest, &md5_context); make_digest(md5str, digest); - key = emalloc(len+sizeof("/wsdl-")-1+user_len+2+sizeof(md5str)); + key = emalloc(len+sizeof("/wsdl-")-1+ZSTR_LEN(user)+1+2+sizeof(md5str)); memcpy(key,SOAP_GLOBAL(cache_dir),len); memcpy(key+len,"/wsdl-",sizeof("/wsdl-")-1); len += sizeof("/wsdl-")-1; - if (user_len) { - memcpy(key+len, user, user_len-1); - len += user_len-1; + if (ZSTR_LEN(user)) { + memcpy(key+len, ZSTR_VAL(user), ZSTR_LEN(user)); + len += ZSTR_LEN(user); key[len++] = '-'; } if (WSDL_CACHE_VERSION <= 0x9f) { diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index e81050323754..a87ab1b5ad62 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1255,7 +1255,7 @@ PHP_FUNCTION(get_current_user) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_STRING(php_get_current_user()); + RETURN_STR_COPY(php_get_current_user()); } /* }}} */ @@ -1434,7 +1434,7 @@ PHP_FUNCTION(error_get_last) ZVAL_STR_COPY(&tmp, PG(last_error_file)); zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp); - ZVAL_LONG(&tmp, PG(last_error_lineno)); + ZVAL_LONG(&tmp, (zend_long)PG(last_error_lineno)); zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); if (!Z_ISUNDEF(EG(last_fatal_error_backtrace))) { diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 7fc31e7d80ca..07e61957d191 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1976,7 +1976,6 @@ function time_nanosleep(int $seconds, int $nanoseconds): array|bool {} function time_sleep_until(float $timestamp): bool {} #endif -/** @refcount 1 */ function get_current_user(): string {} /** @return string|array|false */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index c5266c5a877c..d24de1fef99d 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 3b1649a3abb3cfb5cb39d93f30a97765fe862d67 + * Stub hash: 0c8af3b78b3d6e1ee3e59c60363d0d941bea9faa * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 630a4b7e656b..97d896e8bb6e 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 3b1649a3abb3cfb5cb39d93f30a97765fe862d67 */ + * Stub hash: 0c8af3b78b3d6e1ee3e59c60363d0d941bea9faa */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_3b1649a3abb3cfb5cb39d93f30a97765fe862d67_H -#define ZEND_BASIC_FUNCTIONS_DECL_3b1649a3abb3cfb5cb39d93f30a97765fe862d67_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_0c8af3b78b3d6e1ee3e59c60363d0d941bea9faa_H +#define ZEND_BASIC_FUNCTIONS_DECL_0c8af3b78b3d6e1ee3e59c60363d0d941bea9faa_H typedef enum zend_enum_SortDirection { ZEND_ENUM_SortDirection_Ascending = 1, @@ -20,4 +20,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_3b1649a3abb3cfb5cb39d93f30a97765fe862d67_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_0c8af3b78b3d6e1ee3e59c60363d0d941bea9faa_H */ diff --git a/ext/standard/filestat.c b/ext/standard/filestat.c index 7dcfecf1f872..96669a809346 100644 --- a/ext/standard/filestat.c +++ b/ext/standard/filestat.c @@ -730,14 +730,12 @@ PHPAPI void php_stat(zend_string *filename, int type, zval *return_value) const char *local = NULL; php_stream_wrapper *wrapper = NULL; + ZEND_ASSERT(!zend_str_has_nul_byte(filename)); + /* Quick check for empty file paths */ + if (!ZSTR_LEN(filename)) { + RETURN_FALSE; + } if (IS_ACCESS_CHECK(type)) { - if (!ZSTR_LEN(filename) || zend_str_has_nul_byte(filename)) { - if (ZSTR_LEN(filename) && !IS_EXISTS_CHECK(type)) { - php_error_docref(NULL, E_WARNING, "Filename contains null byte"); - } - RETURN_FALSE; - } - if ((wrapper = php_stream_locate_url_wrapper(ZSTR_VAL(filename), &local, 0)) == &php_plain_files_wrapper && php_check_open_basedir(local)) { RETURN_FALSE; @@ -799,13 +797,6 @@ PHPAPI void php_stat(zend_string *filename, int type, zval *return_value) } if (!wrapper) { - if (!ZSTR_LEN(filename) || zend_str_has_nul_byte(filename)) { - if (ZSTR_LEN(filename) && !IS_EXISTS_CHECK(type)) { - php_error_docref(NULL, E_WARNING, "Filename contains null byte"); - } - RETURN_FALSE; - } - if ((wrapper = php_stream_locate_url_wrapper(ZSTR_VAL(filename), &local, 0)) == &php_plain_files_wrapper && php_check_open_basedir(local)) { RETURN_FALSE; @@ -996,7 +987,7 @@ ZEND_NAMED_FUNCTION(name) { \ zend_string *filename; \ \ ZEND_PARSE_PARAMETERS_START(1, 1) \ - Z_PARAM_STR(filename) \ + Z_PARAM_PATH_STR(filename) \ ZEND_PARSE_PARAMETERS_END(); \ \ php_stat(filename, funcnum, return_value); \ diff --git a/ext/standard/tests/file/bug36365.phpt b/ext/standard/tests/file/bug36365.phpt index be1a6c516555..c3aeb8045d6e 100644 --- a/ext/standard/tests/file/bug36365.phpt +++ b/ext/standard/tests/file/bug36365.phpt @@ -2,6 +2,7 @@ Bug #36365 (scandir duplicates file name at every 65535th file) --SKIPIF-- --FILE-- diff --git a/ext/standard/tests/file/bug39863.phpt b/ext/standard/tests/file/bug39863.phpt index 88c569473a76..2a0ca01ea65a 100644 --- a/ext/standard/tests/file/bug39863.phpt +++ b/ext/standard/tests/file/bug39863.phpt @@ -6,7 +6,11 @@ Andrew van der Stock, vanderaj @ owasp.org getMessage(), PHP_EOL; +} ?> --EXPECT-- -bool(false) +ValueError: file_exists(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/filegroup_null_byte.phpt b/ext/standard/tests/file/filegroup_null_byte.phpt new file mode 100644 index 000000000000..4cb80399c61d --- /dev/null +++ b/ext/standard/tests/file/filegroup_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +filegroup() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: filegroup(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/filegroup_variation3.phpt b/ext/standard/tests/file/filegroup_variation3.phpt index e844be077212..94562850f58d 100644 --- a/ext/standard/tests/file/filegroup_variation3.phpt +++ b/ext/standard/tests/file/filegroup_variation3.phpt @@ -26,10 +26,6 @@ $files_arr = array( "//filegroup_variation3//filegroup_variation3.tmp", "/filegroup_variation3/*.tmp", "filegroup_variation3/filegroup*.tmp", - - /* Testing Binary safe */ - "/filegroup_variation3/filegroup_variation3.tmp".chr(0), - "/filegroup_variation3/filegroup_variation3.tmp\0" ); $count = 1; @@ -74,13 +70,5 @@ bool(false) Warning: filegroup(): stat failed for %s/filegroup_variation3/filegroup*.tmp in %s on line %d bool(false) -- Iteration 7 - - -Warning: filegroup(): Filename contains null byte in %s on line %d -bool(false) -- Iteration 8 - - -Warning: filegroup(): Filename contains null byte in %s on line %d -bool(false) *** Done *** diff --git a/ext/standard/tests/file/fileinode_null_byte.phpt b/ext/standard/tests/file/fileinode_null_byte.phpt new file mode 100644 index 000000000000..48b8272d97cf --- /dev/null +++ b/ext/standard/tests/file/fileinode_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +fileinode() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: fileinode(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/fileinode_variation3.phpt b/ext/standard/tests/file/fileinode_variation3.phpt index 92357a3619e8..506984d41775 100644 --- a/ext/standard/tests/file/fileinode_variation3.phpt +++ b/ext/standard/tests/file/fileinode_variation3.phpt @@ -25,10 +25,6 @@ $files_arr = array( "//fileinode_variation3//fileinode_variation3.tmp", "/fileinode_variation3/*.tmp", "fileinode_variation3/fileinode*.tmp", - - /* Testing Binary safe */ - "/fileinode_variation3/fileinode_variation3.tmp".chr(0), - "/fileinode_variation3/fileinode_variation3.tmp\0" ); $count = 1; @@ -73,13 +69,5 @@ bool(false) Warning: fileinode(): stat failed for %s/fileinode_variation3/fileinode*.tmp in %s on line %d bool(false) -- Iteration 7 - - -Warning: fileinode(): Filename contains null byte in %s on line %d -bool(false) -- Iteration 8 - - -Warning: fileinode(): Filename contains null byte in %s on line %d -bool(false) *** Done *** diff --git a/ext/standard/tests/file/fileowner_null_byte.phpt b/ext/standard/tests/file/fileowner_null_byte.phpt new file mode 100644 index 000000000000..909ac0fe3109 --- /dev/null +++ b/ext/standard/tests/file/fileowner_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +fileowner() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: fileowner(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/fileowner_variation3.phpt b/ext/standard/tests/file/fileowner_variation3.phpt index 63ba6936aaa8..e6360b475713 100644 --- a/ext/standard/tests/file/fileowner_variation3.phpt +++ b/ext/standard/tests/file/fileowner_variation3.phpt @@ -26,10 +26,6 @@ $files_arr = array( "//fileowner_variation3//fileowner_variation3.tmp", "/fileowner_variation3/*.tmp", "fileowner_variation3/fileowner*.tmp", - - /* Testing Binary safe */ - "/fileowner_variation3/fileowner_variation3.tmp".chr(0), - "/fileowner_variation3/fileowner_variation3.tmp\0" ); $count = 1; @@ -74,13 +70,5 @@ bool(false) Warning: fileowner(): stat failed for %s/fileowner_variation3/fileowner*.tmp in %s on line %d bool(false) -- Iteration 7 - - -Warning: fileowner(): Filename contains null byte in %s on line %d -bool(false) -- Iteration 8 - - -Warning: fileowner(): Filename contains null byte in %s on line %d -bool(false) *** Done *** diff --git a/ext/standard/tests/file/fileperms_null_byte.phpt b/ext/standard/tests/file/fileperms_null_byte.phpt new file mode 100644 index 000000000000..1530d0e5bf9f --- /dev/null +++ b/ext/standard/tests/file/fileperms_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +fileperms() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: fileperms(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/fileperms_variation3.phpt b/ext/standard/tests/file/fileperms_variation3.phpt index 5e981e9b8632..6c1da17d6bfd 100644 --- a/ext/standard/tests/file/fileperms_variation3.phpt +++ b/ext/standard/tests/file/fileperms_variation3.phpt @@ -25,10 +25,6 @@ $files_arr = array( "//fileperms_variation3//fileperms_variation3.tmp", "/fileperms_variation3/*.tmp", "fileperms_variation3/fileperms*.tmp", - - /* Testing Binary safe */ - "/fileperms_variation3/fileperms_variation3.tmp".chr(0), - "/fileperms_variation3/fileperms_variation3.tmp\0" ); $count = 1; @@ -73,13 +69,5 @@ bool(false) Warning: fileperms(): stat failed for %s/fileperms_variation3/fileperms*.tmp in %s on line %d bool(false) -- Iteration 7 - - -Warning: fileperms(): Filename contains null byte in %s on line %d -bool(false) -- Iteration 8 - - -Warning: fileperms(): Filename contains null byte in %s on line %d -bool(false) *** Done *** diff --git a/ext/standard/tests/file/is_dir_null_byte.phpt b/ext/standard/tests/file/is_dir_null_byte.phpt new file mode 100644 index 000000000000..a49ccc0e5c45 --- /dev/null +++ b/ext/standard/tests/file/is_dir_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +is_dir() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: is_dir(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/is_dir_variation4.phpt b/ext/standard/tests/file/is_dir_variation4.phpt index d6e64efe211c..30285804a33c 100644 --- a/ext/standard/tests/file/is_dir_variation4.phpt +++ b/ext/standard/tests/file/is_dir_variation4.phpt @@ -23,10 +23,6 @@ $dirs_arr = array( "./is_dir_variation4//", ".//is_dir_variation4//", "is_dir_vari*", - - /* Testing Binary safe */ - "./is_dir_variation4/".chr(0), - "is_dir_variation4\0" ); $count = 1; @@ -75,10 +71,4 @@ bool(true) -- Iteration 8 -- bool(false) --- Iteration 9 -- -bool(false) - --- Iteration 10 -- -bool(false) - *** Done *** diff --git a/ext/standard/tests/file/is_executable_null_byte.phpt b/ext/standard/tests/file/is_executable_null_byte.phpt new file mode 100644 index 000000000000..7c26d53061d1 --- /dev/null +++ b/ext/standard/tests/file/is_executable_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +is_executable() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: is_executable(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/is_executable_variation1.phpt b/ext/standard/tests/file/is_executable_variation1.phpt index a85b9a2ef028..289abb1a265f 100644 --- a/ext/standard/tests/file/is_executable_variation1.phpt +++ b/ext/standard/tests/file/is_executable_variation1.phpt @@ -33,11 +33,6 @@ $files_arr = array( "$file_path/is_executable_variation1/*.tmp", "$file_path/is_executable_variation1/b*.tmp", - /* Testing Binary safe */ - "$file_path/is_executable_variation1".chr(0)."bar.temp", - "$file_path".chr(0)."is_executable_variation1/bar.temp", - "$file_path/is_executable_variation1x000/", - /* Testing directories */ ".", // current directory, exp: bool(true) "$file_path/is_executable_variation1" // temp directory, exp: bool(true) @@ -76,13 +71,7 @@ bool(false) -- Iteration 5 -- bool(false) -- Iteration 6 -- -bool(false) --- Iteration 7 -- -bool(false) --- Iteration 8 -- -bool(false) --- Iteration 9 -- bool(true) --- Iteration 10 -- +-- Iteration 7 -- bool(true) Done diff --git a/ext/standard/tests/file/is_file_null_byte.phpt b/ext/standard/tests/file/is_file_null_byte.phpt new file mode 100644 index 000000000000..f544d7bcf589 --- /dev/null +++ b/ext/standard/tests/file/is_file_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +is_file() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: is_file(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/is_file_variation4.phpt b/ext/standard/tests/file/is_file_variation4.phpt index 1afc34dd03be..9d98b7fd90d7 100644 --- a/ext/standard/tests/file/is_file_variation4.phpt +++ b/ext/standard/tests/file/is_file_variation4.phpt @@ -23,10 +23,6 @@ $files_arr = array( "//is_file_variation4//is_file_variation4.tmp", "/is_file_variation4/*.tmp", "is_file_variation4/is_file*.tmp", - - /* Testing Binary safe */ - "/is_file_variation4/is_file_variation4.tmp".chr(0), - "/is_file_variation4/is_file_variation4.tmp\0" ); $count = 1; @@ -65,9 +61,5 @@ bool(true) bool(false) - Iteration 6 - bool(false) -- Iteration 7 - -bool(false) -- Iteration 8 - -bool(false) *** Done *** diff --git a/ext/standard/tests/file/is_readable_null_byte.phpt b/ext/standard/tests/file/is_readable_null_byte.phpt new file mode 100644 index 000000000000..711700f4e7ec --- /dev/null +++ b/ext/standard/tests/file/is_readable_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +is_readable() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: is_readable(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/is_readable_variation1.phpt b/ext/standard/tests/file/is_readable_variation1.phpt index 9c25213f8abb..8548a840ccbe 100644 --- a/ext/standard/tests/file/is_readable_variation1.phpt +++ b/ext/standard/tests/file/is_readable_variation1.phpt @@ -32,11 +32,6 @@ $files_arr = array( "$file_path/is_readable_variation1/*.tmp", "$file_path/is_readable_variation1/b*.tmp", - /* Testing Binary safe */ - "$file_path/is_readable_variation1".chr(0)."bar.tmp", - "$file_path".chr(0)."is_readable_variation1/bar.tmp", - "$file_path".chr(0)."is_readable_variation1/bar.tmp", - /* Testing directories */ ".", // current directory, exp: bool(true) "$file_path/is_readable_variation1" // temp directory, exp: bool(true) @@ -77,13 +72,7 @@ bool(false) -- Iteration 6 -- bool(false) -- Iteration 7 -- -bool(false) --- Iteration 8 -- -bool(false) --- Iteration 9 -- -bool(false) --- Iteration 10 -- bool(true) --- Iteration 11 -- +-- Iteration 8 -- bool(true) Done diff --git a/ext/standard/tests/file/is_writable_null_byte.phpt b/ext/standard/tests/file/is_writable_null_byte.phpt new file mode 100644 index 000000000000..319db04cc151 --- /dev/null +++ b/ext/standard/tests/file/is_writable_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +is_writable() with filenames with null bytes +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ValueError: is_writable(): Argument #1 ($filename) must not contain any null bytes diff --git a/ext/standard/tests/file/is_writable_variation1.phpt b/ext/standard/tests/file/is_writable_variation1.phpt index 80695d6d45a2..181b1ba4e268 100644 --- a/ext/standard/tests/file/is_writable_variation1.phpt +++ b/ext/standard/tests/file/is_writable_variation1.phpt @@ -31,11 +31,6 @@ $files_arr = array( "$file_path/is_writable_variation1/*.tmp", "$file_path/is_writable_variation1/b*.tmp", - /* Testing Binary safe */ - "$file_path/is_writable_variation1".chr(0)."bar.tmp", - "$file_path".chr(0)."is_writable_variation1/bar.tmp", - "$file_path".chr(0)."is_writable_variation1/bar.tmp", - /* Testing directories */ ".", // current directory, exp: bool(true) "$file_path/is_writable_variation1" // temp directory, exp: bool(true) @@ -87,18 +82,9 @@ bool(false) bool(false) bool(false) -- Iteration 7 -- -bool(false) -bool(false) --- Iteration 8 -- -bool(false) -bool(false) --- Iteration 9 -- -bool(false) -bool(false) --- Iteration 10 -- bool(true) bool(true) --- Iteration 11 -- +-- Iteration 8 -- bool(true) bool(true) Done diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index a9f1f96f366f..458ad2f12baa 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -1249,14 +1249,14 @@ object ":" uiv ":" ["] { } /* Check for unserialize callback */ - if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + if (PG(unserialize_callback_func) == NULL) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } /* Call unserialize callback */ - ZVAL_STRING(&user_func, PG(unserialize_callback_func)); + ZVAL_STR_COPY(&user_func, PG(unserialize_callback_func)); ZVAL_STR(&args[0], class_name); BG(serialize_lock)++; diff --git a/ext/sysvmsg/tests/gh16592.phpt b/ext/sysvmsg/tests/gh16592.phpt index 8490d000f891..d48927b4dfee 100644 --- a/ext/sysvmsg/tests/gh16592.phpt +++ b/ext/sysvmsg/tests/gh16592.phpt @@ -8,11 +8,14 @@ class Test { function __serialize() {} } -$q = msg_get_queue(1); +// use a private queue, so we only remove our own. +$q = msg_get_queue(0, 0600); try { msg_send($q, 1, new Test, true); } catch (\TypeError $e) { echo $e->getMessage(); +} finally { + msg_remove_queue($q); } ?> --EXPECT-- diff --git a/main/SAPI.c b/main/SAPI.c index 31cf5da18a1d..3daa88e07f25 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -370,7 +370,6 @@ SAPI_API void sapi_activate_headers_only(void) SG(read_post_bytes) = 0; SG(request_info).request_body = NULL; SG(request_info).current_user = NULL; - SG(request_info).current_user_length = 0; SG(request_info).no_headers = 0; SG(request_info).post_entry = NULL; SG(global_request_time) = 0; @@ -413,7 +412,6 @@ SAPI_API void sapi_activate(void) SG(read_post_bytes) = 0; SG(request_info).request_body = NULL; SG(request_info).current_user = NULL; - SG(request_info).current_user_length = 0; SG(request_info).no_headers = 0; SG(request_info).post_entry = NULL; SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */ @@ -499,7 +497,7 @@ SAPI_API void sapi_deactivate_module(void) efree(SG(request_info).content_type_dup); } if (SG(request_info).current_user) { - efree(SG(request_info).current_user); + zend_string_release_ex(SG(request_info).current_user, false); } if (sapi_module.deactivate) { sapi_module.deactivate(); diff --git a/main/SAPI.h b/main/SAPI.h index 29532a019335..2621b9184d1b 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -97,8 +97,7 @@ typedef struct { /* this is necessary for the CGI SAPI module */ char *argv0; - char *current_user; - int current_user_length; + zend_string *current_user; /* this is necessary for CLI module */ int argc; diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index c0f88ad3b5ba..562cf1c63b96 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -359,7 +359,6 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) char *path_info; zend_string *filename = NULL; zend_string *resolved_path = NULL; - size_t length; bool orig_display_errors; memset(file_handle, 0, sizeof(zend_file_handle)); @@ -372,7 +371,7 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) if (s) { /* if there is no path name after the file, do not bother */ char user[32]; /* to try open the directory */ - length = s - (path_info + 2); + size_t length = s - (path_info + 2); if (length > sizeof(user) - 1) { length = sizeof(user) - 1; } @@ -421,19 +420,37 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) } } else #endif - if (PG(doc_root) && path_info && (length = strlen(PG(doc_root))) && - IS_ABSOLUTE_PATH(PG(doc_root), length)) { - size_t path_len = strlen(path_info); - filename = zend_string_alloc(length + path_len + 2, 0); - memcpy(ZSTR_VAL(filename), PG(doc_root), length); - if (!IS_SLASH(ZSTR_VAL(filename)[length - 1])) { /* length is never 0 */ - ZSTR_VAL(filename)[length++] = PHP_DIR_SEPARATOR; - } - if (IS_SLASH(path_info[0])) { - length--; - } - strncpy(ZSTR_VAL(filename) + length, path_info, path_len + 1); - ZSTR_LEN(filename) = length + path_len; + if (PG(doc_root) && path_info && IS_ABSOLUTE_PATH(ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)))) { + const size_t path_len = strlen(path_info); + + /* We need to concatenate two paths together, there are 3 situations: + * - No trailing slash AND no leading slash + * - Trailing slash AND leading slash + * - Either a trailing slash OR a leading slash + * In the first case we need to add a slash, in the second one we need to skip the leading slash, + * and in the third we can just concatenate them together */ + const unsigned int nb_slashes = IS_SLASH(ZSTR_VAL(PG(doc_root))[ZSTR_LEN(PG(doc_root)) - 1]) + IS_SLASH(path_info[0]); + switch (nb_slashes) { + case 0: + filename = zend_string_concat3( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + ZEND_STRL("/"), + path_info, path_len + ); + break; + case 1: + filename = zend_string_concat2( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + path_info, path_len + ); + break; + case 2: + filename = zend_string_concat2( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + path_info + 1, path_len -1 + ); + break; + } } else if (SG(request_info).path_translated) { filename = zend_string_init(SG(request_info).path_translated, strlen(SG(request_info).path_translated), 0); diff --git a/main/main.c b/main/main.c index 0a1d67358649..d0ffe1895e9c 100644 --- a/main/main.c +++ b/main/main.c @@ -706,8 +706,9 @@ static PHP_INI_MH(OnUpdateErrorLog) return FAILURE; } } - char **p = ZEND_INI_GET_ADDR(); - *p = new_value && ZSTR_LEN(new_value) > 0 ? ZSTR_VAL(new_value) : NULL; + + zend_string **p = ZEND_INI_GET_ADDR(); + *p = new_value && ZSTR_LEN(new_value) > 0 ? new_value : NULL; return SUCCESS; } /* }}} */ @@ -818,19 +819,19 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("report_memleaks", "1", PHP_INI_ALL, OnUpdateReportMemleaks, report_memleaks, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("report_zend_debug", "0", PHP_INI_ALL, OnUpdateBool, report_zend_debug, php_core_globals, core_globals) STD_PHP_INI_ENTRY("output_buffering", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateLong, output_buffering, php_core_globals, core_globals) - STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, output_handler, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateStrNotEmpty, output_handler, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("register_argc_argv", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_argc_argv, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) - STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateStrNotEmpty, unserialize_callback_func, php_core_globals, core_globals) STD_PHP_INI_ENTRY("serialize_precision", "-1", PHP_INI_ALL, OnSetSerializePrecision, serialize_precision, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.output", "&", PHP_INI_ALL, OnUpdateStrNotEmpty, arg_separator.output, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.input", "&", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStrNotEmpty, arg_separator.input, php_core_globals, core_globals) STD_PHP_INI_ENTRY("auto_append_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_append_file, php_core_globals, core_globals) STD_PHP_INI_ENTRY("auto_prepend_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_prepend_file, php_core_globals, core_globals) - STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, doc_root, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStrNotEmpty, doc_root, php_core_globals, core_globals) STD_PHP_INI_ENTRY("default_charset", PHP_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateDefaultCharset, default_charset, sapi_globals_struct, sapi_globals) STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateDefaultMimeTye, default_mimetype, sapi_globals_struct, sapi_globals) STD_PHP_INI_ENTRY("internal_encoding", NULL, PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, php_core_globals, core_globals) @@ -940,7 +941,7 @@ PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int sys int error_log_mode; #ifdef HAVE_SYSLOG_H - if (!strcmp(PG(error_log), "syslog")) { + if (zend_string_equals_literal(PG(error_log), "syslog")) { php_syslog(syslog_type_int, "%s", log_message); PG(in_error_log) = 0; return; @@ -953,7 +954,7 @@ PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int sys error_log_mode = PG(error_log_mode); } - fd = VCWD_OPEN_MODE(PG(error_log), O_CREAT | O_APPEND | O_WRONLY, error_log_mode); + fd = VCWD_OPEN_MODE(ZSTR_VAL(PG(error_log)), O_CREAT | O_APPEND | O_WRONLY, error_log_mode); if (fd != -1) { char *tmp; size_t len; @@ -1315,7 +1316,7 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c * be NULL if PG(last_error_message) is not NULL */ if (!zend_string_equals(PG(last_error_message), message) || (!PG(ignore_repeated_source) - && ((PG(last_error_lineno) != (int)error_lineno) + && ((PG(last_error_lineno) != error_lineno) || !zend_string_equals(PG(last_error_file), error_filename)))) { display = 1; } else { @@ -1508,7 +1509,7 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c /* }}} */ /* {{{ php_get_current_user */ -PHPAPI char *php_get_current_user(void) +PHPAPI zend_string *php_get_current_user(void) { zend_stat_t *pstat = NULL; @@ -1523,19 +1524,15 @@ PHPAPI char *php_get_current_user(void) pstat = sapi_get_stat(); if (!pstat) { - return ""; + return ZSTR_EMPTY_ALLOC(); } else { #ifdef PHP_WIN32 char *name = php_win32_get_username(); - int len; if (!name) { - return ""; + return ZSTR_EMPTY_ALLOC(); } - len = (int)strlen(name); - name[len] = '\0'; - SG(request_info).current_user_length = len; - SG(request_info).current_user = estrndup(name, len); + SG(request_info).current_user = zend_string_init(name, strlen(name), false); free(name); return SG(request_info).current_user; #else @@ -1565,20 +1562,19 @@ PHPAPI char *php_get_current_user(void) goto try_again; } efree(pwbuf); - return ""; + return ZSTR_EMPTY_ALLOC(); } if (retpwptr == NULL) { efree(pwbuf); - return ""; + return ZSTR_EMPTY_ALLOC(); } pwd = &_pw; #else if ((pwd=getpwuid(pstat->st_uid))==NULL) { - return ""; + return ZSTR_EMPTY_ALLOC(); } #endif - SG(request_info).current_user_length = strlen(pwd->pw_name); - SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length); + SG(request_info).current_user = zend_string_init(pwd->pw_name, strlen(pwd->pw_name), false); #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX) efree(pwbuf); #endif @@ -1885,10 +1881,10 @@ zend_result php_request_startup(void) sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1); } - if (PG(output_handler) && PG(output_handler)[0]) { + if (PG(output_handler)) { zval oh; - ZVAL_STRING(&oh, PG(output_handler)); + ZVAL_STR_COPY(&oh, PG(output_handler)); php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS); zval_ptr_dtor(&oh); } else if (PG(output_buffering)) { diff --git a/main/php.h b/main/php.h index fb81a4b47455..5186868e612f 100644 --- a/main/php.h +++ b/main/php.h @@ -323,7 +323,7 @@ PHPAPI extern int (*php_register_internal_extensions_func)(void); PHPAPI int php_register_internal_extensions(void); PHPAPI void php_register_pre_request_shutdown(void (*func)(void *), void *userdata); PHPAPI void php_com_initialize(void); -PHPAPI char *php_get_current_user(void); +PHPAPI zend_string *php_get_current_user(void); PHPAPI const char *php_get_internal_encoding(void); PHPAPI const char *php_get_input_encoding(void); diff --git a/main/php_globals.h b/main/php_globals.h index 0bab9fc95c14..e3cfe38a63fd 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -65,18 +65,18 @@ struct _php_core_globals { bool ignore_repeated_source; bool report_memleaks; - char *output_handler; + zend_string *output_handler; - char *unserialize_callback_func; + zend_string *unserialize_callback_func; zend_long serialize_precision; zend_long memory_limit; zend_long max_memory_limit; zend_long max_input_time; - char *error_log; + zend_string *error_log; - char *doc_root; + zend_string *doc_root; char *user_dir; char *include_path; char *open_basedir; @@ -136,7 +136,7 @@ struct _php_core_globals { bool report_zend_debug; int last_error_type; - int last_error_lineno; + uint32_t last_error_lineno; zend_string *last_error_message; zend_string *last_error_file; @@ -158,12 +158,10 @@ struct _php_core_globals { bool in_error_log; bool allow_url_include; -#ifdef PHP_WIN32 - bool com_initialized; -#endif bool in_user_include; #ifdef PHP_WIN32 + bool com_initialized; bool windows_show_crt_warning; #endif diff --git a/main/streams/streams.c b/main/streams/streams.c index 740a1d7a6e06..192689ce036f 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2108,115 +2108,105 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod options &= ~USE_PATH; } if (EG(exception)) { - if (resolved_path) { - zend_string_release_ex(resolved_path, false); - } - return NULL; + goto cleanup_no_wrapper_name; } } path_to_open = path; wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options); - if ((options & STREAM_USE_URL) && (!wrapper || !wrapper->is_url)) { - if (wrapper) { - php_stream_wrapper_warn(wrapper, context, options, - ProtocolUnsupported, - "This function may only be used against URLs"); - } else { - php_error_docref(NULL, E_WARNING, "This function may only be used against URLs"); - } - if (resolved_path) { - zend_string_release_ex(resolved_path, 0); - } - return NULL; + if (UNEXPECTED(!wrapper)) { + php_stream_wrapper_warn_name(PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME, context, options, OpenFailed, + "Failed to open stream: no suitable wrapper could be found"); + goto cleanup_no_wrapper_name; + } + if ((options & STREAM_USE_URL) && !wrapper->is_url) { + php_stream_wrapper_warn(wrapper, context, options, + ProtocolUnsupported, + "This function may only be used against URLs"); + goto cleanup_no_wrapper_name; + } + + if (!wrapper->wops->stream_opener) { + php_stream_wrapper_warn(wrapper, context, options, NoOpener, + "Failed to open stream: wrapper does not support stream open"); + goto cleanup_no_wrapper_name; } /* wrapper name needs to be stored as wrapper can be removed in opener (user stream) */ char *wrapper_name = pestrdup(PHP_STREAM_ERROR_WRAPPER_NAME(wrapper), persistent); - if (wrapper) { - if (!wrapper->wops->stream_opener) { - php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, - NoOpener, - "wrapper does not support stream open"); - } else { - stream = wrapper->wops->stream_opener(wrapper, - path_to_open, mode, options & ~REPORT_ERRORS, - opened_path, context STREAMS_REL_CC); - } + stream = wrapper->wops->stream_opener(wrapper, + path_to_open, mode, options & ~REPORT_ERRORS, + opened_path, context STREAMS_REL_CC); - /* if the caller asked for a persistent stream but the wrapper did not - * return one, force an error here */ - if (stream && persistent && !stream->is_persistent) { - php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, - PersistentNotSupported, - "wrapper does not support persistent streams"); - php_stream_close(stream); - stream = NULL; + if (UNEXPECTED(!stream)) { + if (options & REPORT_ERRORS) { + php_stream_display_wrapper_name_errors(wrapper_name, context, PHP_STREAM_EC(OpenFailed), + "Failed to open stream"); } + php_stream_tidy_wrapper_name_error_log(wrapper_name); + goto cleanup; + } - if (stream) { - stream->wrapper = wrapper; - } + /* if the caller asked for a persistent stream but the wrapper did not + * return one, force an error here */ + if (persistent && !stream->is_persistent) { + php_stream_wrapper_warn(wrapper, context, options, PersistentNotSupported, + "Failed to open stream: wrapper does not support persistent streams"); + php_stream_close(stream); + stream = NULL; + goto cleanup; } - if (stream) { - if (opened_path && !*opened_path && resolved_path) { - *opened_path = resolved_path; - resolved_path = NULL; - } - if (stream->orig_path) { - pefree(stream->orig_path, persistent); - } - stream->orig_path = pestrdup(path, persistent); + stream->wrapper = wrapper; + + if (opened_path && !*opened_path && resolved_path) { + *opened_path = resolved_path; + resolved_path = NULL; + } + if (stream->orig_path) { + pefree(stream->orig_path, persistent); + } + stream->orig_path = pestrdup(path, persistent); #if ZEND_DEBUG stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename; stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno; #endif - /* Attach an explicitly provided context to the stream, but never the - * default context: sharing it by reference would let a later - * stream_context_set_option() on the stream mutate the global default - * context, leaking options into every other stream. Stream errors fall - * back to the default context on their own when the stream has none. */ - if (stream->ctx == NULL && context != NULL && context != FG(default_context) && !persistent) { - php_stream_context_set(stream, context); - } + /* Attach an explicitly provided context to the stream, but never the + * default context: sharing it by reference would let a later + * stream_context_set_option() on the stream mutate the global default + * context, leaking options into every other stream. Stream errors fall + * back to the default context on their own when the stream has none. */ + if (stream->ctx == NULL && context != NULL && context != FG(default_context) && !persistent) { + php_stream_context_set(stream, context); } - if (stream != NULL && (options & STREAM_MUST_SEEK)) { + if (options & STREAM_MUST_SEEK) { php_stream *newstream; switch(php_stream_make_seekable_rel(stream, &newstream, (options & STREAM_WILL_CAST) ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) { case PHP_STREAM_UNCHANGED: - if (resolved_path) { - zend_string_release_ex(resolved_path, 0); - } - pefree(wrapper_name, persistent); - return stream; + goto cleanup; case PHP_STREAM_RELEASED: if (newstream->orig_path) { pefree(newstream->orig_path, persistent); } newstream->orig_path = pestrdup(path, persistent); - if (resolved_path) { - zend_string_release_ex(resolved_path, 0); - } - pefree(wrapper_name, persistent); - return newstream; + stream = newstream; + goto cleanup; default: - php_stream_close(stream); - stream = NULL; php_stream_wrapper_warn(wrapper, context, options, SeekNotSupported, "could not make seekable - %s", path); - /* We do not want multiple errors so we negate it */ - options &= ~REPORT_ERRORS; + php_stream_close(stream); + stream = NULL; + goto cleanup; } } - if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) { + if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) { zend_off_t newpos = 0; /* if opened for append, we need to revise our idea of the initial file position */ @@ -2225,19 +2215,18 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } } - if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_name_errors(wrapper_name, context, PHP_STREAM_EC(OpenFailed), - "Failed to open stream"); +cleanup: + pefree(wrapper_name, persistent); +cleanup_no_wrapper_name: + if (resolved_path) { + zend_string_release_ex(resolved_path, 0); + } + if (stream == NULL) { if (opened_path && *opened_path) { zend_string_release_ex(*opened_path, 0); *opened_path = NULL; } } - php_stream_tidy_wrapper_name_error_log(wrapper_name); - pefree(wrapper_name, persistent); - if (resolved_path) { - zend_string_release_ex(resolved_path, 0); - } return stream; } /* }}} */ diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 841f45b207a8..a79eada2728b 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -1221,7 +1221,7 @@ static void init_request_info(fcgi_request *request) size_t script_path_translated_len; if (!env_document_root && PG(doc_root)) { - env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root)); + env_document_root = CGI_PUTENV("DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root))); /* fix docroot */ TRANSLATE_SLASHES(env_document_root); } diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index e06f30b9e2d2..85028cc03f7c 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1219,7 +1219,7 @@ static void php_cli_server_log_response(php_cli_server_client *client, int statu /* error */ if (append_error_message) { - spprintf(&error_buf, 0, " - %s in %s on line %d", + spprintf(&error_buf, 0, " - %s in %s on line %" PRIu32, ZSTR_VAL(PG(last_error_message)), ZSTR_VAL(PG(last_error_file)), PG(last_error_lineno)); if (!error_buf) { efree(basic_buf); diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 9b7cbcf16f06..655d66ce5f06 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -1078,7 +1078,7 @@ static void init_request_info(void) int script_path_translated_len; if (!env_document_root && PG(doc_root)) { - env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", PG(doc_root)); + env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root))); } if (!apache_was_here && env_path_translated != NULL && env_redirect_url != NULL && diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index ee579e81df02..2100d6e7dca4 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -81,7 +81,7 @@ PHPDBG_INFO(error) /* {{{ */ { if (PG(last_error_message)) { phpdbg_try_access { - phpdbg_writeln("Last error: %s at %s line %d", + phpdbg_writeln("Last error: %s at %s line %" PRIu32, ZSTR_VAL(PG(last_error_message)), ZSTR_VAL(PG(last_error_file)), PG(last_error_lineno));