@@ -1297,14 +1297,15 @@ report_newlocale_failure(const char *localename)
1297
1297
}
1298
1298
1299
1299
/*
1300
- * Initialize the locale_t field .
1300
+ * Create a locale_t with the given collation and ctype .
1301
1301
*
1302
- * The "C" and "POSIX" locales are not actually handled by libc, so set the
1303
- * locale_t to zero in that case.
1302
+ * The "C" and "POSIX" locales are not actually handled by libc, so return
1303
+ * NULL.
1304
+ *
1305
+ * Ensure that no path leaks a locale_t.
1304
1306
*/
1305
- static void
1306
- make_libc_collator (const char * collate , const char * ctype ,
1307
- pg_locale_t result )
1307
+ static locale_t
1308
+ make_libc_collator (const char * collate , const char * ctype )
1308
1309
{
1309
1310
locale_t loc = 0 ;
1310
1311
@@ -1343,7 +1344,11 @@ make_libc_collator(const char *collate, const char *ctype,
1343
1344
errno = 0 ;
1344
1345
loc = newlocale (LC_CTYPE_MASK , ctype , loc1 );
1345
1346
if (!loc )
1347
+ {
1348
+ if (loc1 )
1349
+ freelocale (loc1 );
1346
1350
report_newlocale_failure (ctype );
1351
+ }
1347
1352
}
1348
1353
else
1349
1354
loc = loc1 ;
@@ -1360,60 +1365,78 @@ make_libc_collator(const char *collate, const char *ctype,
1360
1365
#endif
1361
1366
}
1362
1367
1363
- result -> info . lt = loc ;
1368
+ return loc ;
1364
1369
}
1365
1370
1366
- void
1367
- make_icu_collator ( const char * iculocstr ,
1368
- const char * icurules ,
1369
- struct pg_locale_struct * resultp )
1370
- {
1371
+ /*
1372
+ * Create a UCollator with the given locale string and rules.
1373
+ *
1374
+ * Ensure that no path leaks a UCollator.
1375
+ */
1371
1376
#ifdef USE_ICU
1372
- UCollator * collator ;
1373
-
1374
- collator = pg_ucol_open ( iculocstr );
1375
-
1376
- /*
1377
- * If rules are specified, we extract the rules of the standard collation,
1378
- * add our own rules, and make a new collator with the combined rules.
1379
- */
1380
- if ( icurules )
1377
+ static UCollator *
1378
+ make_icu_collator ( const char * iculocstr , const char * icurules )
1379
+ {
1380
+ if (! icurules )
1381
+ {
1382
+ /* simple case without rules */
1383
+ return pg_ucol_open ( iculocstr );
1384
+ }
1385
+ else
1381
1386
{
1382
- const UChar * default_rules ;
1383
- UChar * agg_rules ;
1387
+ UCollator * collator_std_rules ;
1388
+ UCollator * collator_all_rules ;
1389
+ const UChar * std_rules ;
1384
1390
UChar * my_rules ;
1385
- UErrorCode status ;
1391
+ UChar * all_rules ;
1386
1392
int32_t length ;
1393
+ int32_t total ;
1394
+ UErrorCode status ;
1387
1395
1388
- default_rules = ucol_getRules (collator , & length );
1396
+ /*
1397
+ * If rules are specified, we extract the rules of the standard
1398
+ * collation, add our own rules, and make a new collator with the
1399
+ * combined rules.
1400
+ */
1389
1401
icu_to_uchar (& my_rules , icurules , strlen (icurules ));
1390
1402
1391
- agg_rules = palloc_array (UChar , u_strlen (default_rules ) + u_strlen (my_rules ) + 1 );
1392
- u_strcpy (agg_rules , default_rules );
1393
- u_strcat (agg_rules , my_rules );
1403
+ collator_std_rules = pg_ucol_open (iculocstr );
1394
1404
1395
- ucol_close (collator );
1405
+ std_rules = ucol_getRules (collator_std_rules , & length );
1406
+
1407
+ total = u_strlen (std_rules ) + u_strlen (my_rules ) + 1 ;
1408
+
1409
+ /* avoid leaking collator on OOM */
1410
+ all_rules = palloc_extended (sizeof (UChar ) * total , MCXT_ALLOC_NO_OOM );
1411
+ if (!all_rules )
1412
+ {
1413
+ ucol_close (collator_std_rules );
1414
+ ereport (ERROR ,
1415
+ (errcode (ERRCODE_OUT_OF_MEMORY ),
1416
+ errmsg ("out of memory" )));
1417
+ }
1418
+
1419
+ u_strcpy (all_rules , std_rules );
1420
+ u_strcat (all_rules , my_rules );
1421
+
1422
+ ucol_close (collator_std_rules );
1396
1423
1397
1424
status = U_ZERO_ERROR ;
1398
- collator = ucol_openRules (agg_rules , u_strlen (agg_rules ),
1399
- UCOL_DEFAULT , UCOL_DEFAULT_STRENGTH , NULL , & status );
1425
+ collator_all_rules = ucol_openRules (all_rules , u_strlen (all_rules ),
1426
+ UCOL_DEFAULT , UCOL_DEFAULT_STRENGTH ,
1427
+ NULL , & status );
1400
1428
if (U_FAILURE (status ))
1429
+ {
1401
1430
ereport (ERROR ,
1402
1431
(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1403
1432
errmsg ("could not open collator for locale \"%s\" with rules \"%s\": %s" ,
1404
1433
iculocstr , icurules , u_errorName (status ))));
1405
- }
1434
+ }
1406
1435
1407
- /* We will leak this string if the caller errors later :-( */
1408
- resultp -> info .icu .locale = MemoryContextStrdup (TopMemoryContext , iculocstr );
1409
- resultp -> info .icu .ucol = collator ;
1410
- #else /* not USE_ICU */
1411
- /* could get here if a collation was created by a build with ICU */
1412
- ereport (ERROR ,
1413
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1414
- errmsg ("ICU is not supported in this build" )));
1415
- #endif /* not USE_ICU */
1436
+ return collator_all_rules ;
1437
+ }
1416
1438
}
1439
+ #endif /* not USE_ICU */
1417
1440
1418
1441
/*
1419
1442
* Initialize default_locale with database locale settings.
@@ -1424,7 +1447,6 @@ init_database_collation(void)
1424
1447
HeapTuple tup ;
1425
1448
Form_pg_database dbform ;
1426
1449
Datum datum ;
1427
- bool isnull ;
1428
1450
1429
1451
/* Fetch our pg_database row normally, via syscache */
1430
1452
tup = SearchSysCache1 (DATABASEOID , ObjectIdGetDatum (MyDatabaseId ));
@@ -1449,8 +1471,10 @@ init_database_collation(void)
1449
1471
}
1450
1472
else if (dbform -> datlocprovider == COLLPROVIDER_ICU )
1451
1473
{
1474
+ #ifdef USE_ICU
1452
1475
char * datlocale ;
1453
1476
char * icurules ;
1477
+ bool isnull ;
1454
1478
1455
1479
datum = SysCacheGetAttrNotNull (DATABASEOID , tup , Anum_pg_database_datlocale );
1456
1480
datlocale = TextDatumGetCString (datum );
@@ -1464,15 +1488,20 @@ init_database_collation(void)
1464
1488
else
1465
1489
icurules = NULL ;
1466
1490
1467
- make_icu_collator (datlocale , icurules , & default_locale );
1491
+ default_locale .info .icu .locale = MemoryContextStrdup (TopMemoryContext , datlocale );
1492
+ default_locale .info .icu .ucol = make_icu_collator (datlocale , icurules );
1493
+ #else
1494
+ /* could get here if a collation was created by a build with ICU */
1495
+ ereport (ERROR ,
1496
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1497
+ errmsg ("ICU is not supported in this build" )));
1498
+ #endif
1468
1499
}
1469
- else
1500
+ else if ( dbform -> datlocprovider == COLLPROVIDER_LIBC )
1470
1501
{
1471
1502
const char * datcollate ;
1472
1503
const char * datctype ;
1473
1504
1474
- Assert (dbform -> datlocprovider == COLLPROVIDER_LIBC );
1475
-
1476
1505
datum = SysCacheGetAttrNotNull (DATABASEOID , tup , Anum_pg_database_datcollate );
1477
1506
datcollate = TextDatumGetCString (datum );
1478
1507
datum = SysCacheGetAttrNotNull (DATABASEOID , tup , Anum_pg_database_datctype );
@@ -1483,8 +1512,12 @@ init_database_collation(void)
1483
1512
default_locale .ctype_is_c = (strcmp (datctype , "C" ) == 0 ) ||
1484
1513
(strcmp (datctype , "POSIX" ) == 0 );
1485
1514
1486
- make_libc_collator (datcollate , datctype , & default_locale );
1515
+ default_locale . info . lt = make_libc_collator (datcollate , datctype );
1487
1516
}
1517
+ else
1518
+ /* shouldn't happen */
1519
+ PGLOCALE_SUPPORT_ERROR (dbform -> datlocprovider );
1520
+
1488
1521
1489
1522
default_locale .provider = dbform -> datlocprovider ;
1490
1523
@@ -1557,25 +1590,9 @@ pg_newlocale_from_collation(Oid collid)
1557
1590
result .info .builtin .locale = MemoryContextStrdup (TopMemoryContext ,
1558
1591
locstr );
1559
1592
}
1560
- else if (collform -> collprovider == COLLPROVIDER_LIBC )
1561
- {
1562
- const char * collcollate ;
1563
- const char * collctype ;
1564
-
1565
- datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collcollate );
1566
- collcollate = TextDatumGetCString (datum );
1567
- datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collctype );
1568
- collctype = TextDatumGetCString (datum );
1569
-
1570
- result .collate_is_c = (strcmp (collcollate , "C" ) == 0 ) ||
1571
- (strcmp (collcollate , "POSIX" ) == 0 );
1572
- result .ctype_is_c = (strcmp (collctype , "C" ) == 0 ) ||
1573
- (strcmp (collctype , "POSIX" ) == 0 );
1574
-
1575
- make_libc_collator (collcollate , collctype , & result );
1576
- }
1577
1593
else if (collform -> collprovider == COLLPROVIDER_ICU )
1578
1594
{
1595
+ #ifdef USE_ICU
1579
1596
const char * iculocstr ;
1580
1597
const char * icurules ;
1581
1598
@@ -1591,8 +1608,35 @@ pg_newlocale_from_collation(Oid collid)
1591
1608
else
1592
1609
icurules = NULL ;
1593
1610
1594
- make_icu_collator (iculocstr , icurules , & result );
1611
+ result .info .icu .locale = MemoryContextStrdup (TopMemoryContext , iculocstr );
1612
+ result .info .icu .ucol = make_icu_collator (iculocstr , icurules );
1613
+ #else
1614
+ /* could get here if a collation was created by a build with ICU */
1615
+ ereport (ERROR ,
1616
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1617
+ errmsg ("ICU is not supported in this build" )));
1618
+ #endif
1595
1619
}
1620
+ else if (collform -> collprovider == COLLPROVIDER_LIBC )
1621
+ {
1622
+ const char * collcollate ;
1623
+ const char * collctype ;
1624
+
1625
+ datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collcollate );
1626
+ collcollate = TextDatumGetCString (datum );
1627
+ datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collctype );
1628
+ collctype = TextDatumGetCString (datum );
1629
+
1630
+ result .collate_is_c = (strcmp (collcollate , "C" ) == 0 ) ||
1631
+ (strcmp (collcollate , "POSIX" ) == 0 );
1632
+ result .ctype_is_c = (strcmp (collctype , "C" ) == 0 ) ||
1633
+ (strcmp (collctype , "POSIX" ) == 0 );
1634
+
1635
+ result .info .lt = make_libc_collator (collcollate , collctype );
1636
+ }
1637
+ else
1638
+ /* shouldn't happen */
1639
+ PGLOCALE_SUPPORT_ERROR (collform -> collprovider );
1596
1640
1597
1641
datum = SysCacheGetAttr (COLLOID , tp , Anum_pg_collation_collversion ,
1598
1642
& isnull );
@@ -2500,6 +2544,8 @@ builtin_validate_locale(int encoding, const char *locale)
2500
2544
/*
2501
2545
* Wrapper around ucol_open() to handle API differences for older ICU
2502
2546
* versions.
2547
+ *
2548
+ * Ensure that no path leaks a UCollator.
2503
2549
*/
2504
2550
static UCollator *
2505
2551
pg_ucol_open (const char * loc_str )
0 commit comments