Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this simple C++ program using <locale> correct?

This code seemed to work ok in (ubuntu trusty) versions of gcc and clang, and in Win 7 on a VM via mingw... Recently I upgraded to Wily and builds made with clang crash consistently here.

#include <iostream>
#include <locale>
#include <string>

int main() {
  std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}

Sometimes its a gibberish string followed by Aborted: Core dumped and sometimes its invalid free.

$ ./a.out 
The locale is 'en_US.UTF-8QX�у�X�у����0�����P�����\�(��\�(��\�(��h��t�������������y���������ț�ԛ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_UP����`�������������������������p�����������@��������������`�������������p��������������������@��@��@��`��������p������������0��P��p���qp��!en_US.UTF-8QЈ[�����\�(��\�(��\�(�����������@�� �����P�����0�����P�����\�(��\�(��\�(��Ȣ�Ԣ����������������(��4��@��L��en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!�v[��������������@�� �����P�����0�����P�����\�(��\�(���(��h��t��������������������Ȥ�Ԥ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!��[�� ����[�������7����7��.,!!x�[��!��[��!�[��@�����������@�� �����P�����0�����P�����\�(��\�(��\�(��(��4��@��L��X��d��p��|������������n_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻAborted (core dumped)

$ ./a.out 
The locale is 'en_US.UTF-8QX\%�QX\%�Q�G�0H��H�PI��I�\:|�Q\D|�Q\>|�QhK�tK��K��K��K��K��Q�K��K��K��K��K��K�en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻ
*** Error in `./a.out': free(): invalid pointer: 0x0000000000b04a98 ***
Aborted (core dumped)

(Both program outputs above were abbreviated greatly or they would not fit in this question.)

I also got an invalid free on Coliru with it as well.

But this is very similar to example code on cppreference:

#include <iostream>
#include <locale>
#include <string>

int main()
{
    std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
    // on startup, the global locale is the "C" locale
    std::wcout << 1000.01 << '\n';
    // replace the C++ global locale as well as the C locale with the user-preferred locale
    std::locale::global(std::locale(""));
    // use the new global locale for future wide character output
    std::wcout.imbue(std::locale());
    // output the same number again
    std::wcout << 1000.01 << '\n';
}

Actually that code crashes Coliru also... :facepalm:

More crashes of similar code from Coliru.

Is this a bug in the c++ library used by clang, or is this code defective?

Note also: These crashes seem to be restricted to the C++ api, if you use <clocale> instead things seem to work okay, so it may just be some trivial problem in the C++ bindings over this?

Variations using setlocale: 1 2 3

like image 344
Chris Beck Avatar asked Dec 07 '15 01:12

Chris Beck


3 Answers

Looks like this is caused by libstdc++'s ABI change in its basic_string, which was needed for C++11 conformance. To manage this transition, GCC added the abi_tag attribute, which changes the mangled name of functions so that functions for the new and old ABI can be distinguished, even if the change wouldn't otherwise affect the mangled name (e.g. the return type of a function).

This code

#include <locale>
#include <string>

int main() {
   std::locale().name();
}

on GCC emits a call to _ZNKSt6locale4nameB5cxx11Ev, which demangles to std::locale::name[abi:cxx11]() const, and returns a SSO string with the new ABI.

Clang, on other other hand, doesn't support the abi_tag attribute, and emits a call to _ZNKSt6locale4nameEv, which demangles to simply std::locale::name() const - which is the version returning a COW string (the old ABI).

The net result is that the program ends up trying to use a COW string as an SSO string when compiled with Clang. Havoc ensues.

The obvious workaround is to force the old ABI via -D_GLIBCXX_USE_CXX11_ABI=0.

like image 174
T.C. Avatar answered Nov 05 '22 04:11

T.C.


I think the "" parameter might be corrupting something. I don't think it's a legal argument?

To verify it's nothing else, try running this:

#include <iostream>
#include <locale>

int main() {
    std::locale("").name();
}
like image 42
user541686 Avatar answered Nov 05 '22 04:11

user541686


It compiles and runs just fine with GCC:

g++ -Wall -pedantic locale.cpp
  <= No errorrs, no warnings

./a.out
The locale is 'en_US.UTF-8'
  <= Expected output

ADDENDUM:

Exactly the same with MSVS 2013 - no errors or warnings compiling; no errors running:

locale.cpp =>

#include <iostream>
#include <locale>
#include <string>

int main() {
  std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}

Output =>

locale
The locale is 'English_United States.1252'
like image 1
paulsm4 Avatar answered Nov 05 '22 04:11

paulsm4