Bug 85732

Summary: use_facet<moneypunct<char, true>>(mylocale) retrieving wrong locale information
Product: gcc Reporter: Tom Straub <gnu-org>
Component: libstdc++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED MOVED    
Severity: normal    
Priority: P3    
Version: 6.4.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2018-05-10 00:00:00
Attachments: Source code and test output results showing error

Description Tom Straub 2018-05-10 12:23:20 UTC
Created attachment 44110 [details]
Source code and test output results showing error

Dear Bug Team,

I just recently upgraded using "apt" my Ubuntu 16.04 system and gcc was upgraded from 6.2.0 to 6.4.0 which introduced the following bug.

In the attached archive is a program "testlocale.cpp" which requires only gcc-supplied  header files. The command line to compile it and execute it is in the comments at the top of the file.

In essence, it tests each facet of three locales (on my system "en_US.utf8", "pt_BR.utf8" and "C" locales. All worked perfectly in g++ 6.2.0. As of g++ 6.4.0, all of the facets, except the "moneypunct" facet work properly (see line 134).

Here is my information:

Linux version
$ uname -a
Linux asusubuntu16 4.13.0-41-generic #46~16.04.1-Ubuntu SMP Thu May 3 10:06:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Compiler version
$ gcc --version
gcc (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compile command:
$ g++ -std=c++14 -m64 testlocale.cpp -static -o testlocale

Run command:
$ ./testlocale > testlocale.out

Attached is a test output generated by gcc 6.4.0 on my system. Of course, you can test it on your system yourself and try to duplicate the error.

Best regards,
Tom Straub
Comment 1 Tom Straub 2018-05-10 12:26:08 UTC
Sorry, wrong compiler included in post, here is the right one:

$ g++ --version
g++ (Ubuntu 6.4.0-17ubuntu1~16.04) 6.4.0 20180424
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Comment 2 Jonathan Wakely 2018-05-10 12:47:39 UTC
It works fine for me with any version of GCC, including 6.4.0

Testing 'moneypunct' Facet:
--> Setting locale 'pt_BR.utf8'
Natl Currency Symbol     = 'R$'
Intl Currency Symbol     = 'BRL '
Natl Positive Sign       = ''
Intl Positive Sign       = ''
Natl Positive Format     = { sign, symbol, space, value }
Intl Positive Format     = { sign, symbol, space, value }
Natl Negative Sign       = '-'
Natl Negative Format     = { sign, symbol, space, value }
Intl Negative Sign       = '-'
Intl Negative Format     = { sign, symbol, space, value }
Natl Decimal Point       = ','
Intl Decimal Point       = ','
Natl Thousands Separator = '.'
Intl Thousands Separator = '.'
Natl Fractional Digits   = '2'
Intl Fractional Digits   = '2'
Natl Grouping Length [0] = 3 digits
Natl Grouping Length [1] = 3 digits
Intl Grouping Length [0] = 3 digits
Intl Grouping Length [1] = 3 digits

Are you sure something else didn't change on your system at the same time? The C++ library just parses the locale definition data on your system, that data comes from glibc not from GCC.
Comment 3 Jonathan Wakely 2018-05-10 12:50:13 UTC
Oh I take it back, when I use -static I can reproduce the problem.
Comment 4 Jonathan Wakely 2018-05-10 13:08:38 UTC
Reduced:

#include <iostream>
#include <locale>

using namespace std;

void test(std::locale loc)
{
  cout << "--> Setting locale '" << loc.name() << "'\n";
  const moneypunct<char, true> & l_facMoneyIntl = use_facet<moneypunct<char, true> >(loc);
  const moneypunct<char, false> & l_facMoneyNatl = use_facet<moneypunct<char, false> >(loc);
  cout << "Natl Currency Symbol     = '"; cout << l_facMoneyNatl.curr_symbol(); cout << "'" << "\n";
  cout << "Intl Currency Symbol     = '"; cout << l_facMoneyIntl.curr_symbol(); cout << "'" << "\n";
  cout << "\n";
}

int main(int argc, char** argv)
{
  locale global ("");
  // locale::global(global);
  test(locale(argc == 1 ? "pt_BR.utf8" : argv[1]));
  test(global);
  test(locale("C"));
}


Without -static this produces something like:

--> Setting locale 'pt_BR.utf8'
Natl Currency Symbol     = 'R$'
Intl Currency Symbol     = 'BRL '

--> Setting locale 'LC_CTYPE=en_GB.UTF-8;LC_NUMERIC=en_GB.UTF-8;LC_TIME=en_GB.UTF-8;LC_COLLATE=C;LC_MONETARY=en_GB.UTF-8;LC_MESSAGES=en_GB.UTF-8;LC_PAPER=en_GB.UTF-8;LC_NAME=en_GB.UTF-8;LC_ADDRESS=en_GB.UTF-8;LC_TELEPHONE=en_GB.UTF-8;LC_MEASUREMENT=en_GB.UTF-8;LC_IDENTIFICATION=en_GB.UTF-8'
Natl Currency Symbol     = '£'
Intl Currency Symbol     = 'GBP '

--> Setting locale 'C'
Natl Currency Symbol     = ''
Intl Currency Symbol     = ''

But with -static the fields are all blank:

--> Setting locale 'pt_BR.utf8'
Natl Currency Symbol     = ''
Intl Currency Symbol     = ''

--> Setting locale 'LC_CTYPE=en_GB.UTF-8;LC_NUMERIC=en_GB.UTF-8;LC_TIME=en_GB.UTF-8;LC_COLLATE=C;LC_MONETARY=en_GB.UTF-8;LC_MESSAGES=en_GB.UTF-8;LC_PAPER=en_GB.UTF-8;LC_NAME=en_GB.UTF-8;LC_ADDRESS=en_GB.UTF-8;LC_TELEPHONE=en_GB.UTF-8;LC_MEASUREMENT=en_GB.UTF-8;LC_IDENTIFICATION=en_GB.UTF-8'
Natl Currency Symbol     = ''
Intl Currency Symbol     = ''

--> Setting locale 'C'
Natl Currency Symbol     = ''
Intl Currency Symbol     = ''


I can reproduce this with any version tested (back to 4.3.6).
Comment 5 Tom Straub 2018-05-10 13:15:00 UTC
Hi Johnathon,

Okay, thanks for confirming. I didn't realize it was such as old bug. You're right, I just recently switched over to using -static (got tired of the library mismatches with multiple gcc versions on my system).

Best, Tom
Comment 6 Jonathan Wakely 2018-05-10 17:59:11 UTC
This isn't a libstdc++ bug, I get the same with a pure C program:

$ cat loc.c
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>

int main()
{
  locale_t loc = newlocale(1 << LC_ALL, "en_US.UTF-8", 0);
  const char* ccurr = nl_langinfo_l(CURRENCY_SYMBOL, loc);
  printf("Currency symbol: %s\n", ccurr);
  return 0;
}
$ gcc -D_GNU_SOURCE loc.c
$ ./a.out
Currency symbol: $
$ gcc -D_GNU_SOURCE loc.c -static
$ ./a.out
Currency symbol: 

So this seems to be a glibc problem.
Comment 7 Tom Straub 2018-05-10 18:14:50 UTC
Hi Jonathan,

Thanks for really tracking that down. Looks like a really deep and subtle bug. I hope somebody knows where to look to fix it in the glibc code.

Best, Tom
Comment 8 Jonathan Wakely 2018-05-10 23:01:40 UTC
I don't think we can do anything to fix this in libstdc++ so I've reported it to glibc:
https://sourceware.org/bugzilla/show_bug.cgi?id=23164
Comment 9 Jonathan Wakely 2018-08-16 11:35:27 UTC
*** Bug 71641 has been marked as a duplicate of this bug. ***