Skip to content

Commit 78782dc

Browse files
committed
Fix static initialization order for UserFormatRegister map
A std::map is in an invalid state when just zero-initialized, and needs to be initialized by its constructor. As this initilization may be done after the first call to Register, a crash will typically happen. To fix this wrap all accesses to the map with a Meyers Singleton. Also remove the extra Array - most accesses are using the key, and the few format list iterations all sort the result afterwards anyway. Fixes NGSolve#201.
1 parent 975414c commit 78782dc

File tree

3 files changed

+36
-24
lines changed

3 files changed

+36
-24
lines changed

libsrc/interface/writeuser.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,38 @@
1616

1717
namespace netgen
1818
{
19-
extern MeshingParameters mparam;
19+
std::map<std::string, UserFormatRegister::UserFormatEntry>& UserFormatRegister::getFormats()
20+
{
21+
static std::map<std::string, UserFormatRegister::UserFormatEntry> formats = {};
22+
return formats;
23+
}
2024

21-
Array<UserFormatRegister::UserFormatEntry> UserFormatRegister::entries;
22-
std::map<string, int> UserFormatRegister::format_to_entry_index;
25+
void UserFormatRegister::Register(UserFormatRegister::UserFormatEntry && entry)
26+
{
27+
getFormats()[entry.format] = std::move(entry);
28+
}
29+
30+
const bool UserFormatRegister::HaveFormat(string format)
31+
{
32+
const auto formats = getFormats();
33+
return formats.find(format) != formats.end();
34+
}
35+
36+
const UserFormatRegister::UserFormatEntry & UserFormatRegister::Get(string format)
37+
{
38+
return getFormats()[format];
39+
}
40+
41+
extern MeshingParameters mparam;
2342

2443
void RegisterUserFormats (NgArray<const char*> & names,
2544
NgArray<const char*> & extensions)
2645

2746
{
28-
for (const auto & entry : UserFormatRegister::entries)
47+
for (const auto & entry : UserFormatRegister::getFormats())
2948
{
30-
names.Append (entry.format.c_str());
31-
extensions.Append (entry.extensions[0].c_str());
49+
names.Append (entry.second.format.c_str());
50+
extensions.Append (entry.second.extensions[0].c_str());
3251
}
3352
}
3453

libsrc/interface/writeuser.hpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,23 @@ struct UserFormatRegister {
2828
optional<FRead> read;
2929
optional<FWrite> write;
3030
};
31-
DLL_HEADER static Array<UserFormatEntry> entries;
32-
DLL_HEADER static std::map<string, int> format_to_entry_index;
31+
static void Register(UserFormatEntry && entry);
3332

34-
static void Register(UserFormatEntry && entry) {
35-
format_to_entry_index[entry.format] = entries.Size();
36-
entries.Append( std::move(entry) );
37-
}
38-
39-
static const bool HaveFormat(string format) {
40-
return format_to_entry_index.count(format) > 0;
41-
}
42-
static const UserFormatEntry & Get(string format) {
43-
return entries[format_to_entry_index[format]];
44-
}
33+
static const bool HaveFormat(string format);
34+
DLL_HEADER static const UserFormatEntry & Get(string format);
4535

4636
template<typename TFunc>
4737
static void IterateFormats(TFunc func, bool need_read=false, bool need_write=false) {
4838
Array<string> import_formats;
49-
for(const auto & e: entries)
50-
if((!need_read || e.read) && (!need_write || e.write))
51-
import_formats.Append(e.format);
39+
for(const auto & e: getFormats())
40+
if((!need_read || e.second.read) && (!need_write || e.second.write))
41+
import_formats.Append(e.second.format);
5242
QuickSort(import_formats);
5343
for(auto format : import_formats)
54-
func(entries[format_to_entry_index[format]]);
44+
func(Get(format));
5545
}
5646

47+
DLL_HEADER static std::map<std::string, UserFormatEntry>& getFormats();
5748
};
5849

5950
struct RegisterUserFormat {

libsrc/meshing/python_mesh.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,14 +700,16 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
700700

701701
string export_docu = "Export mesh to other file format. Supported formats are:\n";
702702
Array<string> export_formats;
703-
for(auto & e : UserFormatRegister::entries)
703+
for(auto & kv : UserFormatRegister::getFormats()) {
704+
const auto e = kv.second;
704705
if(e.write) {
705706
string s = '\t'+e.format+"\t("+e.extensions[0];
706707
for(auto & ext : e.extensions.Range(1, e.extensions.Size()))
707708
s += ", "+ext;
708709
s += ")\n";
709710
export_formats.Append(s);
710711
}
712+
}
711713
QuickSort(export_formats);
712714
for(const auto & s : export_formats)
713715
export_docu += s;

0 commit comments

Comments
 (0)