CVE-2016-5093: Out-of-bounds Read (CWE-125)
value: The get_icu_value_internal function in ext/intl/locale/locale_methods.c in PHP before 5.5.36, 5.6.x before 5.6.22, and 7.x before 7.0.7 does not ensure the presence of a '\0' character, which allows remote attackers to cause a denial of service (out-of-bounds read) or possibly have unspecified other impact via a crafted locale_get_primary_language call.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 8.6
Published: 2016-08-07T10:59Z
Repository: https://github.com/php/php-src
Language: C
Files changed: ext/intl/locale/locale_methods.c, ext/intl/tests/bug72241.phpt
Commit date: 2016-05-22 17:49:02 -0700
Commit message: Fix bug #72241: get_icu_value_internal out-of-bounds read

Diff: diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c
index c8159bcd5ad..31f60b39a41 100644
--- a/ext/intl/locale/locale_methods.c
+++ b/ext/intl/locale/locale_methods.c
@@ -63,30 +63,30 @@ ZEND_EXTERN_MODULE_GLOBALS( intl )
 /* Based on IANA registry at the time of writing this code
 *
 */
 static const char * const LOC_GRANDFATHERED[] = {
 	"art-lojban",		"i-klingon",		"i-lux",			"i-navajo",		"no-bok",		"no-nyn",
-	"cel-gaulish",		"en-GB-oed",		"i-ami", 		
-	"i-bnn",		"i-default",		"i-enochian",	
-	"i-mingo",		"i-pwn", 		"i-tao", 
+	"cel-gaulish",		"en-GB-oed",		"i-ami",
+	"i-bnn",		"i-default",		"i-enochian",
+	"i-mingo",		"i-pwn", 		"i-tao",
 	"i-tay",		"i-tsu",		"sgn-BE-fr",
 	"sgn-BE-nl",		"sgn-CH-de", 		"zh-cmn",
  	"zh-cmn-Hans", 		"zh-cmn-Hant",		"zh-gan" ,
 	"zh-guoyu", 		"zh-hakka", 		"zh-min",
-	"zh-min-nan", 		"zh-wuu", 		"zh-xiang",	
+	"zh-min-nan", 		"zh-wuu", 		"zh-xiang",
 	"zh-yue",		NULL
 };
 
 /* Based on IANA registry at the time of writing this code
 *  This array lists the preferred values for the grandfathered tags if applicable
-*  This is in sync with the array LOC_GRANDFATHERED	 
+*  This is in sync with the array LOC_GRANDFATHERED
 *  e.g. the offsets of the grandfathered tags match the offset of the preferred  value
 */
 static const int 		LOC_PREFERRED_GRANDFATHERED_LEN = 6;
 static const char * const 	LOC_PREFERRED_GRANDFATHERED[]  = {
 	"jbo",			"tlh",			"lb",
-	"nv", 			"nb",			"nn",			
+	"nv", 			"nb",			"nn",
 	NULL
 };
 
 /*returns TRUE if a is an ID separator FALSE otherwise*/
 #define isIDSeparator(a) (a == '_' || a == '-')
@@ -120,11 +120,11 @@ static int16_t findOffset(const char* const* list, const char* key)
 
 }
 /*}}}*/
 
 static char* getPreferredTag(const char* gf_tag)
-{ 
+{
 	char* result = NULL;
 	int grOffset = 0;
 
 	grOffset = findOffset( LOC_GRANDFATHERED ,gf_tag);
 	if(grOffset < 0) {
@@ -139,19 +139,19 @@ static char* getPreferredTag(const char* gf_tag)
 	}
 	return result;
 }
 
 /* {{{
-* returns the position of next token for lookup 
+* returns the position of next token for lookup
 * or -1 if no token
-* strtokr equivalent search for token in reverse direction 
+* strtokr equivalent search for token in reverse direction
 */
 static int getStrrtokenPos(char* str, int savedPos)
 {
 	int result =-1;
 	int i;
-	
+
 	for(i=savedPos-1; i>=0; i--) {
 		if(isIDSeparator(*(str+i)) ){
 			/* delimiter found; check for singleton */
 			if(i>=2 && isIDSeparator(*(str+i-2)) ){
 				/* a singleton; so send the position of token before the singleton */
@@ -169,20 +169,20 @@ static int getStrrtokenPos(char* str, int savedPos)
 	return result;
 }
 /* }}} */
 
 /* {{{
-* returns the position of a singleton if present 
+* returns the position of a singleton if present
 * returns -1 if no singleton
 * strtok equivalent search for singleton
 */
 static int getSingletonPos(const char* str)
 {
 	int result =-1;
 	int i=0;
 	int len = 0;
-	
+
 	if( str && ((len=strlen(str))>0) ){
 		for( i=0; i<len ; i++){
 			if( isIDSeparator(*(str+i)) ){
 				if( i==1){
 					/* string is of the form x-avy or a-prv1 */
@@ -196,11 +196,11 @@ static int getSingletonPos(const char* str)
 						break;
 					}
 				}
 			}
 		}/* end of for */
-		
+
 	}
 	return result;
 }
 /* }}} */
 
@@ -222,11 +222,11 @@ PHP_NAMED_FUNCTION(zif_locale_get_default)
 /* {{{ proto static string locale_set_default( string $locale )
    Set default locale */
 PHP_NAMED_FUNCTION(zif_locale_set_default)
 {
 	char* locale_name = NULL;
-	int   len=0;	
+	int   len=0;
 
 	if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC,  "s",
 		&locale_name ,&len ) == FAILURE)
 	{
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
@@ -238,18 +238,18 @@ PHP_NAMED_FUNCTION(zif_locale_set_default)
 	if(len == 0) {
 		locale_name =  (char *)uloc_getDefault() ;
 		len = strlen(locale_name);
 	}
 
-	zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);	
+	zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 
 	RETURN_TRUE;
 }
 /* }}} */
 
 /* {{{
-* Gets the value from ICU 
+* Gets the value from ICU
 * common code shared by get_primary_language,get_script or get_region or get_variant
 * result = 0 if error, 1 if successful , -1 if no value
 */
 static char* get_icu_value_internal( const char* loc_name , char* tag_name, int* result , int fromParseLocale)
 {
@@ -282,11 +282,11 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
 			if( strlen(loc_name)>1 && (isIDPrefix(loc_name) == 1) ){
 				return estrdup(loc_name);
 			}
 		}
 
-		singletonPos = getSingletonPos( loc_name );	
+		singletonPos = getSingletonPos( loc_name );
 		if( singletonPos == 0){
 			/* singleton at start of script, region , variant etc.
 			 * or invalid singleton at start of language */
 			return NULL;
 		} else if( singletonPos > 0 ){
@@ -297,11 +297,11 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
 	} /* end of if fromParse */
 
 	} /* end of if != LOC_CANONICAL_TAG */
 
 	if( mod_loc_name == NULL){
-		mod_loc_name = estrdup(loc_name );	
+		mod_loc_name = estrdup(loc_name );
 	}
 
 	/* Proceed to ICU */
     do{
 		tag_value = erealloc( tag_value , buflen  );
@@ -324,10 +324,11 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
 		}
 
 		if( U_FAILURE( status ) ) {
 			if( status == U_BUFFER_OVERFLOW_ERROR ) {
 				status = U_ZERO_ERROR;
+				buflen++; /* add space for \0 */
 				continue;
 			}
 
 			/* Error in retriving data */
 			*result = 0;
@@ -364,11 +365,11 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
 
 /* {{{
 * Gets the value from ICU , called when PHP userspace function is called
 * common code shared by get_primary_language,get_script or get_region or get_variant
 */
-static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
+static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 {
 
 	const char* loc_name        	= NULL;
 	int         loc_name_len    	= 0;
 
@@ -420,51 +421,51 @@ static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 	}
 
 }
 /* }}} */
 
-/* {{{ proto static string Locale::getScript($locale) 
- * gets the script for the $locale 
+/* {{{ proto static string Locale::getScript($locale)
+ * gets the script for the $locale
  }}} */
-/* {{{ proto static string locale_get_script($locale) 
- * gets the script for the $locale 
+/* {{{ proto static string locale_get_script($locale)
+ * gets the script for the $locale
  */
-PHP_FUNCTION( locale_get_script ) 
+PHP_FUNCTION( locale_get_script )
 {
 	get_icu_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
-/* {{{ proto static string Locale::getRegion($locale) 
- * gets the region for the $locale 
+/* {{{ proto static string Locale::getRegion($locale)
+ * gets the region for the $locale
  }}} */
-/* {{{ proto static string locale_get_region($locale) 
- * gets the region for the $locale 
+/* {{{ proto static string locale_get_region($locale)
+ * gets the region for the $locale
  */
-PHP_FUNCTION( locale_get_region ) 
+PHP_FUNCTION( locale_get_region )
 {
 	get_icu_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
-/* {{{ proto static string Locale::getPrimaryLanguage($locale) 
- * gets the primary language for the $locale 
+/* {{{ proto static string Locale::getPrimaryLanguage($locale)
+ * gets the primary language for the $locale
  }}} */
-/* {{{ proto static string locale_get_primary_language($locale) 
- * gets the primary language for the $locale 
+/* {{{ proto static string locale_get_primary_language($locale)
+ * gets the primary language for the $locale
  */
-PHP_FUNCTION(locale_get_primary_language ) 
+PHP_FUNCTION(locale_get_primary_language )
 {
 	get_icu_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
 
 /* {{{
- * common code shared by display_xyz functions to  get the value from ICU 
+ * common code shared by display_xyz functions to  get the value from ICU
  }}} */
-static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
+static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 {
 	const char* loc_name        	= NULL;
 	int         loc_name_len    	= 0;
 
 	const char* disp_loc_name       = NULL;
@@ -486,11 +487,11 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME
 	int         grOffset    	= 0;
 
 	intl_error_reset( NULL TSRMLS_CC );
 
 	if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
-		&loc_name, &loc_name_len , 
+		&loc_name, &loc_name_len ,
 		&disp_loc_name ,&disp_loc_name_len ) == FAILURE)
 	{
 		spprintf(&msg , 0, "locale_get_display_%s : unable to parse input params", tag_name );
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 TSRMLS_CC );
 		efree(msg);
@@ -523,11 +524,11 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME
 	} /* end of if != LOC_CANONICAL_TAG */
 
 	if( mod_loc_name==NULL ){
 		mod_loc_name = estrdup( loc_name );
 	}
-	
+
 	/* Check if disp_loc_name passed , if not use default locale */
 	if( !disp_loc_name){
 		disp_loc_name = estrdup(intl_locale_get_default(TSRMLS_C));
 		free_loc_name = 1;
 	}
@@ -602,11 +603,11 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME
 * gets the name for the $locale in $in_locale or default_locale
  }}} */
 /* {{{ proto static string get_display_name($locale[, $in_locale = null])
 * gets the name for the $locale in $in_locale or default_locale
 */
-PHP_FUNCTION(locale_get_display_name) 
+PHP_FUNCTION(locale_get_display_name)
 {
     get_icu_disp_value_src_php( DISP_NAME , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
@@ -614,11 +615,11 @@ PHP_FUNCTION(locale_get_display_name)
 * gets the language for the $locale in $in_locale or default_locale
  }}} */
 /* {{{ proto static string get_display_language($locale[, $in_locale = null])
 * gets the language for the $locale in $in_locale or default_locale
 */
-PHP_FUNCTION(locale_get_display_language) 
+PHP_FUNCTION(locale_get_display_language)
 {
     get_icu_disp_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
@@ -626,11 +627,11 @@ PHP_FUNCTION(locale_get_display_language)
 * gets the script for the $locale in $in_locale or default_locale
  }}} */
 /* {{{ proto static string get_display_script($locale, $in_locale = null)
 * gets the script for the $locale in $in_locale or default_locale
 */
-PHP_FUNCTION(locale_get_display_script) 
+PHP_FUNCTION(locale_get_display_script)
 {
     get_icu_disp_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
@@ -638,11 +639,11 @@ PHP_FUNCTION(locale_get_display_script)
 * gets the region for the $locale in $in_locale or default_locale
  }}} */
 /* {{{ proto static string get_display_region($locale, $in_locale = null)
 * gets the region for the $locale in $in_locale or default_locale
 */
-PHP_FUNCTION(locale_get_display_region) 
+PHP_FUNCTION(locale_get_display_region)
 {
     get_icu_disp_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
@@ -652,11 +653,11 @@ PHP_FUNCTION(locale_get_display_region)
  }}} */
 /* {{{
 * proto static string get_display_variant($locale, $in_locale = null)
 * gets the variant for the $locale in $in_locale or default_locale
 */
-PHP_FUNCTION(locale_get_display_variant) 
+PHP_FUNCTION(locale_get_display_variant)
 {
     get_icu_disp_value_src_php( LOC_VARIANT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
@@ -665,11 +666,11 @@ PHP_FUNCTION(locale_get_display_variant)
  * pairs for this locale. The keys are keys to the array (doh!)
  * }}}*/
  /* {{{ proto static array locale_get_keywords(string $locale) {
  * return an associative array containing keyword-value
  * pairs for this locale. The keys are keys to the array (doh!)
- */ 
+ */
 PHP_FUNCTION( locale_get_keywords )
 {
     UEnumeration*   e        = NULL;
     UErrorCode      status   = U_ZERO_ERROR;
 
@@ -677,14 +678,14 @@ PHP_FUNCTION( locale_get_keywords )
     int32_t         kw_key_len    = 0;
 
     const char*       	loc_name        = NULL;
     int        	 	loc_name_len    = 0;
 
-/* 
-	ICU expects the buffer to be allocated  before calling the function 
-	and so the buffer size has been explicitly specified 
-	ICU uloc.h #define 	ULOC_KEYWORD_AND_VALUES_CAPACITY   100 
+/*
+	ICU expects the buffer to be allocated  before calling the function
+	and so the buffer size has been explicitly specified
+	ICU uloc.h #define 	ULOC_KEYWORD_AND_VALUES_CAPACITY   100
 	hence the kw_value buffer size is 100
 */
 	char*	 	kw_value        = NULL;
     int32_t     kw_value_len    = 100;
 
@@ -719,11 +720,11 @@ PHP_FUNCTION( locale_get_keywords )
 				status = U_ZERO_ERROR;
 				kw_value = erealloc( kw_value , kw_value_len+1);
 				kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len+1 ,  &status );
 			} else if(!U_FAILURE(status)) {
 				kw_value = erealloc( kw_value , kw_value_len+1);
-			} 
+			}
 			if (U_FAILURE(status)) {
 	        		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_get_keywords: Error encountered while getting the keyword  value for the  keyword", 0 TSRMLS_CC );
 				if( kw_value){
 					efree( kw_value );
 				}
@@ -738,26 +739,26 @@ PHP_FUNCTION( locale_get_keywords )
 
     uenum_close( e );
 }
 /* }}} */
 
- /* {{{ proto static string Locale::canonicalize($locale) 
- * @return string the canonicalized locale 
+ /* {{{ proto static string Locale::canonicalize($locale)
+ * @return string the canonicalized locale
  * }}} */
- /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale) 
+ /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale)
  * @param string $locale	The locale string to canonicalize
  */
 PHP_FUNCTION(locale_canonicalize)
 {
 	get_icu_value_src_php( LOC_CANONICALIZE_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
 }
 /* }}} */
 
-/* {{{ append_key_value 
+/* {{{ append_key_value
 * Internal function which is called from locale_compose
 * gets the value for the key_name and appends to the loc_name
-* returns 1 if successful , -1 if not found , 
+* returns 1 if successful , -1 if not found ,
 * 0 if array element is not a string , -2 if buffer-overflow
 */
 static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_name)
 {
 	zval**	ele_value	= NULL;
@@ -765,11 +766,11 @@ static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_
 	if(zend_hash_find(hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
 		if(Z_TYPE_PP(ele_value)!= IS_STRING ){
 			/* element value is not a string */
 			return FAILURE;
 		}
-		if(strcmp(key_name, LOC_LANG_TAG) != 0 && 
+		if(strcmp(key_name, LOC_LANG_TAG) != 0 &&
 		   strcmp(key_name, LOC_GRANDFATHERED_LANG_TAG)!=0 ) {
 			/* not lang or grandfathered tag */
 			smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
 		}
 		smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
@@ -790,15 +791,15 @@ static void add_prefix(smart_str* loc_name, char* key_name)
 		smart_str_appendl(loc_name, PRIVATE_PREFIX , sizeof(PRIVATE_PREFIX)-1);
 	}
 }
 /* }}} */
 
-/* {{{ append_multiple_key_values 
+/* {{{ append_multiple_key_values
 * Internal function which is called from locale_compose
 * gets the multiple values for the key_name and appends to the loc_name
-* used for 'variant','extlang','private' 
-* returns 1 if successful , -1 if not found , 
+* used for 'variant','extlang','private'
+* returns 1 if successful , -1 if not found ,
 * 0 if array element is not a string , -2 if buffer-overflow
 */
 static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, char* key_name TSRMLS_DC)
 {
 	zval**	ele_value    	= NULL;
@@ -848,12 +849,12 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
 			max_value  = MAX_NO_PRIVATE;
 		}
 
 		/* Multiple variant values as variant0, variant1 ,variant2 */
 		isFirstSubtag = 0;
-		for( i=0 ; i< max_value; i++ ){  
-			snprintf( cur_key_name , 30, "%s%d", key_name , i);	
+		for( i=0 ; i< max_value; i++ ){
+			snprintf( cur_key_name , 30, "%s%d", key_name , i);
 			if( zend_hash_find( hash_arr , cur_key_name , strlen(cur_key_name) + 1,(void **)&ele_value ) == SUCCESS ){
 				if( Z_TYPE_PP(ele_value)!= IS_STRING ){
 					/* variant is not a string */
 					return FAILURE;
 				}
@@ -871,11 +872,11 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
 }
 /* }}} */
 
 /*{{{
 * If applicable sets error message and aborts locale_compose gracefully
-* returns 0  if locale_compose needs to be aborted 
+* returns 0  if locale_compose needs to be aborted
 * otherwise returns 1
 */
 static int handleAppendResult( int result, smart_str* loc_name TSRMLS_DC)
 {
 	intl_error_reset( NULL TSRMLS_CC );
@@ -888,15 +889,15 @@ static int handleAppendResult( int result, smart_str* loc_name TSRMLS_DC)
 	return 1;
 }
 /* }}} */
 
 #define RETURN_SMART_STR(s) smart_str_0((s)); RETURN_STRINGL((s)->c, (s)->len, 0)
-/* {{{ proto static string Locale::composeLocale($array) 
-* Creates a locale by combining the parts of locale-ID passed	
+/* {{{ proto static string Locale::composeLocale($array)
+* Creates a locale by combining the parts of locale-ID passed
 * }}} */
-/* {{{ proto static string compose_locale($array) 
-* Creates a locale by combining the parts of locale-ID passed	
+/* {{{ proto static string compose_locale($array)
+* Creates a locale by combining the parts of locale-ID passed
 * }}} */
 PHP_FUNCTION(locale_compose)
 {
 	smart_str      	loc_name_s = {0};
 	smart_str *loc_name = &loc_name_s;
@@ -918,20 +919,20 @@ PHP_FUNCTION(locale_compose)
 
 	if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
 		RETURN_FALSE;
 
 	/* Check for grandfathered first */
-	result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);	
+	result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);
 	if( result == SUCCESS){
 		RETURN_SMART_STR(loc_name);
 	}
 	if( !handleAppendResult( result, loc_name TSRMLS_CC)){
 		RETURN_FALSE;
 	}
 
 	/* Not grandfathered */
-	result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);	
+	result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);
 	if( result == LOC_NOT_FOUND ){
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
 		"locale_compose: parameter array does not contain 'language' tag.", 0 TSRMLS_CC );
 		smart_str_free(loc_name);
 		RETURN_FALSE;
@@ -945,23 +946,23 @@ PHP_FUNCTION(locale_compose)
 	if( !handleAppendResult( result, loc_name TSRMLS_CC)){
 		RETURN_FALSE;
 	}
 
 	/* Script */
-	result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); 
+	result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG);
 	if( !handleAppendResult( result, loc_name TSRMLS_CC)){
 		RETURN_FALSE;
 	}
-	
+
 	/* Region */
 	result = append_key_value( loc_name, hash_arr , LOC_REGION_TAG);
 	if( !handleAppendResult( result, loc_name TSRMLS_CC)){
 		RETURN_FALSE;
 	}
 
 	/* Variant */
-	result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); 
+	result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC);
 	if( !handleAppendResult( result, loc_name TSRMLS_CC)){
 		RETURN_FALSE;
 	}
 
 	/* Private */
@@ -983,20 +984,20 @@ PHP_FUNCTION(locale_compose)
 */
 static char* get_private_subtags(const char* loc_name)
 {
 	char* 	result =NULL;
 	int 	singletonPos = 0;
-	int 	len =0; 
+	int 	len =0;
 	const char* 	mod_loc_name =NULL;
 
 	if( loc_name && (len = strlen(loc_name)>0 ) ){
-		mod_loc_name = loc_name ; 
+		mod_loc_name = loc_name ;
 		len   = strlen(mod_loc_name);
 		while( (singletonPos = getSingletonPos(mod_loc_name))!= -1){
 
-			if( singletonPos!=-1){ 
-				if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){		
+			if( singletonPos!=-1){
+				if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){
 					/* private subtag start found */
 					if( singletonPos + 2 ==  len){
 						/* loc_name ends with '-x-' ; return  NULL */
 					}
 					else{
@@ -1017,11 +1018,11 @@ static char* get_private_subtags(const char* loc_name)
 				}
 			}
 
 		} /* end of while */
 	}
-	
+
 	return result;
 }
 /* }}} */
 
 /* {{{ code used by locale_parse
@@ -1042,24 +1043,24 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name
 		key_value = get_private_subtags( loc_name );
 		result = 1;
 	} else {
 		key_value = get_icu_value_internal( loc_name , key_name , &result,1 );
 	}
-	if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || 
+	if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) ||
 		( strcmp(key_name , LOC_VARIANT_TAG)==0) ){
 		if( result > 0 && key_value){
 			/* Tokenize on the "_" or "-"  */
-			token = php_strtok_r( key_value , DELIMITER ,&last_ptr);	
+			token = php_strtok_r( key_value , DELIMITER ,&last_ptr);
 			if( cur_key_name ){
 				efree( cur_key_name);
 			}
 			cur_key_name = (char*)ecalloc( 25,  25);
-			sprintf( cur_key_name , "%s%d", key_name , cnt++);	
+			sprintf( cur_key_name , "%s%d", key_name , cnt++);
 			add_assoc_string( hash_arr, cur_key_name , token ,TRUE );
 			/* tokenize on the "_" or "-" and stop  at singleton if any */
 			while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
-				sprintf( cur_key_name , "%s%d", key_name , cnt++);	
+				sprintf( cur_key_name , "%s%d", key_name , cnt++);
 				add_assoc_string( hash_arr, cur_key_name , token , TRUE );
 			}
 /*
 			if( strcmp(key_name, LOC_PRIVATE_TAG) == 0 ){
 			}
@@ -1075,20 +1076,20 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name
 	if( cur_key_name ){
 		efree( cur_key_name);
 	}
 	/*if( key_name != LOC_PRIVATE_TAG && key_value){*/
 	if( key_value){
-		efree(key_value);	
+		efree(key_value);
 	}
 	return cur_result;
 }
 /* }}} */
 
-/* {{{ proto static array Locale::parseLocale($locale) 
+/* {{{ proto static array Locale::parseLocale($locale)
 * parses a locale-id into an array the different parts of it
  }}} */
-/* {{{ proto static array parse_locale($locale) 
+/* {{{ proto static array parse_locale($locale)
 * parses a locale-id into an array the different parts of it
 */
 PHP_FUNCTION(locale_parse)
 {
     const char* loc_name        = NULL;
@@ -1142,11 +1143,11 @@ PHP_FUNCTION(locale_get_all_variants)
 	char*	token		= NULL;
 	char*	variant		= NULL;
 	char*	saved_ptr	= NULL;
 
 	intl_error_reset( NULL TSRMLS_CC );
-	
+
 	if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
 	&loc_name, &loc_name_len ) == FAILURE)
 	{
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
 	     "locale_parse: unable to parse input params", 0 TSRMLS_CC );
@@ -1160,30 +1161,30 @@ PHP_FUNCTION(locale_get_all_variants)
 
 
 	array_init( return_value );
 
 	/* If the locale is grandfathered, stop, no variants */
-	if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){ 
+	if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){
 		/* ("Grandfathered Tag. No variants."); */
 	}
-	else {	
+	else {
 	/* Call ICU variant */
 		variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);
 		if( result > 0 && variant){
 			/* Tokenize on the "_" or "-" */
-			token = php_strtok_r( variant , DELIMITER , &saved_ptr);	
+			token = php_strtok_r( variant , DELIMITER , &saved_ptr);
 			add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
 			/* tokenize on the "_" or "-" and stop  at singleton if any	*/
 			while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
  				add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
 			}
 		}
 		if( variant ){
 			efree( variant );
 		}
 	}
-			
+
 
 }
 /* }}} */
 
 /*{{{
@@ -1218,15 +1219,15 @@ static int strToMatch(const char* str ,char *retstr)
     return(result);
 }
 /* }}} */
 
 /* {{{ proto static boolean Locale::filterMatches(string $langtag, string $locale[, bool $canonicalize])
-* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
+* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
 */
 /* }}} */
 /* {{{ proto boolean locale_filter_matches(string $langtag, string $locale[, bool $canonicalize])
-* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
+* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
 */
 PHP_FUNCTION(locale_filter_matches)
 {
 	char*       	lang_tag        = NULL;
 	int         	lang_tag_len    = 0;
@@ -1241,17 +1242,17 @@ PHP_FUNCTION(locale_filter_matches)
 	char*       	can_loc_range   = NULL;
 
 	char*       	cur_lang_tag    = NULL;
 	char*       	cur_loc_range   = NULL;
 
-	zend_bool 	boolCanonical 	= 0;	
+	zend_bool 	boolCanonical 	= 0;
 	UErrorCode	status		= U_ZERO_ERROR;
 
 	intl_error_reset( NULL TSRMLS_CC );
-	
+
 	if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b",
-		&lang_tag, &lang_tag_len , &loc_range , &loc_range_len , 
+		&lang_tag, &lang_tag_len , &loc_range , &loc_range_len ,
 		&boolCanonical) == FAILURE)
 	{
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
 		"locale_filter_matches: unable to parse input params", 0 TSRMLS_CC );
 
@@ -1268,19 +1269,19 @@ PHP_FUNCTION(locale_filter_matches)
 
 	if( boolCanonical ){
 		/* canonicalize loc_range */
 		can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0);
 		if( result ==0) {
-			intl_error_set( NULL, status, 
+			intl_error_set( NULL, status,
 				"locale_filter_matches : unable to canonicalize loc_range" , 0 TSRMLS_CC );
 			RETURN_FALSE;
 		}
 
 		/* canonicalize lang_tag */
 		can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result ,  0);
 		if( result ==0) {
-			intl_error_set( NULL, status, 
+			intl_error_set( NULL, status,
 				"locale_filter_matches : unable to canonicalize lang_tag" , 0 TSRMLS_CC );
 			RETURN_FALSE;
 		}
 
 		/* Convert to lower case for case-insensitive comparison */
@@ -1304,15 +1305,15 @@ PHP_FUNCTION(locale_filter_matches)
 			RETURN_FALSE;
 		}
 
 		/* check if prefix */
 		token 	= strstr( cur_lang_tag , cur_loc_range );
-	
+
 		if( token && (token==cur_lang_tag) ){
 			/* check if the char. after match is SEPARATOR */
 			chrcheck = token + (strlen(cur_loc_range));
-			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
+			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
 				if( cur_lang_tag){
 					efree( cur_lang_tag );
 				}
 				if( cur_loc_range){
 					efree( cur_loc_range );
@@ -1344,11 +1345,11 @@ PHP_FUNCTION(locale_filter_matches)
 
 	} /* end of if isCanonical */
 	else{
 		/* Convert to lower case for case-insensitive comparison */
 		cur_lang_tag = ecalloc( 1, strlen(lang_tag ) + 1);
-		
+
 		result = strToMatch( lang_tag , cur_lang_tag);
 		if( result == 0) {
 			efree( cur_lang_tag );
 			RETURN_FALSE;
 		}
@@ -1360,15 +1361,15 @@ PHP_FUNCTION(locale_filter_matches)
 			RETURN_FALSE;
 		}
 
 		/* check if prefix */
 		token 	= strstr( cur_lang_tag , cur_loc_range );
-		
+
 		if( token && (token==cur_lang_tag) ){
 			/* check if the char. after match is SEPARATOR */
 			chrcheck = token + (strlen(cur_loc_range));
-			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
+			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
 				if( cur_lang_tag){
 					efree( cur_lang_tag );
 				}
 				if( cur_loc_range){
 					efree( cur_loc_range );
@@ -1391,21 +1392,21 @@ PHP_FUNCTION(locale_filter_matches)
 /* }}} */
 
 static void array_cleanup( char* arr[] , int arr_size)
 {
 	int i=0;
-	for( i=0; i< arr_size; i++ ){ 
+	for( i=0; i< arr_size; i++ ){
 		if( arr[i*2] ){
 			efree( arr[i*2]);
 		}
 	}
 	efree(arr);
 }
 
 #define LOOKUP_CLEAN_RETURN(value)	array_cleanup(cur_arr, cur_arr_len); return (value)
 /* {{{
-* returns the lookup result to lookup_loc_range_src_php 
+* returns the lookup result to lookup_loc_range_src_php
 * internal function
 */
 static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int canonicalize  TSRMLS_DC)
 {
 	int	i = 0;
@@ -1425,43 +1426,43 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca
 	cur_arr = ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *));
 	/* convert the array to lowercase , also replace hyphens with the underscore and store it in cur_arr */
 	for(zend_hash_internal_pointer_reset(hash_arr);
 		zend_hash_has_more_elements(hash_arr) == SUCCESS;
 		zend_hash_move_forward(hash_arr)) {
-		
+
 		if (zend_hash_get_current_data(hash_arr, (void**)&ele_value) == FAILURE) {
 			/* Should never actually fail since the key is known to exist.*/
 			continue;
 		}
 		if(Z_TYPE_PP(ele_value)!= IS_STRING) {
 			/* element value is not a string */
 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: locale array element is not a string", 0 TSRMLS_CC);
 			LOOKUP_CLEAN_RETURN(NULL);
-		} 
+		}
 		cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_PP(ele_value), Z_STRLEN_PP(ele_value));
 		result = strToMatch(Z_STRVAL_PP(ele_value), cur_arr[cur_arr_len*2]);
 		if(result == 0) {
 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0 TSRMLS_CC);
 			LOOKUP_CLEAN_RETURN(NULL);
 		}
 		cur_arr[cur_arr_len*2+1] = Z_STRVAL_PP(ele_value);
-		cur_arr_len++ ; 
+		cur_arr_len++ ;
 	} /* end of for */
 
 	/* Canonicalize array elements */
 	if(canonicalize) {
-		for(i=0; i<cur_arr_len; i++) { 
+		for(i=0; i<cur_arr_len; i++) {
 			lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
 			if(result != 1 || lang_tag == NULL || !lang_tag[0]) {
 				if(lang_tag) {
 					efree(lang_tag);
 				}
 				intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
 				LOOKUP_CLEAN_RETURN(NULL);
 			}
 			cur_arr[i*2] = erealloc(cur_arr[i*2], strlen(lang_tag)+1);
-			result = strToMatch(lang_tag, cur_arr[i*2]);	
+			result = strToMatch(lang_tag, cur_arr[i*2]);
 			efree(lang_tag);
 			if(result == 0) {
 				intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
 				LOOKUP_CLEAN_RETURN(NULL);
 			}
@@ -1480,15 +1481,15 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca
 			}
 			LOOKUP_CLEAN_RETURN(NULL);
 		} else {
 			loc_range = can_loc_range;
 		}
-	} 
+	}
 
 	cur_loc_range = ecalloc(1, strlen(loc_range)+1);
 	/* convert to lower and replace hyphens */
-	result = strToMatch(loc_range, cur_loc_range);	
+	result = strToMatch(loc_range, cur_loc_range);
 	if(can_loc_range) {
 		efree(can_loc_range);
 	}
 	if(result == 0) {
 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
@@ -1496,12 +1497,12 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca
 	}
 
 	/* Lookup for the lang_tag match */
 	saved_pos = strlen(cur_loc_range);
 	while(saved_pos > 0) {
-		for(i=0; i< cur_arr_len; i++){ 
-			if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {	
+		for(i=0; i< cur_arr_len; i++){
+			if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
 				/* Match found */
 				return_value = estrdup(canonicalize?cur_arr[i*2]:cur_arr[i*2+1]);
 				efree(cur_loc_range);
 				LOOKUP_CLEAN_RETURN(return_value);
 			}
@@ -1513,18 +1514,18 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca
 	efree(cur_loc_range);
 	LOOKUP_CLEAN_RETURN(NULL);
 }
 /* }}} */
 
-/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) 
+/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
 * Searchs the items in $langtag for the best match to the language
-* range 
+* range
 */
 /* }}} */
 /* {{{ proto string locale_lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
 * Searchs the items in $langtag for the best match to the language
-* range 
+* range
 */
 PHP_FUNCTION(locale_lookup)
 {
 	char*      	fallback_loc  		= NULL;
 	int        	fallback_loc_len	= 0;
@@ -1550,12 +1551,12 @@ PHP_FUNCTION(locale_lookup)
 
 	hash_arr = HASH_OF(arr);
 
 	if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
 		RETURN_EMPTY_STRING();
-	} 
-	
+	}
+
 	result = lookup_loc_range(loc_range, hash_arr, boolCanonical TSRMLS_CC);
 	if(result == NULL || result[0] == '\0') {
 		if( fallback_loc ) {
 			result = estrndup(fallback_loc, fallback_loc_len);
 		} else {
@@ -1588,14 +1589,14 @@ PHP_FUNCTION(locale_accept_from_http)
 	{
 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
 		"locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC );
 		RETURN_FALSE;
 	}
-	
+
 	available = ures_openAvailableLocales(NULL, &status);
 	INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list");
-	len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, 
+	len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN,
 						&outResult, http_accept, available, &status);
 	uenum_close(available);
 	INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale");
 	if (len < 0 || outResult == ULOC_ACCEPT_FAILED) {
 		RETURN_FALSE;
diff --git a/ext/intl/tests/bug72241.phpt b/ext/intl/tests/bug72241.phpt
new file mode 100644
index 00000000000..397e1e7834b
--- /dev/null
+++ b/ext/intl/tests/bug72241.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #72241: get_icu_value_internal out-of-bounds read
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$var1=str_repeat("A", 1000);
+$out = locale_get_primary_language($var1);
+echo strlen($out) . PHP_EOL;
+echo unpack('H*', $out)[1] . PHP_EOL;
+--EXPECT--
+1000
+61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161
+

Vulnerable code: 	"cel-gaulish",		"en-GB-oed",		"i-ami", 		
	"i-bnn",		"i-default",		"i-enochian",	
	"i-mingo",		"i-pwn", 		"i-tao", 
	"zh-min-nan", 		"zh-wuu", 		"zh-xiang",	
*  This is in sync with the array LOC_GRANDFATHERED	 
	"nv", 			"nb",			"nn",			
{ 
* returns the position of next token for lookup 
* strtokr equivalent search for token in reverse direction 
	
* returns the position of a singleton if present 
	
		
	int   len=0;	
	zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);	
* Gets the value from ICU 
		singletonPos = getSingletonPos( loc_name );	
		mod_loc_name = estrdup(loc_name );	
static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
/* {{{ proto static string Locale::getScript($locale) 
 * gets the script for the $locale 
/* {{{ proto static string locale_get_script($locale) 
 * gets the script for the $locale 
PHP_FUNCTION( locale_get_script ) 
/* {{{ proto static string Locale::getRegion($locale) 
 * gets the region for the $locale 
/* {{{ proto static string locale_get_region($locale) 
 * gets the region for the $locale 
PHP_FUNCTION( locale_get_region ) 
/* {{{ proto static string Locale::getPrimaryLanguage($locale) 
 * gets the primary language for the $locale 
/* {{{ proto static string locale_get_primary_language($locale) 
 * gets the primary language for the $locale 
PHP_FUNCTION(locale_get_primary_language ) 
 * common code shared by display_xyz functions to  get the value from ICU 
static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
		&loc_name, &loc_name_len , 
	
PHP_FUNCTION(locale_get_display_name) 
PHP_FUNCTION(locale_get_display_language) 
PHP_FUNCTION(locale_get_display_script) 
PHP_FUNCTION(locale_get_display_region) 
PHP_FUNCTION(locale_get_display_variant) 
 */ 
/* 
	ICU expects the buffer to be allocated  before calling the function 
	and so the buffer size has been explicitly specified 
	ICU uloc.h #define 	ULOC_KEYWORD_AND_VALUES_CAPACITY   100 
			} 
 /* {{{ proto static string Locale::canonicalize($locale) 
 * @return string the canonicalized locale 
 /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale) 
/* {{{ append_key_value 
* returns 1 if successful , -1 if not found , 
		if(strcmp(key_name, LOC_LANG_TAG) != 0 && 
/* {{{ append_multiple_key_values 
* used for 'variant','extlang','private' 
* returns 1 if successful , -1 if not found , 
		for( i=0 ; i< max_value; i++ ){  
			snprintf( cur_key_name , 30, "%s%d", key_name , i);	
* returns 0  if locale_compose needs to be aborted 
/* {{{ proto static string Locale::composeLocale($array) 
* Creates a locale by combining the parts of locale-ID passed	
/* {{{ proto static string compose_locale($array) 
* Creates a locale by combining the parts of locale-ID passed	
	result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);	
	result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);	
	result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); 
	
	result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); 
	int 	len =0; 
		mod_loc_name = loc_name ; 
			if( singletonPos!=-1){ 
				if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){		
	
	if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || 
			token = php_strtok_r( key_value , DELIMITER ,&last_ptr);	
			sprintf( cur_key_name , "%s%d", key_name , cnt++);	
				sprintf( cur_key_name , "%s%d", key_name , cnt++);	
		efree(key_value);	
/* {{{ proto static array Locale::parseLocale($locale) 
/* {{{ proto static array parse_locale($locale) 
	
	if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){ 
	else {	
			token = php_strtok_r( variant , DELIMITER , &saved_ptr);	
			
* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
	zend_bool 	boolCanonical 	= 0;	
	
		&lang_tag, &lang_tag_len , &loc_range , &loc_range_len , 
			intl_error_set( NULL, status, 
			intl_error_set( NULL, status, 
	
			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
		
		
			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
	for( i=0; i< arr_size; i++ ){ 
* returns the lookup result to lookup_loc_range_src_php 
		
		} 
		cur_arr_len++ ; 
		for(i=0; i<cur_arr_len; i++) { 
			result = strToMatch(lang_tag, cur_arr[i*2]);	
	} 
	result = strToMatch(loc_range, cur_loc_range);	
		for(i=0; i< cur_arr_len; i++){ 
			if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {	
/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) 
* range 
* range 
	} 
	
	
	len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, 
Fixed code: 	"cel-gaulish",		"en-GB-oed",		"i-ami",
	"i-bnn",		"i-default",		"i-enochian",
	"i-mingo",		"i-pwn", 		"i-tao",
	"zh-min-nan", 		"zh-wuu", 		"zh-xiang",
*  This is in sync with the array LOC_GRANDFATHERED
	"nv", 			"nb",			"nn",
{
* returns the position of next token for lookup
* strtokr equivalent search for token in reverse direction

* returns the position of a singleton if present


	int   len=0;
	zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
* Gets the value from ICU
		singletonPos = getSingletonPos( loc_name );
		mod_loc_name = estrdup(loc_name );
				buflen++; /* add space for \0 */
static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
/* {{{ proto static string Locale::getScript($locale)
 * gets the script for the $locale
/* {{{ proto static string locale_get_script($locale)
 * gets the script for the $locale
PHP_FUNCTION( locale_get_script )
/* {{{ proto static string Locale::getRegion($locale)
 * gets the region for the $locale
/* {{{ proto static string locale_get_region($locale)
 * gets the region for the $locale
PHP_FUNCTION( locale_get_region )
/* {{{ proto static string Locale::getPrimaryLanguage($locale)
 * gets the primary language for the $locale
/* {{{ proto static string locale_get_primary_language($locale)
 * gets the primary language for the $locale
PHP_FUNCTION(locale_get_primary_language )
 * common code shared by display_xyz functions to  get the value from ICU
static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
		&loc_name, &loc_name_len ,

PHP_FUNCTION(locale_get_display_name)
PHP_FUNCTION(locale_get_display_language)
PHP_FUNCTION(locale_get_display_script)
PHP_FUNCTION(locale_get_display_region)
PHP_FUNCTION(locale_get_display_variant)
 */
/*
	ICU expects the buffer to be allocated  before calling the function
	and so the buffer size has been explicitly specified
	ICU uloc.h #define 	ULOC_KEYWORD_AND_VALUES_CAPACITY   100
			}
 /* {{{ proto static string Locale::canonicalize($locale)
 * @return string the canonicalized locale
 /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale)
/* {{{ append_key_value
* returns 1 if successful , -1 if not found ,
		if(strcmp(key_name, LOC_LANG_TAG) != 0 &&
/* {{{ append_multiple_key_values
* used for 'variant','extlang','private'
* returns 1 if successful , -1 if not found ,
		for( i=0 ; i< max_value; i++ ){
			snprintf( cur_key_name , 30, "%s%d", key_name , i);
* returns 0  if locale_compose needs to be aborted
/* {{{ proto static string Locale::composeLocale($array)
* Creates a locale by combining the parts of locale-ID passed
/* {{{ proto static string compose_locale($array)
* Creates a locale by combining the parts of locale-ID passed
	result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);
	result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);
	result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG);

	result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC);
	int 	len =0;
		mod_loc_name = loc_name ;
			if( singletonPos!=-1){
				if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){

	if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) ||
			token = php_strtok_r( key_value , DELIMITER ,&last_ptr);
			sprintf( cur_key_name , "%s%d", key_name , cnt++);
				sprintf( cur_key_name , "%s%d", key_name , cnt++);
		efree(key_value);
/* {{{ proto static array Locale::parseLocale($locale)
/* {{{ proto static array parse_locale($locale)

	if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){
	else {
			token = php_strtok_r( variant , DELIMITER , &saved_ptr);

* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
	zend_bool 	boolCanonical 	= 0;

		&lang_tag, &lang_tag_len , &loc_range , &loc_range_len ,
			intl_error_set( NULL, status,
			intl_error_set( NULL, status,

			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){


			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
	for( i=0; i< arr_size; i++ ){
* returns the lookup result to lookup_loc_range_src_php

		}
		cur_arr_len++ ;
		for(i=0; i<cur_arr_len; i++) {
			result = strToMatch(lang_tag, cur_arr[i*2]);
	}
	result = strToMatch(loc_range, cur_loc_range);
		for(i=0; i< cur_arr_len; i++){
			if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
* range
* range
	}


	len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN,
--TEST--
Bug #72241: get_icu_value_internal out-of-bounds read
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
$var1=str_repeat("A", 1000);
$out = locale_get_primary_language($var1);
echo strlen($out) . PHP_EOL;
echo unpack('H*', $out)[1] . PHP_EOL;
--EXPECT--
1000
61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161