[Locale] Static locale initialisation

I'm encountering a crash with Boost.Locale as the process terminates I initialise the global Boost.Locale in the contructor of a class with a single static instance (the ATL module to be exact) as I don't have access to the code of my main method (it comes from the Boost.Test runner). A static object seems to be the only logical place to put this code: #include <boost/locale.hpp> // boost::locale::generator class CModule : public ATL::CAtlModule { public : CModule() : ATL::CAtlModule() { try { // Initialise Boost.Locale translation mechanism generator gen; gen.add_messages_path("C:/My/Path"); gen.add_messages_domain("swish"); std::locale::global(gen("")); // default locale } catch (std::exception) {} } HRESULT AddCommonRGSReplacements(IRegistrarBase*) { return S_OK; } }; CModule _AtlModule; // Global module instance However, when I run my EXE, it crashes as it terminates with: Unhandled exception at 0x5ba43d93 (msvcp80d.dll) in test-shell_folder.exe: 0xC0000005: Access violation reading location 0x0321f4e4. and the following stack trace: msvcp80d.dll!std::_DebugHeapDelete<std::locale::facet>(std::locale::facet * _Ptr=0x023af590) msvcp80d.dll!_Deletegloballocale(void * ptr=0x5bb25258) msvcp80d.dll!tidy_global() msvcp80d.dll!_Init_atexit::~_Init_atexit() msvcp80d.dll!`dynamic atexit destructor for 'init_atexit''() msvcp80d.dll!_CRT_INIT(void * hDllHandle=0x5ba30000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001) msvcp80d.dll!__DllMainCRTStartup(void * hDllHandle=0x5ba30000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001) msvcp80d.dll!_DllMainCRTStartup(void * hDllHandle=0x5ba30000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001) ntdll.dll!_LdrpCallInitRoutine@16() ntdll.dll!_LdrShutdownProcess@0() ntdll.dll!_RtlExitUserProcess@4() kernel32.dll!76843b69() msvcr80d.dll!__crtExitProcess(int status=0x00000000) msvcr80d.dll!doexit(int code=0x00000000, int quick=0x00000000, int retcaller=0x00000000) msvcr80d.dll!exit(int code=0x00000000) test-shell_folder.exe!__tmainCRTStartup() test-shell_folder.exe!mainCRTStartup() If I move the initialisation code to run just before each point I need to use translate() then it works fine. So maybe this has something to do with the way static data is destroyed. This is on Windows - not sure about other platforms. Any ideas? Many thanks. Alex Lamaison P.S. I realise Boost.Locale isn't in Boost yet but previous discussions have been here so it seems a reasonable place to ask.

I'm encountering a crash with Boost.Locale as the process terminates
I initialise the global Boost.Locale in the contructor of a class with a single static instance (the ATL module to be exact) as I don't have access to the code of my main method (it comes from the Boost.Test runner). A static object seems to be the only logical place to put this code:
<snip>
I've tried to reproduce the bug but I couldn't: at least with MSVC9 with Release and Debug builds and under Linux. (I do not have MSVC8 you are using). Can you provide a simple sample of the code that reproduces the issue so I can debug it? Also what setup are you using: - Debug, Release or RelWithDebInfo builds - How do you use Boost.Locale - static version or dynamic (dll)? if you use static version are you sure you link with correct ICU library -- (debug versions of ICU library end with "d" suffix) - What version of Boost.Locale you use? Taken from SVN, boost_locale.zip or boost_locale-svn_r1112.zip? - What is your system locale? - Does program crashes when dictionaries are not loaded? (i.e. comment out: gen.add_messages_domain("swish"); ) - What ICU version do you have?
If I move the initialisation code to run just before each point I need to use translate() then it works fine. So maybe this has something to do with the way static data is destroyed. This is on Windows - not sure about other platforms.
Any ideas?
Can you try please following: add global destructor that would reset the global locale to standard one: ~CModule() { std::locale::global(std::locale::classic()); }
Many thanks.
Alex Lamaison
P.S. I realise Boost.Locale isn't in Boost yet but previous discussions have been here so it seems a reasonable place to ask.
Yes this is the place, I would request the formal review soon, so I do need inputs from users before I do it. Thanks, Artyom

On Mon, 5 Apr 2010 00:27:05 -0700 (PDT), Artyom wrote:
I'm encountering a crash with Boost.Locale as the process terminates
I initialise the global Boost.Locale in the contructor of a class with a single static instance (the ATL module to be exact) as I don't have access to the code of my main method (it comes from the Boost.Test runner). A static object seems to be the only logical place to put this code:
<snip>
I've tried to reproduce the bug but I couldn't: at least with MSVC9 with Release and Debug builds and under Linux. (I do not have MSVC8 you are using).
Can you provide a simple sample of the code that reproduces the issue so I can debug it?
I'll try and whip something up tonight.
Also what setup are you using:
- Debug, Release or RelWithDebInfo builds
Debug
- How do you use Boost.Locale - static version or dynamic (dll)? if you use static version are you sure you link with correct ICU library -- (debug versions of ICU library end with "d" suffix)
I'm statically linking with my compiled Boost.Locale but I'm using the ICU DLLs from the ICU site - I'm not compiling my own. These don't have the d suffix as debug builds aren't redistributable. I believe they are also compiled with MSVC9 where I'm using MSVC8. Would this cause a problem. I expected that, if it did, it would fail completely not partially work like this.
- What version of Boost.Locale you use? Taken from SVN, boost_locale.zip or boost_locale-svn_r1112.zip?
svn_r1112.zip
- What is your system locale?
Testing with en_GB and nl.
- Does program crashes when dictionaries are not loaded? (i.e. comment out: gen.add_messages_domain("swish"); ) - What ICU version do you have?
4.2.1
Can you try please following: add global destructor that would reset the global locale to standard one:
~CModule() { std::locale::global(std::locale::classic()); }
This didn't make a difference. Thanks. Alex Lamaison

I'll try and whip something up tonight.
Thanks.
I'm statically linking with my compiled Boost.Locale but I'm using the ICU DLLs from the ICU site - I'm not compiling my own. These don't have the d suffix as debug builds aren't redistributable. I believe they are also compiled with MSVC9 where I'm using MSVC8. Would this cause a problem. I expected that, if it did, it would fail completely not partially work like this.
I would **strongly** recommend to download ICU sources and build it. It is very simple, they provide Visual Studio projects so you can **easily** build the correct version of ICU with debug and release configurations and for correct MSVC (they use different runtime dlls). This is the way I use ICU libraries. Believe me this is very simple. I had numerous issues and unexpected crashes when I had build projects with incorrect version of dlls and debug/release mismatch including ICU. I assume this **may be** not the issue but I still strongly recommend you to lineup versions/releases of ICU and your environment.
- What version of Boost.Locale you use? Taken from SVN, boost_locale.zip or boost_locale-svn_r1112.zip?
svn_r1112.zip
- What is your system locale?
Testing with en_GB and nl.
- Does program crashes when dictionaries are not loaded? (i.e. comment out: gen.add_messages_domain("swish"); ) - What ICU version do you have?
4.2.1
Can you try please following: add global destructor that would reset the global locale to standard one:
~CModule() { std::locale::global(std::locale::classic()); }
This didn't make a difference.
Thanks.
Alex Lamaison
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Tue, 6 Apr 2010 23:26:09 -0700 (PDT), Artyom wrote:
Can you provide a simple sample of the code that reproduces the issue so I can debug it?
I'll try and whip something up tonight.
Any updates?
I've had real trouble isolating a minimal set of code to reproduce this. It appears to be related to the static local instance: __PURE_APPDOMAIN_GLOBAL static std::locale::_Locimp *global_locale = 0; // pointer to current locale being deleted once for *each loaded DLL*. When I Release() a COM component in a separate DLL, the DLL is unloaded and calls tidy_global() deleting global_locale. Later the EXE terminates which again tries to delete global_locale causing an access violation. Unfortunately, I'm nowhere near a small set of code for repro yet :( Alex P.S. As you advised, I compiled my own version of ICU. Because they only ship an MSVC9 project with version 4.2 (why do projects to that?!) I've downgraded to 4.0.

I've had real trouble isolating a minimal set of code to reproduce this. It appears to be related to the static local instance:
__PURE_APPDOMAIN_GLOBAL static std::locale::_Locimp *global_locale = 0; // pointer to current locale
being deleted once for *each loaded DLL*. When I Release() a COM component in a separate DLL, the DLL is unloaded and calls tidy_global() deleting global_locale. Later the EXE terminates which again tries to delete global_locale causing an access violation.
Unfortunately, I'm nowhere near a small set of code for repro yet :(
Ok, I see, this enteres the area called COM+DLLs... where I feel quite... helpless. I really have no idea why this does not work and why something destroyed twice, because it shouldn't. But it looks like rather issue reated to runtime environment rather then to specific localization library. You probably may try to test something like that (create a facet of your own); class my_facet: std::locale::facet { public: my_facet() : std::locale::facet(0) { } std::locale::id id; }; std::locale::id my_facet::id; struct init { init() { std::locale tmp(std::locale::classic(),new my_facet); std::locale::global(tmp); }} instance; Maybe do some allocations, deallocations in it and see if it causes crash (without any usage of boost::locale), if it causes crash then it has nothing to do to library but rather to environment. -------------------------------- For unit test you may try to do something like that: void set_locale() { if(std::has_facet<boost::locale::info>(std::locale()) return; boost::locale::generator gen(); ... /// set path you need ... std::locale::global(gen("en_US.UTF-8")); } And before each test just call set_locale. It would check that `boost::locale` based locale was loaded (every such locale has boost::locale::info facet) and not reload dictionaries each time.
P.S. As you advised, I compiled my own version of ICU. Because they only ship an MSVC9 project with version 4.2 (why do projects to that?!) I've downgraded to 4.0.
Strange, because according to their documentation MSVC 2005 is supported. Artyom

I've notices something right now:
__PURE_APPDOMAIN_GLOBAL static std::locale::_Locimp *global_locale = 0; // pointer to current locale
Ok, this is interesting point... Make sure that all DLLs you are using are compiled correctly with Same MSVC runtime **DLL** (with correct import flags) and not mixed DLL/static library/ Because if they are not, there may be more then one instance of std::locale::_Locimp *global_locale = 0; If it was not exported! foo.dll -> uses dllexported std::locale::_Locimp *global_locale bar.dll -> uses dllexported std::locale::_Locimp *global_locale baz.dll -> do not import symbol of std::locale::_Locimp *global_locale and uses its own version. And you end with two static variables that are not merged... It is very unplesant issue (which makes me love ELF and shared objects ;-) ). When using Boost.Locale or any std::locale faces on your own you must make sure that all DLLs and libraries same MSVC DLL. Otherwise... wellcome to hell. Artyom

On Thu, 8 Apr 2010 13:25:05 -0700 (PDT), Artyom wrote:
__PURE_APPDOMAIN_GLOBAL static std::locale::_Locimp *global_locale = 0; // pointer to current locale
Ok, this is interesting point... Make sure that all DLLs you are using are compiled correctly with Same MSVC runtime **DLL** (with correct import flags) and not mixed DLL/static library/
You were right about that cause of that crash: i had mixed Release and Debug DLLs (that is a problem in its own right as typically you aren't in control of other DLLs)
Ok, I see, this enteres the area called COM+DLLs... where I feel quite... helpless. I really have no idea why this does not work and why something destroyed twice, because it shouldn't.
So reproducing it wasn't too hard after all (once i realised the DLL thing). This code should crash quite reliably: http://www.doc.ic.ac.uk/~awl03/locale_test.zip Turns out its not a COM problem but a general DLL problem
But it looks like rather issue reated to runtime environment rather then to specific localization library.
Basically what happens is that the DLL sets the global locale when it is loaded. Great. We work away doing stuff and everything is fine ... Then at some point the DLL is unloaded. But the global locale is still pointing at an object whose definition was provided by the non-unloaded DLL. Disaster! The next time anything tries to use a locale (like a simple stream op) we crash with an access violation. The problem here is setting a locale 'owned' by the DLL. Is there a way round this? If anyone uses Boost.Locale with COM (or any other situation where DLLs are unloaded) they will run into this problem. Many thanks. Alex

Ok, this is interesting point... Make sure that all
DLLs you are using
are compiled correctly with Same MSVC runtime **DLL** (with correct import flags) and not mixed DLL/static library/
You were right about that cause of that crash: i had mixed Release and Debug DLLs (that is a problem in its own right as typically you aren't in control of other DLLs)
So I do not understand fixing correct runtime solved your problem or not?
So reproducing it wasn't too hard after all (once i realised the DLL thing). This code should crash quite reliably: http://www.doc.ic.ac.uk/~awl03/locale_test.zip
Turns out its not a COM problem but a general DLL problem <snip> < Basically what happens is that the DLL sets the global locale when it is loaded. Great. We work away doing stuff and everything is fine ...
Then at some point the DLL is unloaded. But the global locale is still pointing at an object whose definition was provided by the non-unloaded DLL. Disaster! The next time anything tries to use a locale (like a simple stream op) we crash with an access violation.
The problem here is setting a locale 'owned' by the DLL. Is there a way round this?
If anyone uses Boost.Locale with COM (or any other situation where DLLs are unloaded) they will run into this problem.
Many thanks.
This code reproduces the issue of crash when you set global locale and then you do not unload it, at least I see that you do not call std::locale::global(std::locale::classic()) . Am I right? If so.. this is your problem and not Boost.Locale one. It can be recreated even on Linux with shared objects, if you create global locale in dynamic library and unload the library you will crash when you would try to create an locale instance - clearly. .......... Does it crashes when you call on library unload: std::locale::global(std::locale::classic()); If so, are you 100% sure it is called? Have you triyed to just create a global object with constructor and destructor (without writing DllMain) -- because it is more portable? If you cleanup it with: std::locale::global(std::locale::classic()); So normal object is created instead of boost.locale Now there is interesting point. If DLL sets some object owned by dll when you set std::locale::classic() to global locale... Then blame standard library, because classic instance should point to standard library runtime and not DLL and this has nothing to do with Boost.Locale. If so you may try to set std::locale classic just after unloading library. If it does not help... You should not set global locale in loadable module or move to other platform where dynamically loaded libraries are not so brain-damaged. (no offense all Windows users :-) ) In any case: - It seems to be rather standard library issue then Boost.Locale one - Any DLL that would create its own facets and set global locale would have this issue. Artyom

On Sat, 10 Apr 2010 13:07:47 -0700 (PDT), Artyom wrote:
You were right about that cause of that crash: i had mixed Release and Debug DLLs (that is a problem in its own right as typically you aren't in control of other DLLs)
So I do not understand fixing correct runtime solved your problem or not?
No, it just stopped the double-delete
Basically what happens is that the DLL sets the global locale when it is loaded. Great. We work away doing stuff and everything is fine ...
Then at some point the DLL is unloaded. But the global locale is still pointing at an object whose definition was provided by the non-unloaded DLL. Disaster! The next time anything tries to use a locale (like a simple stream op) we crash with an access violation.
The problem here is setting a locale 'owned' by the DLL. Is there a way round this?
This code reproduces the issue of crash when you set global locale and then you do not unload it, at least I see that you do not call std::locale::global(std::locale::classic()) . Am I right?
Yes, I wasn't doing that.
If so.. this is your problem and not Boost.Locale one.
It can be recreated even on Linux with shared objects, if you create global locale in dynamic library and unload the library you will crash when you would try to create an locale instance - clearly.
Can you add this to the documentation becuase its not at all obvious - there is no mention of cleanup.
Does it crashes when you call on library unload:
std::locale::global(std::locale::classic());
Yes, this fixes the crash. In fact, what I'm doing now is saving the old locale and restoring that when unloading so that if tow modules use boost.locale and one unloads, its doesn't destroy boost.locale for the other.
In any case:
- It seems to be rather standard library issue then Boost.Locale one - Any DLL that would create its own facets and set global locale would have this issue.
You're probably right but it needs to be documented explicitly. I've never come across a situation before where you have to do cleanup before unloading a DLL. Now that *that* part (not crashing) is fixed, I'm running into another problem. I can see the .mo file being loaded; excellent! But when I try to translate a string, the translation mechanism fails to find it! This only happens when i set the locale statically. If I set it just before using translate() it works fine. Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip To see the different situations, change which commentted line declaring LocaleSetup. The problem seems to be that std::has_facet looks for a Facet with an id of 46 (0x2e). But when it gets to this line: const facet *_Facptr = _Id < _Ptr->_Facetcount ? _Ptr->_Facetvec[_Id] : 0; // null if id off end _Facetcount is 46 so it decides it's off the end. I notice that in the working version _Facet::id is 44 (0x2c). Any idea what's happening here? Many thanks. Alex

Hello,
Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip
To see the different situations, change which commentted line declaring LocaleSetup. The problem seems to be that std::has_facet looks for a Facet with an id of 46 (0x2e). But when it gets to this line:
const facet *_Facptr = _Id < _Ptr->_Facetcount ? _Ptr->_Facetvec[_Id] : 0; // null if id off end
_Facetcount is 46 so it decides it's off the end. I notice that in the working version _Facet::id is 44 (0x2c).
Till I get to VS at evening so I'll be able to answer. Few questions: 1. Are you using statically or dynamically liked boost.locale? 2. Are you using statically or dynamically liked boost.test? 3. If you use dynamically liked versions do you specify correct import defines? 4. The last what parameters of CMake did you used when you build boost.locale library. 5. I really hope that after build you did not switch Debug/Release from the MSVC project but rather prepared two solutions with passing correct options to CMake?
Any idea what's happening here?
Yes... This is what called why I love dlls very much ;-) Each facet type should have specific unique id which is static member of facet class (std::locale::id). If this id is not unique - two different ids would be created and thus there would be mismatch of facets and you would not be able to use them. More then that, each time when id is initialized it uses some kind of global counter (static as well) that usually belongs to standard C++ library. If it is not unique two different facets may accidentally have same numeric id and... not work. How could this can happen? If some unit that accesses locale incorrectly uses standard library not importing symbols correctly it would end with duplicate counters or duplicate ids and this is relate to **evey** compilation unit. Also if the code uses accidentally debug and release version of MSVCRTX.dll This may happen. So it is very easy to screw everything up when using dlls and static class members... So what happens something somehow didn't used everything correctly. So you should be extremely careful when creating or using DLLs. At this point I have no idea. Maybe I missed something in my code or there is something missing in the builds. ................ P.S.: That is exactly the reason that after spending lots of time on Linux I suffer very much when I touch everything Windows related. P.P.S.: I'll take a look on the code you gave today or tomorrow. Artyom

On Sun, 11 Apr 2010 07:23:10 -0700 (PDT), Artyom wrote:
The problem seems to be that std::has_facet looks for a Facet with an id of 46 (0x2e). But when it gets to this line:
const facet *_Facptr = _Id < _Ptr->_Facetcount ? _Ptr->_Facetvec[_Id] : 0; // null if id off end
_Facetcount is 46 so it decides it's off the end. I notice that in the working version _Facet::id is 44 (0x2c).
Till I get to VS at evening so I'll be able to answer. Few questions:
1. Are you using statically or dynamically liked boost.locale?
Static
2. Are you using statically or dynamically liked boost.test?
Static
3. If you use dynamically liked versions do you specify correct import defines?
N/A
4. The last what parameters of CMake did you used when you build boost.locale library.
I'm afraid I don't understand the question
5. I really hope that after build you did not switch Debug/Release from the MSVC project but rather prepared two solutions with passing correct options to CMake?
I generated the single solution using CMake which puts a debug and release configuration in the same file. This is how it's supposed to work, right? I didn't run CMake twice to create two seperate solutions.
Any idea what's happening here?
Yes... This is what called why I love dlls very much ;-) ...snip... So it is very easy to screw everything up when using dlls and static class members...
So what happens something somehow didn't used everything correctly. So you should be extremely careful when creating or using DLLs.
I'm not using DLLs here! My repro code does it with a simple EXE. All it takes is a single static locale instance. This may even repro on Linux.
Each facet type should have specific unique id which is static member of facet class (std::locale::id).
If this id is not unique - two different ids would be created and thus there would be mismatch of facets and you would not be able to use them.
Where are these ids generated? I tried to find it but it seems that they appear by magic :P
P.P.S.: I'll take a look on the code you gave today or tomorrow.
Thanks! Alex

4. The last what parameters of CMake did you used when you build boost.locale library.
I'm afraid I don't understand the question
I mean had you passed any special parameters to CMake when you configured the library?
I generated the single solution using CMake which puts a debug and release configuration in the same file. This is how it's supposed to work, right? I didn't run CMake twice to create two seperate solutions.
Not really... CMake creates a solution for configured build. If you need two configurations rerun CMake and create different solution. See solution is not more then "makefile" or a way to build something. You do not change it, you rerun CMake. I'd suggest build libraries in clean way and add binaries to project rather then integrating project to solution. Think of using libraries created with bjam.
I'm not using DLLs here! My repro code does it with a simple EXE. All it takes is a single static locale instance.
You are using ICU dlls. And you are using MSVCRT.DLL -- these are DLLs.
This may even repro on Linux.
Not sure, because what you are explaining is quite DLL related (I had some similar issues that were strictly Build+DLL related.
Where are these ids generated? I tried to find it but it seems that they appear by magic :P
Generally id class is something like that: class std::locale::id { public: id() : my_id_(counter++) {} int _get_id() const { return my_id_; } private: int my_id_; static int counter; }; libstdc++.cpp int std::locale::id::counter; (Of course just literally, because the counter is atomic counter and so on). So if class is not exported correctly or used different dlls counter may have more then one instance... and this is bad. -------------------------- Artyom

On Sun, 11 Apr 2010 08:05:40 -0700 (PDT), Artyom wrote:
4. The last what parameters of CMake did you used when you build boost.locale library.
I'm afraid I don't understand the question
I mean had you passed any special parameters to CMake when you configured the library?
No, other than having to manually specify the individual ICU DLL paths.
I generated the single solution using CMake which puts a debug and release configuration in the same file. This is how it's supposed to work, right? I didn't run CMake twice to create two seperate solutions.
Not really... CMake creates a solution for configured build. If you need two configurations rerun CMake and create different solution.
See solution is not more then "makefile" or a way to build something. You do not change it, you rerun CMake.
I'd suggest build libraries in clean way and add binaries to project rather then integrating project to solution.
That's not how CMake works with Visual Studio projects. There is no option to generate a specific Debug or Release version (the value of CMAKE_BUILD_TYPE) is ignored.
I'm not using DLLs here! My repro code does it with a simple EXE. All it takes is a single static locale instance.
You are using ICU dlls. And you are using MSVCRT.DLL -- these are DLLs.
Sorry, I thought you were referring to my earlier DLL-unloading problem. Alex

I've noticed something
Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip
According to project files both Debug and Release versions of Boost.Locale use release versions of ICU. Check this. Also I strongly recommend regenerating solutions for debug and release using CMake. Artyom

On Sun, 11 Apr 2010 07:29:49 -0700 (PDT), Artyom wrote:
I've noticed something
Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip
According to project files both Debug and Release versions of Boost.Locale use release versions of ICU.
You're right. I've fixed this by removing the dependencies completely (they should only be in the EXE project) but I still have the same failure in both Debug and Release builds. Alex

Now that *that* part (not crashing) is fixed, I'm running into another problem. I can see the .mo file being loaded; excellent! But when I try to translate a string, the translation mechanism fails to find it! This only happens when i set the locale statically. If I set it just before using translate() it works fine.
Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip
To see the different situations, change which commentted line declaring LocaleSetup.
Ok, you are right, I managed to reproduce it. Looks like something overerites the created locale with other one. Maybe standard library defines global locale after it is defined in the constructor and this is just a question of an order of operation. I don't know I'll try to figure out. Note: I've tested on Linux and Windows with GCC with both static and dynamic libraries, this works. Looks like it happens only with MSVC. In any case... I don't think that defining the global locale in static constructor is generally good idea. For unit test you may use the trick I described with testing if the current locale has boost::locale::info facet. Best, Artyom

On Sun, 11 Apr 2010 12:25:53 -0700 (PDT), Artyom wrote:
Now that *that* part (not crashing) is fixed, I'm running into another problem. I can see the .mo file being loaded; excellent! But when I try to translate a string, the translation mechanism fails to find it! This only happens when i set the locale statically. If I set it just before using translate() it works fine.
Here is the repro code: http://www.doc.ic.ac.uk/~awl03/locale_test2.zip
To see the different situations, change which commentted line declaring LocaleSetup.
Ok, you are right, I managed to reproduce it. Looks like something overerites the created locale with other one.
Maybe standard library defines global locale after it is defined in the constructor and this is just a question of an order of operation. I don't know I'll try to figure out.
I'll happily test any fix you come up with.
Note: I've tested on Linux and Windows with GCC with both static and dynamic libraries, this works. Looks like it happens only with MSVC.
In any case... I don't think that defining the global locale in static constructor is generally good idea.
Possibly not but commonly done. My workaround is to declare a static *local variable* instance of LocalSetup inside DllMain. This is created at runtime, unlike true static variables which are created at loadtime.
For unit test you may use the trick I described with testing if the current locale has boost::locale::info facet.
Thanks for the tips :) Alex

Hi,
generator gen; gen.add_messages_path("C:/My/Path"); gen.add_messages_domain("swish"); std::locale::global(gen("")); // default locale
Small note, using *system* default locale gen("") in testing procedures is very error prone because it depends on current setup of the OS the program is running on. So I would recommend to define locale explicitly like: std::locale::global(gen("en_US.UTF-8")); Artyom
participants (2)
-
Alexander Lamaison
-
Artyom