Commit cd753007ce1 for php.net

commit cd753007ce15665620343dc9244b37526c805cb4
Author: Gina Peter Banyard <girgias@php.net>
Date:   Mon Mar 30 14:48:12 2026 +0100

    Audit INI functions and macros, and replace them with better alternatives (#21146)

    Audit zend_ini_string(), INI_STR(), and related functions and macros, and all other INI_* macros.

    The primary motivation is that these APIs should return a `const char*` because the `char*` is owned by a zend_string, and thus should never be released.

    Moreover, the INI_STR() API doesn't follow our usual naming scheme as it returns a char* rather than a zend_string*.

    In this PR new zend_ini_{bool|long|double|str|string}_literal() macros are introduced replacing the INI_{BOOL|INT|FLT|STR} macros which follow our more modern naming convention.
    Moreover, the INI_BOOL() macro didn't produce correct values if the INI string is a word like "true" or "on".

    The INI_ORIG_* APIs are removed because a Sourcegraph search shows 0 results, other than the one case used in ext/tidy that we fix using the typical API.

    Add some additional checks for the value of an INI string to ensure it doesn't contain a nul byte when describing a path.

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 656e1d556a5..1072d822ee4 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -75,6 +75,14 @@ PHP 8.6 INTERNALS UPGRADE NOTES
   . Added a C23_ENUM() helper macro to define forward-compatible fixed-size
     enums.
   . Extended php_stream_filter_ops with seek method.
+  . The INI_STR(), INI_INT(), INI_FLT(), and INI_BOOL() macros have been
+    removed. Instead new zend_ini_{bool|long|double|str|string}_literal()
+    macros have been added. This fixes an internal naming inconsistency as
+    "str" usually means zend_string*, and "string" means char*.
+    However INI_STR() returned a char*
+  . The INI_ORIG_{INT|STR|FLT|BOOL}() macros have been removed as they are
+    unused. If this behaviour is required fall back to the zend_ini_*
+    functions.

 ========================
 2. Build system changes
diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c
index d571a622e47..248b4f401a7 100644
--- a/Zend/zend_fibers.c
+++ b/Zend/zend_fibers.c
@@ -572,9 +572,9 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
 	zend_fiber *fiber = EG(active_fiber);

 	/* Determine the current error_reporting ini setting. */
-	zend_long error_reporting = INI_INT("error_reporting");
-	/* If error_reporting is 0 and not explicitly set to 0, INI_STR returns a null pointer. */
-	if (!error_reporting && !INI_STR("error_reporting")) {
+	zend_long error_reporting = zend_ini_long_literal("error_reporting");
+	/* If error_reporting is 0 and not explicitly set to 0, zend_ini_str returns a null pointer. */
+	if (!error_reporting && !zend_ini_str_literal("error_reporting")) {
 		error_reporting = E_ALL;
 	}

diff --git a/Zend/zend_highlight.c b/Zend/zend_highlight.c
index 5c3cd136d58..c5fc874b9cb 100644
--- a/Zend/zend_highlight.c
+++ b/Zend/zend_highlight.c
@@ -79,8 +79,8 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini
 {
 	zval token;
 	int token_type;
-	char *last_color = syntax_highlighter_ini->highlight_html;
-	char *next_color;
+	const char *last_color = syntax_highlighter_ini->highlight_html;
+	const char *next_color;

 	zend_printf("<pre><code style=\"color: %s\">", last_color);
 	/* highlight stuff coming back from zendlex() */
diff --git a/Zend/zend_highlight.h b/Zend/zend_highlight.h
index 04688d65132..adc1d3c8c81 100644
--- a/Zend/zend_highlight.h
+++ b/Zend/zend_highlight.h
@@ -30,11 +30,11 @@


 typedef struct _zend_syntax_highlighter_ini {
-	char *highlight_html;
-	char *highlight_comment;
-	char *highlight_default;
-	char *highlight_string;
-	char *highlight_keyword;
+	const char *highlight_html;
+	const char *highlight_comment;
+	const char *highlight_default;
+	const char *highlight_string;
+	const char *highlight_keyword;
 } zend_syntax_highlighter_ini;


diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c
index d8f1d4f50f9..85739415feb 100644
--- a/Zend/zend_ini.c
+++ b/Zend/zend_ini.c
@@ -491,7 +491,7 @@ ZEND_API double zend_ini_double(const char *name, size_t name_length, bool orig)
 }
 /* }}} */

-ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists) /* {{{ */
+ZEND_API const char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists) /* {{{ */
 {
 	zend_string *str = zend_ini_str_ex(name, name_length, orig, exists);

@@ -499,7 +499,7 @@ ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool ori
 }
 /* }}} */

-ZEND_API char *zend_ini_string(const char *name, size_t name_length, bool orig) /* {{{ */
+ZEND_API const char *zend_ini_string(const char *name, size_t name_length, bool orig) /* {{{ */
 {
 	zend_string *str = zend_ini_str(name, name_length, orig);

diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h
index d8d7f599f46..d2419bb160f 100644
--- a/Zend/zend_ini.h
+++ b/Zend/zend_ini.h
@@ -88,13 +88,19 @@ ZEND_API void display_ini_entries(zend_module_entry *module);

 ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, bool orig);
 ZEND_API double zend_ini_double(const char *name, size_t name_length, bool orig);
-ZEND_API char *zend_ini_string(const char *name, size_t name_length, bool orig);
-ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists);
+ZEND_API const char *zend_ini_string(const char *name, size_t name_length, bool orig);
+ZEND_API const char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists);
 ZEND_API zend_string *zend_ini_str(const char *name, size_t name_length, bool orig);
 ZEND_API zend_string *zend_ini_str_ex(const char *name, size_t name_length, bool orig, bool *exists);
 ZEND_API zend_string *zend_ini_get_value(zend_string *name);
 ZEND_API bool zend_ini_parse_bool(const zend_string *str);

+#define zend_ini_bool_literal(name) zend_ini_parse_bool(zend_ini_str((name), sizeof("" name) - 1, false))
+#define zend_ini_long_literal(name) zend_ini_long((name), sizeof("" name) - 1, false)
+#define zend_ini_double_literal(name) zend_ini_double((name), sizeof("" name) - 1, false)
+#define zend_ini_str_literal(name) zend_ini_str((name), sizeof("" name) - 1, false)
+#define zend_ini_string_literal(name) zend_ini_string((name), sizeof("" name) - 1, false)
+
 /**
  * Parses an ini quantity
  *
@@ -191,16 +197,6 @@ END_EXTERN_C()
 	ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, (void *) XtOffsetOf(struct_type, property_name), (void *) &struct_ptr, NULL, zend_ini_boolean_displayer_cb)
 #endif

-#define INI_INT(name) zend_ini_long((name), strlen(name), 0)
-#define INI_FLT(name) zend_ini_double((name), strlen(name), 0)
-#define INI_STR(name) zend_ini_string_ex((name), strlen(name), 0, NULL)
-#define INI_BOOL(name) ((bool) INI_INT(name))
-
-#define INI_ORIG_INT(name)	zend_ini_long((name), strlen(name), 1)
-#define INI_ORIG_FLT(name)	zend_ini_double((name), strlen(name), 1)
-#define INI_ORIG_STR(name)	zend_ini_string((name), strlen(name), 1)
-#define INI_ORIG_BOOL(name) ((bool) INI_ORIG_INT(name))
-
 #define REGISTER_INI_ENTRIES() zend_register_ini_entries_ex(ini_entries, module_number, type)
 #define UNREGISTER_INI_ENTRIES() zend_unregister_ini_entries_ex(module_number, type)
 #define DISPLAY_INI_ENTRIES() display_ini_entries(zend_module)
diff --git a/Zend/zend_multibyte.c b/Zend/zend_multibyte.c
index f61ed79fd1f..fc130162f08 100644
--- a/Zend/zend_multibyte.c
+++ b/Zend/zend_multibyte.c
@@ -114,8 +114,8 @@ ZEND_API zend_result zend_multibyte_set_functions(const zend_multibyte_functions
 	 * populated, we need to reinitialize script_encoding here.
 	 */
 	{
-		const char *value = zend_ini_string("zend.script_encoding", sizeof("zend.script_encoding") - 1, 0);
-		zend_multibyte_set_script_encoding_by_string(value, strlen(value));
+		const zend_string *value = zend_ini_str_literal("zend.script_encoding");
+		zend_multibyte_set_script_encoding_by_string(ZSTR_VAL(value), ZSTR_LEN(value));
 	}
 	return SUCCESS;
 }
diff --git a/ext/com_dotnet/com_dotnet.c b/ext/com_dotnet/com_dotnet.c
index f8b4a828e15..e4ab9848583 100644
--- a/ext/com_dotnet/com_dotnet.c
+++ b/ext/com_dotnet/com_dotnet.c
@@ -127,7 +127,6 @@ static HRESULT dotnet_bind_runtime(LPVOID FAR *ppv)
 	typedef HRESULT (STDAPICALLTYPE *cbtr_t)(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
 	cbtr_t CorBindToRuntime;
 	OLECHAR *oleversion;
-	char *version;

 	mscoree = LoadLibraryA("mscoree.dll");
 	if (mscoree == NULL) {
@@ -140,11 +139,11 @@ static HRESULT dotnet_bind_runtime(LPVOID FAR *ppv)
 		return S_FALSE;
 	}

-	version = INI_STR("com.dotnet_version");
-	if (version == NULL || *version == '\0') {
+	const zend_string *version = zend_ini_str_literal("com.dotnet_version");
+	if (version == NULL || ZSTR_LEN(version) == 0) {
 		oleversion = NULL;
 	} else {
-		oleversion = php_com_string_to_olestring(version, strlen(version), COMG(code_page));
+		oleversion = php_com_string_to_olestring(ZSTR_VAL(version), ZSTR_LEN(version), COMG(code_page));
 	}

 	hr = CorBindToRuntime(oleversion, NULL, &CLSID_CorRuntimeHost, &IID_ICorRuntimeHost, ppv);
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 6328538241f..57bc2f1ede3 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -1100,8 +1100,6 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode)
    Set default options for a handle */
 static void _php_curl_set_default_options(php_curl *ch)
 {
-	char *cainfo;
-
 	curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS,        1L);
 	curl_easy_setopt(ch->cp, CURLOPT_VERBOSE,           0L);
 	curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);
@@ -1114,9 +1112,9 @@ static void _php_curl_set_default_options(php_curl *ch)
 	curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120L);
 	curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20L); /* prevent infinite redirects */

-	cainfo = INI_STR("openssl.cafile");
+	const char *cainfo = zend_ini_string_literal("openssl.cafile");
 	if (!(cainfo && cainfo[0] != '\0')) {
-		cainfo = INI_STR("curl.cainfo");
+		cainfo = zend_ini_string_literal("curl.cainfo");
 	}
 	if (cainfo && cainfo[0] != '\0') {
 		curl_easy_setopt(ch->cp, CURLOPT_CAINFO, cainfo);
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index dd80e15e9cf..e5b094acdb3 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -5478,18 +5478,18 @@ static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, bool calc_s
 	ZEND_PARSE_PARAMETERS_END();

 	if (latitude_is_null) {
-		latitude = INI_FLT("date.default_latitude");
+		latitude = zend_ini_double_literal("date.default_latitude");
 	}

 	if (longitude_is_null) {
-		longitude = INI_FLT("date.default_longitude");
+		longitude = zend_ini_double_literal("date.default_longitude");
 	}

 	if (zenith_is_null) {
 		if (calc_sunset) {
-			zenith = INI_FLT("date.sunset_zenith");
+			zenith = zend_ini_double_literal("date.sunset_zenith");
 		} else {
-			zenith = INI_FLT("date.sunrise_zenith");
+			zenith = zend_ini_double_literal("date.sunrise_zenith");
 		}
 	}

diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index 33b397b4f69..1bd1a26f051 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -1595,7 +1595,7 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type,

 #ifdef HAVE_GD_JPG
 			case PHP_GDIMG_TYPE_JPG:
-				ignore_warning = INI_INT("gd.jpeg_ignore_warning");
+				ignore_warning = zend_ini_bool_literal("gd.jpeg_ignore_warning");
 				im = gdImageCreateFromJpegEx(fp, ignore_warning);
 			break;
 #endif
diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c
index 6f257af4981..533d2f2c61f 100644
--- a/ext/openssl/openssl_backend_common.c
+++ b/ext/openssl/openssl_backend_common.c
@@ -504,10 +504,8 @@ void php_openssl_set_cert_locations(zval *return_value)
 	add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env());
 	add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir());
 	add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area());
-	add_assoc_string(return_value, "ini_cafile",
-		zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0));
-	add_assoc_string(return_value, "ini_capath",
-		zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0));
+	add_assoc_str(return_value, "ini_cafile", zend_string_copy(zend_ini_str_literal("openssl.cafile")));
+	add_assoc_str(return_value, "ini_capath", zend_string_copy(zend_ini_str_literal("openssl.capath")));
 }

 X509 *php_openssl_x509_from_str(
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index 34b4acd9f1c..8f9395e4602 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -880,16 +880,16 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c
 static zend_result php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */
 {
 	zval *val = NULL;
-	char *cafile = NULL;
-	char *capath = NULL;
+	const char *cafile = NULL;
+	const char *capath = NULL;
 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;

 	GET_VER_OPT_STRING("cafile", cafile);
 	GET_VER_OPT_STRING("capath", capath);

 	if (cafile == NULL) {
-		cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0);
-		cafile = strlen(cafile) ? cafile : NULL;
+		const zend_string *cafile_str = zend_ini_str_literal("openssl.cafile");
+		cafile = ZSTR_LEN(cafile_str) ? ZSTR_VAL(cafile_str) : NULL;
 	} else if (!sslsock->is_client) {
 		/* Servers need to load and assign CA names from the cafile */
 		STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(cafile);
@@ -902,8 +902,8 @@ static zend_result php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream
 	}

 	if (capath == NULL) {
-		capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0);
-		capath = strlen(capath) ? capath : NULL;
+		const zend_string *capath_str = zend_ini_str_literal("openssl.capath");
+		capath = ZSTR_LEN(capath_str) ? ZSTR_VAL(capath_str) : NULL;
 	}

 	if (cafile || capath) {
diff --git a/ext/session/session.c b/ext/session/session.c
index c04e19e25ed..51ab3922e0b 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -1654,7 +1654,7 @@ PHPAPI zend_result php_session_start(void)
 			return FAILURE;

 		case php_session_disabled: {
-			const char *value = zend_ini_string(ZEND_STRL("session.save_handler"), false);
+			const char *value = zend_ini_string_literal("session.save_handler");
 			if (!PS(mod) && value) {
 				PS(mod) = _php_find_ps_module(value);
 				if (!PS(mod)) {
@@ -1662,7 +1662,7 @@ PHPAPI zend_result php_session_start(void)
 					return FAILURE;
 				}
 			}
-			value = zend_ini_string(ZEND_STRL("session.serialize_handler"), false);
+			value = zend_ini_string_literal("session.serialize_handler");
 			if (!PS(serializer) && value) {
 				PS(serializer) = _php_find_ps_serializer(value);
 				if (!PS(serializer)) {
@@ -2768,14 +2768,14 @@ static zend_result php_rinit_session(bool auto_start)

 	PS(mod) = NULL;
 	{
-		const char *value = zend_ini_string(ZEND_STRL("session.save_handler"), false);
+		const char *value = zend_ini_string_literal("session.save_handler");
 		if (value) {
 			PS(mod) = _php_find_ps_module(value);
 		}
 	}

 	if (PS(serializer) == NULL) {
-		const char *value = zend_ini_string(ZEND_STRL("session.serialize_handler"), false);
+		const char *value = zend_ini_string_literal("session.serialize_handler");
 		if (value) {
 			PS(serializer) = _php_find_ps_serializer(value);
 		}
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 178660ec4cd..59e2bd41680 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -1695,7 +1695,7 @@ PHP_METHOD(SoapServer, handle)
 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
 		}

-		if (INI_INT("zlib.output_compression")) {
+		if (zend_ini_long_literal("zlib.output_compression")) {
 			sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
 		} else {
 			snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
@@ -1857,7 +1857,7 @@ static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeade
 	if (use_http_error_status) {
 		sapi_add_header("HTTP/1.1 500 Internal Server Error", sizeof("HTTP/1.1 500 Internal Server Error")-1, 1);
 	}
-	if (INI_INT("zlib.output_compression")) {
+	if (zend_ini_long_literal("zlib.output_compression")) {
 		sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
 	} else {
 		snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index fbbeeb0b433..a7417f2a390 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -1717,11 +1717,11 @@ PHPAPI bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_

 ZEND_API void php_get_highlight_struct(zend_syntax_highlighter_ini *syntax_highlighter_ini) /* {{{ */
 {
-	syntax_highlighter_ini->highlight_comment = INI_STR("highlight.comment");
-	syntax_highlighter_ini->highlight_default = INI_STR("highlight.default");
-	syntax_highlighter_ini->highlight_html    = INI_STR("highlight.html");
-	syntax_highlighter_ini->highlight_keyword = INI_STR("highlight.keyword");
-	syntax_highlighter_ini->highlight_string  = INI_STR("highlight.string");
+	syntax_highlighter_ini->highlight_comment = zend_ini_string_literal("highlight.comment");
+	syntax_highlighter_ini->highlight_default = zend_ini_string_literal("highlight.default");
+	syntax_highlighter_ini->highlight_html    = zend_ini_string_literal("highlight.html");
+	syntax_highlighter_ini->highlight_keyword = zend_ini_string_literal("highlight.keyword");
+	syntax_highlighter_ini->highlight_string  = zend_ini_string_literal("highlight.string");
 }
 /* }}} */

@@ -2029,17 +2029,16 @@ PHP_FUNCTION(ini_restore)
 PHP_FUNCTION(set_include_path)
 {
 	zend_string *new_value;
-	char *old_value;
 	zend_string *key;

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH_STR(new_value)
 	ZEND_PARSE_PARAMETERS_END();

-	old_value = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
+	zend_string *old_value = zend_ini_str_literal("include_path");
 	/* copy to return here, because alter might free it! */
 	if (old_value) {
-		RETVAL_STRING(old_value);
+		RETVAL_STR_COPY(old_value);
 	} else {
 		RETVAL_FALSE;
 	}
@@ -2059,7 +2058,7 @@ PHP_FUNCTION(get_include_path)
 {
 	ZEND_PARSE_PARAMETERS_NONE();

-	zend_string *str = zend_ini_str("include_path", sizeof("include_path") - 1, 0);
+	zend_string *str = zend_ini_str_literal("include_path");

 	if (str == NULL) {
 		RETURN_FALSE;
diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c
index 5009c779368..ec9e3a59e4b 100644
--- a/ext/standard/browscap.c
+++ b/ext/standard/browscap.c
@@ -337,7 +337,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
 					) {
 						zend_error(E_CORE_ERROR, "Invalid browscap ini file: "
 							"'Parent' value cannot be same as the section name: %s "
-							"(in file %s)", ZSTR_VAL(ctx->current_section_name), INI_STR("browscap"));
+							"(in file %s)", ZSTR_VAL(ctx->current_section_name), zend_ini_string_literal("browscap"));
 						return;
 					}

@@ -399,7 +399,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
 }
 /* }}} */

-static zend_result browscap_read_file(char *filename, browser_data *browdata, bool persistent) /* {{{ */
+static zend_result browscap_read_file(const char *filename, browser_data *browdata, bool persistent) /* {{{ */
 {
 	zend_file_handle fh;
 	browscap_parser_ctx ctx = {0};
@@ -499,7 +499,7 @@ PHP_INI_MH(OnChangeBrowscap)

 PHP_MINIT_FUNCTION(browscap) /* {{{ */
 {
-	char *browscap = INI_STR("browscap");
+	const char *browscap = zend_ini_string_literal("browscap");

 #ifdef ZTS
 	ts_allocate_id(&browscap_globals_id, sizeof(browser_data), (ts_allocate_ctor) browscap_globals_ctor, NULL);
diff --git a/ext/standard/dl.c b/ext/standard/dl.c
index 31adbceac8c..209b0c1d3b0 100644
--- a/ext/standard/dl.c
+++ b/ext/standard/dl.c
@@ -114,11 +114,11 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)
 	zend_module_entry *module_entry;
 	zend_module_entry *(*get_module)(void);
 	int error_type, slash_suffix = 0;
-	char *extension_dir;
+	const char *extension_dir;
 	char *err1, *err2;

 	if (type == MODULE_PERSISTENT) {
-		extension_dir = INI_STR("extension_dir");
+		extension_dir = zend_ini_string_literal("extension_dir");
 	} else {
 		extension_dir = PG(extension_dir);
 	}
diff --git a/ext/standard/mail.c b/ext/standard/mail.c
index 395c7bb81d4..c909c0ed55d 100644
--- a/ext/standard/mail.c
+++ b/ext/standard/mail.c
@@ -336,8 +336,8 @@ PHP_FUNCTION(mail)
 		subject_r = subject;
 	}

-	zend_string *force_extra_parameters = zend_ini_str_ex("mail.force_extra_parameters", strlen("mail.force_extra_parameters"), false, NULL);
-	if (force_extra_parameters) {
+	zend_string *force_extra_parameters = zend_ini_str_literal("mail.force_extra_parameters");
+	if (force_extra_parameters && ZSTR_LEN(force_extra_parameters) > 0) {
 		extra_cmd = php_escape_shell_cmd(force_extra_parameters);
 	} else if (extra_cmd) {
 		extra_cmd = php_escape_shell_cmd(extra_cmd);
@@ -437,9 +437,9 @@ static int php_mail_detect_multiple_crlf(const char *hdr) {
 PHPAPI bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const zend_string *extra_cmd)
 {
 	FILE *sendmail;
-	char *sendmail_path = INI_STR("sendmail_path");
+	const char *sendmail_path = zend_ini_string_literal("sendmail_path");
 	char *sendmail_cmd = NULL;
-	const zend_string *mail_log = zend_ini_str(ZEND_STRL("mail.log"), false);
+	const zend_string *mail_log = zend_ini_str_literal("mail.log");
 	const char *hdr = headers;
 	char *ahdr = NULL;
 #if PHP_SIGCHILD
@@ -536,7 +536,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
 		char *tsm_errmsg = NULL;

 		/* handle old style win smtp sending */
-		if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message) == FAILURE) {
+		if (TSendMail(zend_ini_string_literal("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message) == FAILURE) {
 			if (tsm_errmsg) {
 				php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
 				efree(tsm_errmsg);
@@ -553,7 +553,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
 	if (extra_cmd != NULL) {
 		spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, ZSTR_VAL(extra_cmd));
 	} else {
-		sendmail_cmd = sendmail_path;
+		sendmail_cmd = (char*)sendmail_path;
 	}

 #if PHP_SIGCHILD
@@ -576,7 +576,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
 	sendmail = popen(sendmail_cmd, "w");
 #endif
 	if (extra_cmd != NULL) {
-		efree (sendmail_cmd);
+		efree(sendmail_cmd);
 	}

 	if (sendmail) {
@@ -701,7 +701,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
 /* {{{ PHP_MINFO_FUNCTION */
 PHP_MINFO_FUNCTION(mail)
 {
-	char *sendmail_path = INI_STR("sendmail_path");
+	const char *sendmail_path = zend_ini_string_literal("sendmail_path");

 #ifdef PHP_WIN32
 	if (!sendmail_path) {
diff --git a/ext/standard/tests/mail/mail_basic2.phpt b/ext/standard/tests/mail/mail_basic2.phpt
index 44d8d86310b..96a5a4a10a1 100644
--- a/ext/standard/tests/mail/mail_basic2.phpt
+++ b/ext/standard/tests/mail/mail_basic2.phpt
@@ -20,14 +20,17 @@
 $additional_headers = 'KHeaders';
 $additional_parameters = "-n";
 $outFile = "/tmp/php_test_mailBasic2.out";
-@unlink($outFile);

 echo "-- extra parameters --\n";
 // Calling mail() with all possible arguments
 var_dump( mail($to, $subject, $message, $additional_headers, $additional_parameters) );

 echo file_get_contents($outFile);
-unlink($outFile);
+
+?>
+--CLEAN--
+<?php
+@unlink("/tmp/php_test_mailBasic2.out");
 ?>
 --EXPECTF--
 *** Testing mail() : basic functionality ***
diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c
index 9dcfb733a59..6b5d1061d51 100644
--- a/ext/tidy/tidy.c
+++ b/ext/tidy/tidy.c
@@ -873,7 +873,7 @@ static PHP_RINIT_FUNCTION(tidy)

 static PHP_RSHUTDOWN_FUNCTION(tidy)
 {
-	TG(clean_output) = INI_ORIG_BOOL("tidy.clean_output");
+	TG(clean_output) = zend_ini_parse_bool(zend_ini_str(ZEND_STRL("tidy.clean_output"), /* orig */ true));

 	return SUCCESS;
 }
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index ad2c9edb9dd..ef792b374b1 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -1263,7 +1263,6 @@ ZEND_GET_MODULE(php_zlib)
 static PHP_INI_MH(OnUpdate_zlib_output_compression)
 {
 	int int_value;
-	char *ini_value;
 	if (new_value == NULL) {
 		return FAILURE;
 	}
@@ -1275,9 +1274,9 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression)
 	} else {
 		int_value = (int) zend_ini_parse_quantity_warn(new_value, entry->name);
 	}
-	ini_value = zend_ini_string("output_handler", sizeof("output_handler") - 1, 0);
+	const zend_string *ini_value = zend_ini_str_literal("output_handler");

-	if (ini_value && *ini_value && int_value) {
+	if (ini_value && ZSTR_LEN(ini_value) > 0 && int_value) {
 		php_error_docref("ref.outcontrol", E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!");
 		return FAILURE;
 	}
diff --git a/main/main.c b/main/main.c
index bbd2d18ba18..bb5b700fe7a 100644
--- a/main/main.c
+++ b/main/main.c
@@ -1471,8 +1471,8 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c
 			if (PG(xmlrpc_errors)) {
 				php_printf("<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>" ZEND_LONG_FMT "</int></value></member><member><name>faultString</name><value><string>%s:%s in %s on line %" PRIu32 "%s%s</string></value></member></struct></value></fault></methodResponse>", PG(xmlrpc_error_number), error_type_str, ZSTR_VAL(message), ZSTR_VAL(error_filename), error_lineno, ZSTR_LEN(backtrace) ? "\nStack trace:\n" : "", ZSTR_VAL(backtrace));
 			} else {
-				char *prepend_string = INI_STR("error_prepend_string");
-				char *append_string = INI_STR("error_append_string");
+				const char *prepend_string = zend_ini_string_literal("error_prepend_string");
+				const char *append_string = zend_ini_string_literal("error_append_string");

 				if (PG(html_errors)) {
 					if (type == E_ERROR || type == E_PARSE) {
@@ -2374,7 +2374,7 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
 	}

 	/* disable certain functions as requested by php.ini */
-	zend_disable_functions(INI_STR("disable_functions"));
+	zend_disable_functions(zend_ini_string_literal("disable_functions"));

 	/* make core report what it should */
 	if ((module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core")-1)) != NULL) {
@@ -2638,7 +2638,7 @@ PHPAPI bool php_execute_script_ex(zend_file_handle *primary_file, zval *retval)
 #ifdef PHP_WIN32
 			zend_unset_timeout();
 #endif
-			zend_set_timeout(INI_INT("max_execution_time"), 0);
+			zend_set_timeout(zend_ini_long_literal("max_execution_time"), false);
 		}

 		if (prepend_file_p && result) {
diff --git a/main/php_ini.c b/main/php_ini.c
index e464c05d1fc..4bac70e8877 100644
--- a/main/php_ini.c
+++ b/main/php_ini.c
@@ -334,7 +334,7 @@ static void php_load_zend_extension_cb(void *arg)
 	} else {
 		DL_HANDLE handle;
 		char *libpath;
-		char *extension_dir = INI_STR("extension_dir");
+		const char *extension_dir = zend_ini_string_literal("extension_dir");
 		int slash_suffix = 0;
 		char *err1, *err2;

diff --git a/main/rfc1867.c b/main/rfc1867.c
index f6ffb6fabc7..161a0e4e487 100644
--- a/main/rfc1867.c
+++ b/main/rfc1867.c
@@ -665,8 +665,8 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
 	zend_llist header;
 	void *event_extra_data = NULL;
 	unsigned int llen = 0;
-	zend_long upload_cnt = REQUEST_PARSE_BODY_OPTION_GET(max_file_uploads, INI_INT("max_file_uploads"));
-	zend_long body_parts_cnt = REQUEST_PARSE_BODY_OPTION_GET(max_multipart_body_parts, INI_INT("max_multipart_body_parts"));
+	zend_long upload_cnt = REQUEST_PARSE_BODY_OPTION_GET(max_file_uploads, zend_ini_long_literal("max_file_uploads"));
+	zend_long body_parts_cnt = REQUEST_PARSE_BODY_OPTION_GET(max_multipart_body_parts, zend_ini_long_literal("max_multipart_body_parts"));
 	zend_long post_max_size = REQUEST_PARSE_BODY_OPTION_GET(post_max_size, SG(post_max_size));
 	zend_long max_input_vars = REQUEST_PARSE_BODY_OPTION_GET(max_input_vars, PG(max_input_vars));
 	zend_long upload_max_filesize = REQUEST_PARSE_BODY_OPTION_GET(upload_max_filesize, PG(upload_max_filesize));
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 9566c1abd4e..f3b4ff6b9dd 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -1190,19 +1190,20 @@ static void add_zendext_info(zend_extension *ext) /* {{{ */ {
 #ifdef HAVE_LIBDL
 PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, const char **name) /* {{{ */ {
 	DL_HANDLE handle;
-	char *extension_dir;
-
-	extension_dir = INI_STR("extension_dir");
+	zend_string *extension_dir = zend_ini_str_literal("extension_dir");

+	if (UNEXPECTED(zend_str_has_nul_byte(extension_dir))) {
+		phpdbg_error("extension_dir ini setting contains a nul byte");
+		return NULL;
+	}
 	if (strchr(*path, '/') != NULL || strchr(*path, DEFAULT_SLASH) != NULL) {
 		/* path is fine */
-	} else if (extension_dir && extension_dir[0]) {
+	} else if (extension_dir && ZSTR_LEN(extension_dir) > 0) {
 		char *libpath;
-		int extension_dir_len = strlen(extension_dir);
-		if (IS_SLASH(extension_dir[extension_dir_len-1])) {
-			spprintf(&libpath, 0, "%s%s", extension_dir, *path); /* SAFE */
+		if (IS_SLASH(ZSTR_VAL(extension_dir)[ZSTR_LEN(extension_dir)-1])) {
+			spprintf(&libpath, 0, "%s%s", ZSTR_VAL(extension_dir), *path); /* SAFE */
 		} else {
-			spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, *path); /* SAFE */
+			spprintf(&libpath, 0, "%s%c%s", ZSTR_VAL(extension_dir), DEFAULT_SLASH, *path); /* SAFE */
 		}
 		efree(*path);
 		*path = libpath;
diff --git a/win32/sendmail.c b/win32/sendmail.c
index f267d1fae85..939106f31b0 100644
--- a/win32/sendmail.c
+++ b/win32/sendmail.c
@@ -216,8 +216,8 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message,
 	}

 	/* Fall back to sendmail_from php.ini setting */
-	if (INI_STR("sendmail_from")) {
-		RPath = estrdup(INI_STR("sendmail_from"));
+	if (zend_ini_string_literal("sendmail_from")) {
+		RPath = estrdup(zend_ini_string_literal("sendmail_from"));
 	} else if (headers_lc) {
 		int found = 0;
 		const char *lookup = ZSTR_VAL(headers_lc);
@@ -276,7 +276,7 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message,
 		snprintf(*error_message, HOST_NAME_LEN + 128,
 			"Failed to connect to mailserver at \"%s\" port " ZEND_ULONG_FMT ", verify your \"SMTP\" "
 			"and \"smtp_port\" setting in php.ini or use ini_set()",
-			PW32G(mail_host), !INI_INT("smtp_port") ? 25 : INI_INT("smtp_port"));
+			PW32G(mail_host), !zend_ini_long_literal("smtp_port") ? 25 : zend_ini_long_literal("smtp_port"));
 		return FAILURE;
 	} else {
 		ret = SendText(RPath, Subject, mailTo, data, headers_trim, headers_lc, error_message);
@@ -789,7 +789,7 @@ return 0;
 	}
 	*/

-	portnum = (short) INI_INT("smtp_port");
+	portnum = (short) zend_ini_long_literal("smtp_port");
 	if (!portnum) {
 		portnum = 25;
 	}