Page MenuHomePhabricator

setlocale() calls may lead to crash
Closed, ResolvedPublic

Description

Calls like

const char* previousCLocale = setlocale(LC_NUMERIC, nullptr);
setlocale(LC_NUMERIC, "C");

are invalid because previousCLocale variable becomes invalid after the second setlocale() call.

https://msdn.microsoft.com/ru-ru/library/x99tb11d.aspx:
"Later calls to setlocale overwrite the string, which invalidates string pointers returned by earlier calls."

This may lead to random crashes.
It's possible to reproduce such crash if run debug version of program under Application Verifier with Basics.Heaps option enabled.

Event Timeline

kislinsk edited projects, added MITK (2016-11); removed MITK.
kislinsk added a subscriber: kislinsk.

The solution is probably to (1) simply replace setlocale with std::setlocale, and (2) copy the old locale name so it won't be clobbered by subsequent calls to setlocale. We should actually use mitk::LocaleSwitch whenever possible.

kislinsk triaged this task as Normal priority.Aug 24 2016, 11:40 AM

I'm not sure about this, http://en.cppreference.com/w/cpp/locale/setlocale says that a copy of the returned string can be used to restore locale, not string itself.

There is a pull request #140 that replaces all setlocale() calls with mitk::LocaleSwitch guard but it may be an overkill.

It's definitely enough to use std::string instead of char* to store returned value:

const std::string previousCLocale = setlocale(LC_NUMERIC, nullptr);
setlocale(LC_NUMERIC, "C");

It will create an independent copy of previous locale that isn't spoiled by future calls.

Yes, sorry, we just read it completely and I edited my comment above accordingly.

In itself I would not call replacing all locale calls with mitk::LocalSwitch overkill, only tedious. However looking at
https://github.com/MITK/MITK/pull/140

I do see one issue, which would keep me from accepting it as is:

What is the purpose of
https://github.com/MITK/MITK/pull/140/commits/d088f34cc30628d81723a7728b5c754f626e673c#diff-52e7f9c2c949eb22cf2c898c143fff18L18

You add

#include "mitkLogMacros.h"
#include <string>
#pragma warning(disable:4251)

I would hesitate to add includes to such a widely included header.

#include <string> is required to use std::string.
#include "mitkLogMacros.h" is required to use MITK_INFO.
Otherwise all files that include "mitkLocaleSwitch.h" will have to include both <string> and "mitkLogMacros.h" as well.

It's possible to remove "mitkLogMacros.h" if move implementation to .cpp file from mitkLocaleSwitch.h.

#pragma warning(disable:4251) is required to stop compiler warning about std::string export:

class 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' needs to have dll-interface to be used by clients of struct 'mitk::LocaleSwitch'

mitkMimeType.h already uses this pragma in slightly different way:

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif

So, I'll:

  1. Split mitk::LocaleSwitcher into .h and .cpp files
  2. Move "#include "mitkLogMacros.h" to .cpp
  3. Try to deal with 4251 warning in more elegant way.

I vote for

  1. Move implementation to .cpp file
  2. Remove std::string dependency in header by using the Pimpl idiom and change the signature of the ctor, which should be explicit btw.

@kuznetsov Do you want to do it or should we do it? Both really is okay for us, I'm just asking because we don't want to "take away" a contribution from you of course.

I'll do it.
Also, Pimpl will fix 4251 warning as well, as far as I understand.

Cool, thank you. Here's a nice example of the Pimpl idiom in MITK:

https://phabricator.mitk.org/diffusion/MITK/browse/master/Modules/Core/include/mitkPropertyFilter.h
https://phabricator.mitk.org/diffusion/MITK/browse/master/Modules/Core/src/DataManagement/mitkPropertyFilter.cpp

Don't forget to delete the impl pointer in the dtor of the actual class. It's a raw pointer instead of a std::unique_ptr because that would lead to the 4251 warning again.

Just saw the update on GitHub. A minor thing: Please initialize the impl in the initializer list of the ctor instead of in the ctor body, thank you!

Merged, thanks again.

dCIp7.gif (245×500 px, 942 KB)