mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
ICU: check for U_STRING_NOT_TERMINATED_WARNING.
Fixes memory error in cases where the length of the language name returned by uloc_getLanguage() is exactly ULOC_LANG_CAPACITY, in which case the status is set to U_STRING_NOT_TERMINATED_WARNING. Also check in call sites for other ICU functions that are expected to return a C string to be safe (no bug is known at these other call sites). Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/2098874d-c111-41e4-9063-30bcf135226b@gmail.com
This commit is contained in:
@@ -2468,7 +2468,7 @@ pg_ucol_open(const char *loc_str)
|
|||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("could not get language from locale \"%s\": %s",
|
(errmsg("could not get language from locale \"%s\": %s",
|
||||||
@@ -2504,7 +2504,7 @@ pg_ucol_open(const char *loc_str)
|
|||||||
* Pretend the error came from ucol_open(), for consistent error
|
* Pretend the error came from ucol_open(), for consistent error
|
||||||
* message across ICU versions.
|
* message across ICU versions.
|
||||||
*/
|
*/
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
ucol_close(collator);
|
ucol_close(collator);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@@ -2639,7 +2639,8 @@ icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar)
|
|||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1,
|
len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1,
|
||||||
buff_uchar, len_uchar, &status);
|
buff_uchar, len_uchar, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) ||
|
||||||
|
status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("%s failed: %s", "ucnv_fromUChars",
|
(errmsg("%s failed: %s", "ucnv_fromUChars",
|
||||||
u_errorName(status))));
|
u_errorName(status))));
|
||||||
@@ -2681,7 +2682,7 @@ icu_set_collation_attributes(UCollator *collator, const char *loc,
|
|||||||
icu_locale_id = palloc(len + 1);
|
icu_locale_id = palloc(len + 1);
|
||||||
*status = U_ZERO_ERROR;
|
*status = U_ZERO_ERROR;
|
||||||
len = uloc_canonicalize(loc, icu_locale_id, len + 1, status);
|
len = uloc_canonicalize(loc, icu_locale_id, len + 1, status);
|
||||||
if (U_FAILURE(*status))
|
if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lower_str = asc_tolower(icu_locale_id, strlen(icu_locale_id));
|
lower_str = asc_tolower(icu_locale_id, strlen(icu_locale_id));
|
||||||
@@ -2765,7 +2766,6 @@ icu_set_collation_attributes(UCollator *collator, const char *loc,
|
|||||||
|
|
||||||
pfree(lower_str);
|
pfree(lower_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2789,7 +2789,7 @@ icu_language_tag(const char *loc_str, int elevel)
|
|||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
if (elevel > 0)
|
if (elevel > 0)
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
@@ -2811,19 +2811,12 @@ icu_language_tag(const char *loc_str, int elevel)
|
|||||||
langtag = palloc(buflen);
|
langtag = palloc(buflen);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int32_t len;
|
|
||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
len = uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
|
uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
|
||||||
|
|
||||||
/*
|
/* try again if the buffer is not large enough */
|
||||||
* If the result fits in the buffer exactly (len == buflen),
|
|
||||||
* uloc_toLanguageTag() will return success without nul-terminating
|
|
||||||
* the result. Check for either U_BUFFER_OVERFLOW_ERROR or len >=
|
|
||||||
* buflen and try again.
|
|
||||||
*/
|
|
||||||
if ((status == U_BUFFER_OVERFLOW_ERROR ||
|
if ((status == U_BUFFER_OVERFLOW_ERROR ||
|
||||||
(U_SUCCESS(status) && len >= buflen)) &&
|
status == U_STRING_NOT_TERMINATED_WARNING) &&
|
||||||
buflen < MaxAllocSize)
|
buflen < MaxAllocSize)
|
||||||
{
|
{
|
||||||
buflen = Min(buflen * 2, MaxAllocSize);
|
buflen = Min(buflen * 2, MaxAllocSize);
|
||||||
@@ -2878,7 +2871,7 @@ icu_validate_locale(const char *loc_str)
|
|||||||
/* validate that we can extract the language */
|
/* validate that we can extract the language */
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errmsg("could not get language from ICU locale \"%s\": %s",
|
(errmsg("could not get language from ICU locale \"%s\": %s",
|
||||||
@@ -2901,7 +2894,7 @@ icu_validate_locale(const char *loc_str)
|
|||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status);
|
uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strcmp(lang, otherlang) == 0)
|
if (strcmp(lang, otherlang) == 0)
|
||||||
|
|||||||
@@ -2252,7 +2252,7 @@ icu_language_tag(const char *loc_str)
|
|||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
|
||||||
if (U_FAILURE(status))
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
pg_fatal("could not get language from locale \"%s\": %s",
|
pg_fatal("could not get language from locale \"%s\": %s",
|
||||||
loc_str, u_errorName(status));
|
loc_str, u_errorName(status));
|
||||||
@@ -2272,19 +2272,12 @@ icu_language_tag(const char *loc_str)
|
|||||||
langtag = pg_malloc(buflen);
|
langtag = pg_malloc(buflen);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int32_t len;
|
|
||||||
|
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
len = uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
|
uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
|
||||||
|
|
||||||
/*
|
/* try again if the buffer is not large enough */
|
||||||
* If the result fits in the buffer exactly (len == buflen),
|
|
||||||
* uloc_toLanguageTag() will return success without nul-terminating
|
|
||||||
* the result. Check for either U_BUFFER_OVERFLOW_ERROR or len >=
|
|
||||||
* buflen and try again.
|
|
||||||
*/
|
|
||||||
if (status == U_BUFFER_OVERFLOW_ERROR ||
|
if (status == U_BUFFER_OVERFLOW_ERROR ||
|
||||||
(U_SUCCESS(status) && len >= buflen))
|
status == U_STRING_NOT_TERMINATED_WARNING)
|
||||||
{
|
{
|
||||||
buflen = buflen * 2;
|
buflen = buflen * 2;
|
||||||
langtag = pg_realloc(langtag, buflen);
|
langtag = pg_realloc(langtag, buflen);
|
||||||
|
|||||||
Reference in New Issue
Block a user