@@ -153,8 +153,8 @@ static UConverter *icu_converter = NULL;
153153
154154static UCollator * pg_ucol_open (const char * loc_str );
155155static void init_icu_converter (void );
156- static size_t uchar_length (UConverter * converter ,
157- const char * str , int32_t len );
156+ static int32_t uchar_length (UConverter * converter ,
157+ const char * str , int32_t len );
158158static int32_t uchar_convert (UConverter * converter ,
159159 UChar * dest , int32_t destlen ,
160160 const char * src , int32_t srclen );
@@ -1795,8 +1795,9 @@ pg_strncoll_libc_win32_utf8(const char *arg1, size_t len1, const char *arg2,
17951795 char * buf = sbuf ;
17961796 char * a1p ,
17971797 * a2p ;
1798- int a1len = len1 * 2 + 2 ;
1799- int a2len = len2 * 2 + 2 ;
1798+ size_t a1len ,
1799+ a2len ,
1800+ buflen ;
18001801 int r ;
18011802 int result ;
18021803
@@ -1806,8 +1807,16 @@ pg_strncoll_libc_win32_utf8(const char *arg1, size_t len1, const char *arg2,
18061807 Assert (false);
18071808#endif
18081809
1809- if (a1len + a2len > TEXTBUFLEN )
1810- buf = palloc (a1len + a2len );
1810+ /*
1811+ * In a 32-bit build, twice the input length can overflow size_t, so we
1812+ * must be careful.
1813+ */
1814+ a1len = add_size (add_size (len1 , len1 ), 2 );
1815+ a2len = add_size (add_size (len2 , len2 ), 2 );
1816+ buflen = add_size (a1len , a2len );
1817+
1818+ if (buflen > TEXTBUFLEN )
1819+ buf = palloc (buflen );
18111820
18121821 a1p = buf ;
18131822 a2p = buf + a1len ;
@@ -1958,12 +1967,11 @@ static int
19581967pg_strncoll_icu_no_utf8 (const char * arg1 , int32_t len1 ,
19591968 const char * arg2 , int32_t len2 , pg_locale_t locale )
19601969{
1961- char sbuf [TEXTBUFLEN ];
1962- char * buf = sbuf ;
1970+ UChar sbuf [TEXTBUFLEN / sizeof ( UChar ) ];
1971+ UChar * buf = sbuf ;
19631972 int32_t ulen1 ;
19641973 int32_t ulen2 ;
1965- size_t bufsize1 ;
1966- size_t bufsize2 ;
1974+ size_t bufsize ;
19671975 UChar * uchar1 ,
19681976 * uchar2 ;
19691977 int result ;
@@ -1978,14 +1986,13 @@ pg_strncoll_icu_no_utf8(const char *arg1, int32_t len1,
19781986 ulen1 = uchar_length (icu_converter , arg1 , len1 );
19791987 ulen2 = uchar_length (icu_converter , arg2 , len2 );
19801988
1981- bufsize1 = (ulen1 + 1 ) * sizeof (UChar );
1982- bufsize2 = (ulen2 + 1 ) * sizeof (UChar );
1989+ /* ulen1+1 or ulen2+1 doesn't risk overflow, but summing them might */
1990+ bufsize = add_size (ulen1 + 1 , ulen2 + 1 );
1991+ if (bufsize > lengthof (sbuf ))
1992+ buf = palloc_array (UChar , bufsize );
19831993
1984- if (bufsize1 + bufsize2 > TEXTBUFLEN )
1985- buf = palloc (bufsize1 + bufsize2 );
1986-
1987- uchar1 = (UChar * ) buf ;
1988- uchar2 = (UChar * ) (buf + bufsize1 );
1994+ uchar1 = buf ;
1995+ uchar2 = buf + ulen1 + 1 ;
19891996
19901997 ulen1 = uchar_convert (icu_converter , uchar1 , ulen1 + 1 , arg1 , len1 );
19911998 ulen2 = uchar_convert (icu_converter , uchar2 , ulen2 + 1 , arg2 , len2 );
@@ -2166,11 +2173,9 @@ static size_t
21662173pg_strnxfrm_icu (char * dest , const char * src , int32_t srclen , int32_t destsize ,
21672174 pg_locale_t locale )
21682175{
2169- char sbuf [TEXTBUFLEN ];
2170- char * buf = sbuf ;
2171- UChar * uchar ;
2176+ UChar sbuf [TEXTBUFLEN / sizeof (UChar )];
2177+ UChar * uchar = sbuf ;
21722178 int32_t ulen ;
2173- size_t uchar_bsize ;
21742179 Size result_bsize ;
21752180
21762181 Assert (locale -> provider == COLLPROVIDER_ICU );
@@ -2179,12 +2184,8 @@ pg_strnxfrm_icu(char *dest, const char *src, int32_t srclen, int32_t destsize,
21792184
21802185 ulen = uchar_length (icu_converter , src , srclen );
21812186
2182- uchar_bsize = (ulen + 1 ) * sizeof (UChar );
2183-
2184- if (uchar_bsize > TEXTBUFLEN )
2185- buf = palloc (uchar_bsize );
2186-
2187- uchar = (UChar * ) buf ;
2187+ if (ulen >= lengthof (sbuf ))
2188+ uchar = palloc_array (UChar , ulen + 1 );
21882189
21892190 ulen = uchar_convert (icu_converter , uchar , ulen + 1 , src , srclen );
21902191
@@ -2199,8 +2200,8 @@ pg_strnxfrm_icu(char *dest, const char *src, int32_t srclen, int32_t destsize,
21992200 Assert (result_bsize > 0 );
22002201 result_bsize -- ;
22012202
2202- if (buf != sbuf )
2203- pfree (buf );
2203+ if (uchar != sbuf )
2204+ pfree (uchar );
22042205
22052206 /* if dest is defined, it should be nul-terminated */
22062207 Assert (result_bsize >= destsize || dest [result_bsize ] == '\0' );
@@ -2213,14 +2214,12 @@ static size_t
22132214pg_strnxfrm_prefix_icu_no_utf8 (char * dest , const char * src , int32_t srclen ,
22142215 int32_t destsize , pg_locale_t locale )
22152216{
2216- char sbuf [TEXTBUFLEN ];
2217- char * buf = sbuf ;
2217+ UChar sbuf [TEXTBUFLEN / sizeof ( UChar ) ];
2218+ UChar * uchar = sbuf ;
22182219 UCharIterator iter ;
22192220 uint32_t state [2 ];
22202221 UErrorCode status ;
2221- int32_t ulen = -1 ;
2222- UChar * uchar = NULL ;
2223- size_t uchar_bsize ;
2222+ int32_t ulen ;
22242223 Size result_bsize ;
22252224
22262225 Assert (locale -> provider == COLLPROVIDER_ICU );
@@ -2230,12 +2229,8 @@ pg_strnxfrm_prefix_icu_no_utf8(char *dest, const char *src, int32_t srclen,
22302229
22312230 ulen = uchar_length (icu_converter , src , srclen );
22322231
2233- uchar_bsize = (ulen + 1 ) * sizeof (UChar );
2234-
2235- if (uchar_bsize > TEXTBUFLEN )
2236- buf = palloc (uchar_bsize );
2237-
2238- uchar = (UChar * ) buf ;
2232+ if (ulen >= lengthof (sbuf ))
2233+ uchar = palloc_array (UChar , ulen + 1 );
22392234
22402235 ulen = uchar_convert (icu_converter , uchar , ulen + 1 , src , srclen );
22412236
@@ -2253,8 +2248,8 @@ pg_strnxfrm_prefix_icu_no_utf8(char *dest, const char *src, int32_t srclen,
22532248 (errmsg ("sort key generation failed: %s" ,
22542249 u_errorName (status ))));
22552250
2256- if (buf != sbuf )
2257- pfree (buf );
2251+ if (uchar != sbuf )
2252+ pfree (uchar );
22582253
22592254 return result_bsize ;
22602255}
@@ -2599,8 +2594,12 @@ init_icu_converter(void)
25992594
26002595/*
26012596 * Find length, in UChars, of given string if converted to UChar string.
2597+ *
2598+ * Note: given the assumption that the input string fits in MaxAllocSize,
2599+ * the result cannot overflow int32_t. But callers must be careful about
2600+ * multiplying the result by sizeof(UChar).
26022601 */
2603- static size_t
2602+ static int32_t
26042603uchar_length (UConverter * converter , const char * str , int32_t len )
26052604{
26062605 UErrorCode status = U_ZERO_ERROR ;
@@ -2624,7 +2623,6 @@ uchar_convert(UConverter *converter, UChar *dest, int32_t destlen,
26242623 UErrorCode status = U_ZERO_ERROR ;
26252624 int32_t ulen ;
26262625
2627- status = U_ZERO_ERROR ;
26282626 ulen = ucnv_toUChars (converter , dest , destlen , src , srclen , & status );
26292627 if (U_FAILURE (status ))
26302628 ereport (ERROR ,
@@ -2653,7 +2651,7 @@ icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes)
26532651
26542652 len_uchar = uchar_length (icu_converter , buff , nbytes );
26552653
2656- * buff_uchar = palloc (( len_uchar + 1 ) * sizeof ( * * buff_uchar ) );
2654+ * buff_uchar = palloc_array ( UChar , len_uchar + 1 );
26572655 len_uchar = uchar_convert (icu_converter ,
26582656 * buff_uchar , len_uchar + 1 , buff , nbytes );
26592657
0 commit comments