Skip to content

Commit eb98734

Browse files
jeff-davispull[bot]
authored andcommitted
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
1 parent 38dc714 commit eb98734

File tree

2 files changed

+15
-29
lines changed

2 files changed

+15
-29
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2468,7 +2468,7 @@ pg_ucol_open(const char *loc_str)
24682468

24692469
status = U_ZERO_ERROR;
24702470
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
2471-
if (U_FAILURE(status))
2471+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
24722472
{
24732473
ereport(ERROR,
24742474
(errmsg("could not get language from locale \"%s\": %s",
@@ -2504,7 +2504,7 @@ pg_ucol_open(const char *loc_str)
25042504
* Pretend the error came from ucol_open(), for consistent error
25052505
* message across ICU versions.
25062506
*/
2507-
if (U_FAILURE(status))
2507+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
25082508
{
25092509
ucol_close(collator);
25102510
ereport(ERROR,
@@ -2639,7 +2639,8 @@ icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar)
26392639
status = U_ZERO_ERROR;
26402640
len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1,
26412641
buff_uchar, len_uchar, &status);
2642-
if (U_FAILURE(status))
2642+
if (U_FAILURE(status) ||
2643+
status == U_STRING_NOT_TERMINATED_WARNING)
26432644
ereport(ERROR,
26442645
(errmsg("%s failed: %s", "ucnv_fromUChars",
26452646
u_errorName(status))));
@@ -2681,7 +2682,7 @@ icu_set_collation_attributes(UCollator *collator, const char *loc,
26812682
icu_locale_id = palloc(len + 1);
26822683
*status = U_ZERO_ERROR;
26832684
len = uloc_canonicalize(loc, icu_locale_id, len + 1, status);
2684-
if (U_FAILURE(*status))
2685+
if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING)
26852686
return;
26862687

26872688
lower_str = asc_tolower(icu_locale_id, strlen(icu_locale_id));
@@ -2765,7 +2766,6 @@ icu_set_collation_attributes(UCollator *collator, const char *loc,
27652766

27662767
pfree(lower_str);
27672768
}
2768-
27692769
#endif
27702770

27712771
/*
@@ -2789,7 +2789,7 @@ icu_language_tag(const char *loc_str, int elevel)
27892789

27902790
status = U_ZERO_ERROR;
27912791
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
2792-
if (U_FAILURE(status))
2792+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
27932793
{
27942794
if (elevel > 0)
27952795
ereport(elevel,
@@ -2811,19 +2811,12 @@ icu_language_tag(const char *loc_str, int elevel)
28112811
langtag = palloc(buflen);
28122812
while (true)
28132813
{
2814-
int32_t len;
2815-
28162814
status = U_ZERO_ERROR;
2817-
len = uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
2815+
uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
28182816

2819-
/*
2820-
* If the result fits in the buffer exactly (len == buflen),
2821-
* uloc_toLanguageTag() will return success without nul-terminating
2822-
* the result. Check for either U_BUFFER_OVERFLOW_ERROR or len >=
2823-
* buflen and try again.
2824-
*/
2817+
/* try again if the buffer is not large enough */
28252818
if ((status == U_BUFFER_OVERFLOW_ERROR ||
2826-
(U_SUCCESS(status) && len >= buflen)) &&
2819+
status == U_STRING_NOT_TERMINATED_WARNING) &&
28272820
buflen < MaxAllocSize)
28282821
{
28292822
buflen = Min(buflen * 2, MaxAllocSize);
@@ -2878,7 +2871,7 @@ icu_validate_locale(const char *loc_str)
28782871
/* validate that we can extract the language */
28792872
status = U_ZERO_ERROR;
28802873
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
2881-
if (U_FAILURE(status))
2874+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
28822875
{
28832876
ereport(elevel,
28842877
(errmsg("could not get language from ICU locale \"%s\": %s",
@@ -2901,7 +2894,7 @@ icu_validate_locale(const char *loc_str)
29012894

29022895
status = U_ZERO_ERROR;
29032896
uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status);
2904-
if (U_FAILURE(status))
2897+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
29052898
continue;
29062899

29072900
if (strcmp(lang, otherlang) == 0)

src/bin/initdb/initdb.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,7 +2252,7 @@ icu_language_tag(const char *loc_str)
22522252

22532253
status = U_ZERO_ERROR;
22542254
uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
2255-
if (U_FAILURE(status))
2255+
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
22562256
{
22572257
pg_fatal("could not get language from locale \"%s\": %s",
22582258
loc_str, u_errorName(status));
@@ -2272,19 +2272,12 @@ icu_language_tag(const char *loc_str)
22722272
langtag = pg_malloc(buflen);
22732273
while (true)
22742274
{
2275-
int32_t len;
2276-
22772275
status = U_ZERO_ERROR;
2278-
len = uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
2276+
uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
22792277

2280-
/*
2281-
* If the result fits in the buffer exactly (len == buflen),
2282-
* uloc_toLanguageTag() will return success without nul-terminating
2283-
* the result. Check for either U_BUFFER_OVERFLOW_ERROR or len >=
2284-
* buflen and try again.
2285-
*/
2278+
/* try again if the buffer is not large enough */
22862279
if (status == U_BUFFER_OVERFLOW_ERROR ||
2287-
(U_SUCCESS(status) && len >= buflen))
2280+
status == U_STRING_NOT_TERMINATED_WARNING)
22882281
{
22892282
buflen = buflen * 2;
22902283
langtag = pg_realloc(langtag, buflen);

0 commit comments

Comments
 (0)