Print this page
locale stuff should use libc safe lmalloc.  Other fixes from tests.


 141         "LC_ALL",
 142 };
 143 
 144 /*
 145  * Prototypes.
 146  */
 147 static const char *get_locale_env(int);
 148 static struct locdata *locdata_get(int, const const char *);
 149 static struct locdata *locdata_get_cache(int, const char *);
 150 static locale_t mklocname(locale_t);
 151 
 152 /*
 153  * Some utility routines.
 154  */
 155 
 156 struct locdata *
 157 __locdata_alloc(const char *name, size_t memsz)
 158 {
 159         struct locdata *ldata;
 160 
 161         if ((ldata = calloc(1, sizeof (*ldata))) == NULL) {
 162                 return (NULL);
 163         }
 164         if ((ldata->l_data[0] = calloc(1, memsz)) == NULL) {
 165                 free(ldata);
 166                 errno = ENOMEM;
 167                 return (NULL);
 168         }
 169         (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
 170 
 171         return (ldata);
 172 }
 173 
 174 /*
 175  * Normally we never free locale data truly, but if we failed to load it
 176  * for some reason, this routine is used to cleanup the partial mess.
 177  */
 178 void
 179 __locdata_free(struct locdata *ldata)
 180 {
 181         for (int i = 0; i < NLOCDATA; i++)
 182                 free(ldata->l_data[i]);
 183         if (ldata->l_map != NULL && ldata->l_map_len)
 184                 (void) munmap(ldata->l_map, ldata->l_map_len);
 185         free(ldata);
 186 }
 187 
 188 /*
 189  * It turns out that for performance reasons we would really like to
 190  * cache the most recently referenced locale data to avoid wasteful
 191  * loading from files.
 192  */
 193 
 194 static struct locdata *cache_data[LC_ALL];
 195 static struct locdata *cat_data[LC_ALL];
 196 static mutex_t cache_lock = DEFAULTMUTEX;
 197 
 198 /*
 199  * Returns the cached data if the locale name is the same.  If not,
 200  * returns NULL (cache miss).  The locdata is returned with a hold on
 201  * it, taken on behalf of the caller.  The caller should drop the hold
 202  * when it is finished.
 203  */
 204 static struct locdata *
 205 locdata_get_cache(int category, const char *locname)


 233          * Finally, if we still don't have one, try loading the locale
 234          * data from the actual on-disk data.
 235          *
 236          * We drop the lock (libc wants to ensure no internal locks
 237          * are held when we call other routines required to read from
 238          * files, allocate memory, etc.)  There is a small race here,
 239          * but the consequences of the race are benign -- if multiple
 240          * threads hit this at precisely the same point, we could
 241          * wind up with duplicates of the locale data in the cache.
 242          *
 243          * This wastes the memory for an extra copy of the locale
 244          * data, but there is no further harm beyond that.  Its not
 245          * worth the effort to recode this to something "safe"
 246          * (which would require rescanning the list, etc.), given
 247          * that this race will probably never actually occur.
 248          */
 249         if (loc == NULL) {
 250                 lmutex_unlock(&cache_lock);
 251                 loc = (*loaders[category])(locname);
 252                 lmutex_lock(&cache_lock);
 253                 (void) strlcpy(loc->l_lname, locname, sizeof (loc->l_lname));


 254         }
 255 
 256         /*
 257          * Assuming we got one, update the cache, and stick us on the list
 258          * of loaded locale data.  We insert into the head (more recent
 259          * use is likely to win.)
 260          */
 261         if (loc != NULL) {
 262                 cache_data[category] = loc;
 263                 if (loc->l_next == NULL) {

 264                         loc->l_next = cat_data[category];
 265                         cat_data[category] = loc;
 266                 }
 267         }
 268 
 269         lmutex_unlock(&cache_lock);
 270         return (loc);
 271 }
 272 
 273 /*
 274  * Routine to get the locdata for a given category and locale.
 275  * This includes retrieving it from cache, retrieving it from
 276  * a file, etc.
 277  */
 278 static struct locdata *
 279 locdata_get(int category, const char *locname)
 280 {
 281         char scratch[ENCODING_LEN + 1];
 282         char *slash;
 283         int cnt;


 357 {
 358         return (loc->ctype->lc_max_mblen);
 359 }
 360 
 361 unsigned char
 362 __mb_cur_max(void)
 363 {
 364         return (__mb_cur_max_l(uselocale(NULL)));
 365 }
 366 
 367 /*
 368  * Public interfaces.
 369  */
 370 
 371 locale_t
 372 duplocale(locale_t src)
 373 {
 374         locale_t        loc;
 375         int             i;
 376 
 377         loc = calloc(1, sizeof (*loc));
 378         if (loc == NULL) {
 379                 return (NULL);
 380         }
 381         if (src == NULL) {
 382                 /* illumos extension: POSIX says LC_GLOBAL_LOCALE here */
 383                 src = ___global_locale;
 384         }
 385         for (i = 0; i < LC_ALL; i++) {
 386                 loc->locdata[i] = src->locdata[i];
 387                 loc->loaded[i] = 0;
 388         }
 389         loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
 390         loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
 391         loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
 392         loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
 393         loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
 394         loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
 395         loc->time = loc->locdata[LC_TIME]->l_data[0];
 396         return (loc);
 397 }
 398 
 399 void
 400 freelocale(locale_t loc)
 401 {
 402         /*
 403          * We take extra care never to free a saved locale created by
 404          * setlocale().  This shouldn't be strictly necessary, but a little
 405          * extra safety doesn't hurt here.
 406          */
 407         if ((loc != &posix_locale) && (!loc->on_list))
 408                 free(loc);
 409 }
 410 
 411 locale_t
 412 newlocale(int catmask, const char *locname, locale_t base)
 413 {
 414         locale_t loc;
 415         int i, e;
 416 
 417         if (catmask & ~(LC_ALL_MASK)) {
 418                 errno = EINVAL;
 419                 return (NULL);
 420         }
 421 
 422         /*
 423          * Technically passing LC_GLOBAL_LOCALE here is illegal,
 424          * but we allow it.
 425          */
 426         if (base == NULL || base == ___global_locale) {
 427                 loc = duplocale(___global_locale);
 428         } else {
 429                 loc = base;
 430         }
 431         if (loc == NULL) {
 432                 return (NULL);
 433         }
 434 
 435         for (i = 0; i < LC_ALL; i++) {
 436                 struct locdata *ldata;
 437                 loc->loaded[i] = 0;
 438                 if (((1 << i) & catmask) == 0) {
 439                         /* Default to base locale if not overriding */
 440                         continue;
 441                 }
 442                 ldata = locdata_get(i, locname);
 443                 if (ldata == NULL) {
 444                         e = errno;
 445                         freelocale(loc);
 446                         errno = e;
 447                         return (NULL);
 448                 }
 449                 loc->locdata[i] = ldata;
 450         }
 451         loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
 452         loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
 453         loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
 454         loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
 455         loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
 456         loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
 457         loc->time = loc->locdata[LC_TIME]->l_data[0];


 458         return (mklocname(loc));
 459 }
 460 
 461 locale_t
 462 uselocale(locale_t loc)
 463 {
 464         locale_t lastloc = ___global_locale;
 465         locale_t *locptr;
 466 
 467         locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
 468         /* Should never occur */
 469         if (locptr == NULL) {
 470                 errno = EINVAL;
 471                 return (NULL);
 472         }
 473 
 474         if (*locptr != NULL)
 475                 lastloc = *locptr;
 476 
 477         /* Argument loc is NULL if we are just querying. */




 141         "LC_ALL",
 142 };
 143 
 144 /*
 145  * Prototypes.
 146  */
 147 static const char *get_locale_env(int);
 148 static struct locdata *locdata_get(int, const const char *);
 149 static struct locdata *locdata_get_cache(int, const char *);
 150 static locale_t mklocname(locale_t);
 151 
 152 /*
 153  * Some utility routines.
 154  */
 155 
 156 struct locdata *
 157 __locdata_alloc(const char *name, size_t memsz)
 158 {
 159         struct locdata *ldata;
 160 
 161         if ((ldata = lmalloc(sizeof (*ldata))) == NULL) {
 162                 return (NULL);
 163         }
 164         if ((ldata->l_data[0] = libc_malloc(memsz)) == NULL) {
 165                 lfree(ldata, sizeof (*ldata));
 166                 errno = ENOMEM;
 167                 return (NULL);
 168         }
 169         (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
 170 
 171         return (ldata);
 172 }
 173 
 174 /*
 175  * Normally we never free locale data truly, but if we failed to load it
 176  * for some reason, this routine is used to cleanup the partial mess.
 177  */
 178 void
 179 __locdata_free(struct locdata *ldata)
 180 {
 181         for (int i = 0; i < NLOCDATA; i++)
 182                 libc_free(ldata->l_data[i]);
 183         if (ldata->l_map != NULL && ldata->l_map_len)
 184                 (void) munmap(ldata->l_map, ldata->l_map_len);
 185         lfree(ldata, sizeof (*ldata));
 186 }
 187 
 188 /*
 189  * It turns out that for performance reasons we would really like to
 190  * cache the most recently referenced locale data to avoid wasteful
 191  * loading from files.
 192  */
 193 
 194 static struct locdata *cache_data[LC_ALL];
 195 static struct locdata *cat_data[LC_ALL];
 196 static mutex_t cache_lock = DEFAULTMUTEX;
 197 
 198 /*
 199  * Returns the cached data if the locale name is the same.  If not,
 200  * returns NULL (cache miss).  The locdata is returned with a hold on
 201  * it, taken on behalf of the caller.  The caller should drop the hold
 202  * when it is finished.
 203  */
 204 static struct locdata *
 205 locdata_get_cache(int category, const char *locname)


 233          * Finally, if we still don't have one, try loading the locale
 234          * data from the actual on-disk data.
 235          *
 236          * We drop the lock (libc wants to ensure no internal locks
 237          * are held when we call other routines required to read from
 238          * files, allocate memory, etc.)  There is a small race here,
 239          * but the consequences of the race are benign -- if multiple
 240          * threads hit this at precisely the same point, we could
 241          * wind up with duplicates of the locale data in the cache.
 242          *
 243          * This wastes the memory for an extra copy of the locale
 244          * data, but there is no further harm beyond that.  Its not
 245          * worth the effort to recode this to something "safe"
 246          * (which would require rescanning the list, etc.), given
 247          * that this race will probably never actually occur.
 248          */
 249         if (loc == NULL) {
 250                 lmutex_unlock(&cache_lock);
 251                 loc = (*loaders[category])(locname);
 252                 lmutex_lock(&cache_lock);
 253                 if (loc != NULL)
 254                         (void) strlcpy(loc->l_lname, locname,
 255                             sizeof (loc->l_lname));
 256         }
 257 
 258         /*
 259          * Assuming we got one, update the cache, and stick us on the list
 260          * of loaded locale data.  We insert into the head (more recent
 261          * use is likely to win.)
 262          */
 263         if (loc != NULL) {
 264                 cache_data[category] = loc;
 265                 if (!loc->l_cached) {
 266                         loc->l_cached = 1;
 267                         loc->l_next = cat_data[category];
 268                         cat_data[category] = loc;
 269                 }
 270         }
 271 
 272         lmutex_unlock(&cache_lock);
 273         return (loc);
 274 }
 275 
 276 /*
 277  * Routine to get the locdata for a given category and locale.
 278  * This includes retrieving it from cache, retrieving it from
 279  * a file, etc.
 280  */
 281 static struct locdata *
 282 locdata_get(int category, const char *locname)
 283 {
 284         char scratch[ENCODING_LEN + 1];
 285         char *slash;
 286         int cnt;


 360 {
 361         return (loc->ctype->lc_max_mblen);
 362 }
 363 
 364 unsigned char
 365 __mb_cur_max(void)
 366 {
 367         return (__mb_cur_max_l(uselocale(NULL)));
 368 }
 369 
 370 /*
 371  * Public interfaces.
 372  */
 373 
 374 locale_t
 375 duplocale(locale_t src)
 376 {
 377         locale_t        loc;
 378         int             i;
 379 
 380         loc = lmalloc(sizeof (*loc));
 381         if (loc == NULL) {
 382                 return (NULL);
 383         }
 384         if (src == NULL) {
 385                 /* illumos extension: POSIX says LC_GLOBAL_LOCALE here */
 386                 src = ___global_locale;
 387         }
 388         for (i = 0; i < LC_ALL; i++) {
 389                 loc->locdata[i] = src->locdata[i];
 390                 loc->loaded[i] = 0;
 391         }
 392         loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
 393         loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
 394         loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
 395         loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
 396         loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
 397         loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
 398         loc->time = loc->locdata[LC_TIME]->l_data[0];
 399         return (loc);
 400 }
 401 
 402 void
 403 freelocale(locale_t loc)
 404 {
 405         /*
 406          * We take extra care never to free a saved locale created by
 407          * setlocale().  This shouldn't be strictly necessary, but a little
 408          * extra safety doesn't hurt here.
 409          */
 410         if ((loc != NULL) && (loc != &posix_locale) && (!loc->on_list))
 411                 lfree(loc, sizeof (*loc));
 412 }
 413 
 414 locale_t
 415 newlocale(int catmask, const char *locname, locale_t base)
 416 {
 417         locale_t loc;
 418         int i, e;
 419 
 420         if (catmask & ~(LC_ALL_MASK)) {
 421                 errno = EINVAL;
 422                 return (NULL);
 423         }
 424 
 425         /*
 426          * Technically passing LC_GLOBAL_LOCALE here is illegal,
 427          * but we allow it.
 428          */
 429         if (base == NULL || base == ___global_locale) {
 430                 loc = duplocale(___global_locale);
 431         } else {
 432                 loc = duplocale(base);
 433         }
 434         if (loc == NULL) {
 435                 return (NULL);
 436         }
 437 
 438         for (i = 0; i < LC_ALL; i++) {
 439                 struct locdata *ldata;
 440                 loc->loaded[i] = 0;
 441                 if (((1 << i) & catmask) == 0) {
 442                         /* Default to base locale if not overriding */
 443                         continue;
 444                 }
 445                 ldata = locdata_get(i, locname);
 446                 if (ldata == NULL) {
 447                         e = errno;
 448                         freelocale(loc);
 449                         errno = e;
 450                         return (NULL);
 451                 }
 452                 loc->locdata[i] = ldata;
 453         }
 454         loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
 455         loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
 456         loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
 457         loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
 458         loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
 459         loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
 460         loc->time = loc->locdata[LC_TIME]->l_data[0];
 461         freelocale(base);
 462 
 463         return (mklocname(loc));
 464 }
 465 
 466 locale_t
 467 uselocale(locale_t loc)
 468 {
 469         locale_t lastloc = ___global_locale;
 470         locale_t *locptr;
 471 
 472         locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
 473         /* Should never occur */
 474         if (locptr == NULL) {
 475                 errno = EINVAL;
 476                 return (NULL);
 477         }
 478 
 479         if (*locptr != NULL)
 480                 lastloc = *locptr;
 481 
 482         /* Argument loc is NULL if we are just querying. */