Re: crash in newlocale()

Ken Brown <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
On 8/11/2022 8:18 AM, Takashi Yano wrote:
> On Thu, 11 Aug 2022 11:29:28 +1000
> Tony Cook wrote:
>> $ cat newlocale-test.c
>> #include <locale.h>
>> #include <stdio.h>
>>
>> int main() {
>>    locale_t st = newlocale(LC_ALL_MASK, "C", (locale_t)0);
>>
>>    locale_t st2 = newlocale(LC_CTYPE_MASK, "en_US.UTF-8", st);
>>    printf("Done\n");
>>    return 0;
>> }
>> Program terminated with signal SIGTRAP, Trace/breakpoint trap.
>> The program no longer exists.
>> (gdb)
> 
> I looked into this problem and found the access violation
> occurs at:
> newlib/libc/locale/newlocale.c
> @@ 188,7 @@ _newlocale_r (struct _reent *p, int category_mask, const char *locale,
> 	if (tmp_locale.lc_cat[i].buf == (const void *) -1)
> 	  {
> 	    tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
> 	    base->lc_cat[i].ptr = base->lc_cat[i].buf = NULL; <-- Here!!!
> 	  }
> #endif /* __HAVE_LOCALE_INFO__ */
>        _freelocale_r (p, base);
> 
> This is because
> locale_t st = newlocale(LC_ALL_MASK, "C", (locale_t)0);
> returns
>    extern const struct __locale_t __C_locale;
>    return (struct __locale_t *) &__C_locale;
> , which is in the const area that cannot be modified.
> 
> This seems to be a newlib bug.
> 
> I also found following patch solves the issue.
> 
> diff --git a/newlib/libc/locale/newlocale.c b/newlib/libc/locale/newlocale.c
> index 0789d5fd9..1974665ec 100644
> --- a/newlib/libc/locale/newlocale.c
> +++ b/newlib/libc/locale/newlocale.c
> @@ -108,10 +108,12 @@ _newlocale_r (struct _reent *p, int category_mask, const char *locale,
>       }
>     /* If the new locale is supposed to be all default locale, just return
>        a pointer to the default locale. */
> +#if 0
>     if ((!base && category_mask == 0)
>         || (category_mask == LC_VALID_MASK
>   	  && (!strcmp (locale, "C") || !strcmp (locale, "POSIX"))))
>       return __get_C_locale ();
> +#endif
>     /* Start with setting all values to the default locale values. */
>     tmp_locale = *__get_C_locale ();
>     /* Fill out new category strings. */

Good work tracking this down!

I was about to suggest that instead of just disabling this optimization, you 
call _duplocale_r to return a duplicate of __get_C_locale ().  But then I saw 
the following in the definition of _duplocale_r in duplocale.c:

   /* The "C" locale is used statically, never copied. */
   else if (locobj == __get_C_locale ())
     return __get_C_locale ();

This looks like another bug.  Shouldn't duplocale always return a modifiable object?

Ken
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.