summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut2017-06-24 13:39:24 +0000
committerPeter Eisentraut2017-07-02 03:08:37 +0000
commitd8b3c81335600ad3487ca9bd642ef354d62919dc (patch)
tree6229778411a8570c589425d6144575f2dc6fd94e
parentb0f069d931f0a3d4a39aeeb230baf2f2b18cb3c3 (diff)
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.
-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 eae9fcb0de..12419fc8df 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 */