diff options
| author | Joël Lamotte (Klaim) <mjklaim@gmail.com> | 2023-10-05 00:33:47 +0200 |
|---|---|---|
| committer | Joël Lamotte (Klaim) <mjklaim@gmail.com> | 2023-10-05 16:58:49 +0200 |
| commit | 5134c82573b727887b4f8dbd574c4db954298452 (patch) | |
| tree | 7d32c6d64e627de1f7c52affaf4a9f35d974a16a | |
| parent | cd61a9bbe881b902750111eac8b02c04778f366b (diff) | |
| download | redot-cpp-5134c82573b727887b4f8dbd574c4db954298452.tar.gz | |
Fixes crash in ClassDB::deinitialize due to usage of invalid iterator.
After the removed call to `std::vector::erase` all iterators,
`i` included, are invalidated and therefore this code has undefined
behavior (which can or not lead to a crash).
This change delays the removal of class names from
`class_register_order` to after having gone through it's content,
removing the undefined behavior.
| -rw-r--r-- | src/core/class_db.cpp | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index 7219a79..1f4b135 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -352,6 +352,7 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) { } void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { + std::set<StringName> to_erase; for (std::vector<StringName>::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) { const StringName &name = *i; const ClassInfo &cl = classes[name]; @@ -362,12 +363,20 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { internal::gdextension_interface_classdb_unregister_extension_class(internal::library, name._native_ptr()); - for (auto method : cl.method_map) { + for (const std::pair<const StringName, MethodBind *> &method : cl.method_map) { memdelete(method.second); } - classes.erase(*i); - class_register_order.erase((i + 1).base()); + classes.erase(name); + to_erase.insert(name); + } + + { + // The following is equivalent to c++20 `std::erase_if(class_register_order, [&](const StringName& name){ return to_erase.contains(name); });` + std::vector<StringName>::iterator it = std::remove_if(class_register_order.begin(), class_register_order.end(), [&](const StringName &p_name) { + return to_erase.count(p_name) > 0; + }); + class_register_order.erase(it, class_register_order.end()); } } |
