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 #201.
This commit is contained in:
Stefan Brüns 2024-12-19 01:28:35 +01:00
parent 975414c2fe
commit 78782dcd53
3 changed files with 36 additions and 24 deletions

View File

@ -16,19 +16,38 @@
namespace netgen namespace netgen
{ {
extern MeshingParameters mparam; std::map<std::string, UserFormatRegister::UserFormatEntry>& UserFormatRegister::getFormats()
{
static std::map<std::string, UserFormatRegister::UserFormatEntry> formats = {};
return formats;
}
Array<UserFormatRegister::UserFormatEntry> UserFormatRegister::entries; void UserFormatRegister::Register(UserFormatRegister::UserFormatEntry && entry)
std::map<string, int> UserFormatRegister::format_to_entry_index; {
getFormats()[entry.format] = std::move(entry);
}
const bool UserFormatRegister::HaveFormat(string format)
{
const auto formats = getFormats();
return formats.find(format) != formats.end();
}
const UserFormatRegister::UserFormatEntry & UserFormatRegister::Get(string format)
{
return getFormats()[format];
}
extern MeshingParameters mparam;
void RegisterUserFormats (NgArray<const char*> & names, void RegisterUserFormats (NgArray<const char*> & names,
NgArray<const char*> & extensions) NgArray<const char*> & extensions)
{ {
for (const auto & entry : UserFormatRegister::entries) for (const auto & entry : UserFormatRegister::getFormats())
{ {
names.Append (entry.format.c_str()); names.Append (entry.second.format.c_str());
extensions.Append (entry.extensions[0].c_str()); extensions.Append (entry.second.extensions[0].c_str());
} }
} }

View File

@ -28,32 +28,23 @@ struct UserFormatRegister {
optional<FRead> read; optional<FRead> read;
optional<FWrite> write; optional<FWrite> write;
}; };
DLL_HEADER static Array<UserFormatEntry> entries; static void Register(UserFormatEntry && entry);
DLL_HEADER static std::map<string, int> format_to_entry_index;
static void Register(UserFormatEntry && entry) { static const bool HaveFormat(string format);
format_to_entry_index[entry.format] = entries.Size(); DLL_HEADER static const UserFormatEntry & Get(string format);
entries.Append( std::move(entry) );
}
static const bool HaveFormat(string format) {
return format_to_entry_index.count(format) > 0;
}
static const UserFormatEntry & Get(string format) {
return entries[format_to_entry_index[format]];
}
template<typename TFunc> template<typename TFunc>
static void IterateFormats(TFunc func, bool need_read=false, bool need_write=false) { static void IterateFormats(TFunc func, bool need_read=false, bool need_write=false) {
Array<string> import_formats; Array<string> import_formats;
for(const auto & e: entries) for(const auto & e: getFormats())
if((!need_read || e.read) && (!need_write || e.write)) if((!need_read || e.second.read) && (!need_write || e.second.write))
import_formats.Append(e.format); import_formats.Append(e.second.format);
QuickSort(import_formats); QuickSort(import_formats);
for(auto format : import_formats) for(auto format : import_formats)
func(entries[format_to_entry_index[format]]); func(Get(format));
} }
DLL_HEADER static std::map<std::string, UserFormatEntry>& getFormats();
}; };
struct RegisterUserFormat { struct RegisterUserFormat {

View File

@ -700,7 +700,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
string export_docu = "Export mesh to other file format. Supported formats are:\n"; string export_docu = "Export mesh to other file format. Supported formats are:\n";
Array<string> export_formats; Array<string> export_formats;
for(auto & e : UserFormatRegister::entries) for(auto & kv : UserFormatRegister::getFormats()) {
const auto e = kv.second;
if(e.write) { if(e.write) {
string s = '\t'+e.format+"\t("+e.extensions[0]; string s = '\t'+e.format+"\t("+e.extensions[0];
for(auto & ext : e.extensions.Range(1, e.extensions.Size())) for(auto & ext : e.extensions.Range(1, e.extensions.Size()))
@ -708,6 +709,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
s += ")\n"; s += ")\n";
export_formats.Append(s); export_formats.Append(s);
} }
}
QuickSort(export_formats); QuickSort(export_formats);
for(const auto & s : export_formats) for(const auto & s : export_formats)
export_docu += s; export_docu += s;