Boost locale - unset LANG needed when creating temporary files

Viewed 214

I am building a C++ project using CMake and have recently added temporary file creation using the Boost C++ library. This is how I have included Boost in the CMake files:

# get boost
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_MULTITHREADED ON)
SET(Boost_USE_STATIC_RUNTIME OFF)
FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(${exe_name} ${Boost_LIBRARIES})
ADD_LIBRARY(${lib_name} ${common_SOURCES})
TARGET_LINK_LIBRARIES(${lib_name} ${CMAKE_DL_LIBS} ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(${exe_name} ${lib_name})

This is how I call it in C++:

#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#undef BOOST_NO_CXX11_SCOPED_ENUMS
...
input_file *Utils::get_input_file_from_string(const std::string &inp) {
    std::string real_inp(inp);

    boost::filesystem::path temp_path = boost::filesystem::unique_path();
    const std::string temp_pathstr = temp_path.native();
        
    boost::filesystem::path temp_folder = boost::filesystem::temp_directory_path();
    const std::string temp_folderstr = temp_folder.native();
    const std::string temp_fname = temp_folderstr + "/" + temp_pathstr;
    
    const char *temp_pathchar = temp_fname.c_str();

    ...

    FILE *temp = fopen(temp_pathchar, "wb+");
    ...
    input_file *ret = new input_file;
    loadInput(ret, temp);

    fclose(temp);

    return ret;
}

When I run the program, I get the following error:

terminate called after throwing an instance of 'std::runtime_error'
  what():  locale::facet::_S_create_c_locale name not valid
Aborted (core dumped)

However, by running the bash command...

unset LANG

...the program runs successfully (note that echo $LANG returns C.UTF-8)

Is there a way to edit the program so that I do not need to run the unset LANG command every time I load a new shell instance?

EDIT: I am aware that it is possible to unset an environment variable within c++ but I believe that there must be a solution within Boost related to the locale that ensures the error is not raised.

(PS Just to reiterate, the program runs successfully with the desired output when unset LANG is called before running the executable)

1 Answers

It's hard to debug this well without back-and-forth or access to your machine as I couldn't reproduce this locally. I'll take a crack at it anyway. My guess is the locale issues come up due to the .native() conversion to a std::string. Try this instead:

input_file *Utils::get_input_file_from_string(const std::string &inp) {
    ...
    boost::filesystem::path temp_path = boost::filesystem::unique_path();
    boost::filesystem::path temp_folder = boost::filesystem::temp_directory_path();
    boost::filesystem::path temp_file_path = temp_folder / temp_path;

    // try either:
    std::string temp_file_path_string = temp_file_path.string();    
    const char *temp_pathchar = temp_file_path_string.c_str();
    // or:
    const char *temp_pathchar = temp_file_path.c_str();
    ...
}

This will not behave well on non-POSIX platforms if you go with the lines that use string() due to the use of forward slashes.

Also, I'd try to do some more minimization of the code shown. It seems possible that unique_path() is throwing the error. Try hardcoding a path or path string and see if the error persists, for example.

Related