diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2017-06-24 09:39:24 -0400 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2017-07-01 23:08:37 -0400 |
commit | d8b3c81335600ad3487ca9bd642ef354d62919dc (patch) | |
tree | 6229778411a8570c589425d6144575f2dc6fd94e /src/backend | |
parent | b0f069d931f0a3d4a39aeeb230baf2f2b18cb3c3 (diff) | |
download | postgresql-d8b3c81335600ad3487ca9bd642ef354d62919dc.tar.gz postgresql-d8b3c81335600ad3487ca9bd642ef354d62919dc.zip |
Refine memory allocation in ICU conversions
The simple calculations done to estimate the size of the output buffers
for ucnv_fromUChars() and ucnv_toUChars() could overflow int32_t for
large strings. To avoid that, go the long way and run the function
first without an output buffer to get the correct output buffer size
requirement.
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index eae9fcb0def..12419fc8df9 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -1511,14 +1511,22 @@ icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes) init_icu_converter(); - len_uchar = 2 * nbytes + 1; /* max length per docs */ - *buff_uchar = palloc(len_uchar * sizeof(**buff_uchar)); status = U_ZERO_ERROR; - len_uchar = ucnv_toUChars(icu_converter, *buff_uchar, len_uchar, + len_uchar = ucnv_toUChars(icu_converter, NULL, 0, + buff, nbytes, &status); + if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) + ereport(ERROR, + (errmsg("ucnv_toUChars failed: %s", u_errorName(status)))); + + *buff_uchar = palloc((len_uchar + 1) * sizeof(**buff_uchar)); + + status = U_ZERO_ERROR; + len_uchar = ucnv_toUChars(icu_converter, *buff_uchar, len_uchar + 1, buff, nbytes, &status); if (U_FAILURE(status)) ereport(ERROR, (errmsg("ucnv_toUChars failed: %s", u_errorName(status)))); + return len_uchar; } @@ -1541,14 +1549,22 @@ icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar) init_icu_converter(); - len_result = UCNV_GET_MAX_BYTES_FOR_STRING(len_uchar, ucnv_getMaxCharSize(icu_converter)); + status = U_ZERO_ERROR; + len_result = ucnv_fromUChars(icu_converter, NULL, 0, + buff_uchar, len_uchar, &status); + if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) + ereport(ERROR, + (errmsg("ucnv_fromUChars failed: %s", u_errorName(status)))); + *result = palloc(len_result + 1); + status = U_ZERO_ERROR; len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1, buff_uchar, len_uchar, &status); if (U_FAILURE(status)) ereport(ERROR, (errmsg("ucnv_fromUChars failed: %s", u_errorName(status)))); + return len_result; } #endif /* USE_ICU */ |