aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2017-06-24 09:39:24 -0400
committerPeter Eisentraut <peter_e@gmx.net>2017-07-01 23:08:37 -0400
commitd8b3c81335600ad3487ca9bd642ef354d62919dc (patch)
tree6229778411a8570c589425d6144575f2dc6fd94e /src/backend
parentb0f069d931f0a3d4a39aeeb230baf2f2b18cb3c3 (diff)
downloadpostgresql-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.c24
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 */