Merge pull request #55022 from godotengine/revert-54433-fix-undo-redo-double-free-50769

This commit is contained in:
Rémi Verschelde 2021-11-16 10:05:51 +01:00 committed by GitHub
commit 785fef988e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 21 deletions

View File

@ -33,20 +33,25 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "core/resource.h" #include "core/resource.h"
UndoRedo::Operation::~Operation() { void UndoRedo::_discard_redo() {
if (type == Operation::TYPE_REFERENCE) { if (current_action == actions.size() - 1) {
if (!ref.is_valid()) { return;
Object *obj = ObjectDB::get_instance(object); }
for (int i = current_action + 1; i < actions.size(); i++) {
for (List<Operation>::Element *E = actions.write[i].do_ops.front(); E; E = E->next()) {
if (E->get().type == Operation::TYPE_REFERENCE) {
if (E->get().ref.is_valid()) {
E->get().ref.unref();
} else {
Object *obj = ObjectDB::get_instance(E->get().object);
if (obj) { if (obj) {
memdelete(obj); memdelete(obj);
} }
} }
} }
} }
//ERASE do data
void UndoRedo::_discard_redo() {
if (current_action == actions.size() - 1) {
return;
} }
actions.resize(current_action + 1); actions.resize(current_action + 1);
@ -63,7 +68,21 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
current_action = actions.size() - 2; current_action = actions.size() - 2;
if (p_mode == MERGE_ENDS) { if (p_mode == MERGE_ENDS) {
actions.write[current_action + 1].do_ops.clear(); // Clear all do ops from last action, and delete all object references
List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front();
while (E) {
if (E->get().type == Operation::TYPE_REFERENCE) {
Object *obj = ObjectDB::get_instance(E->get().object);
if (obj) {
memdelete(obj);
}
}
E = E->next();
actions.write[current_action + 1].do_ops.pop_front();
}
} }
actions.write[actions.size() - 1].last_tick = ticks; actions.write[actions.size() - 1].last_tick = ticks;
@ -204,6 +223,19 @@ void UndoRedo::_pop_history_tail() {
return; return;
} }
for (List<Operation>::Element *E = actions.write[0].undo_ops.front(); E; E = E->next()) {
if (E->get().type == Operation::TYPE_REFERENCE) {
if (E->get().ref.is_valid()) {
E->get().ref.unref();
} else {
Object *obj = ObjectDB::get_instance(E->get().object);
if (obj) {
memdelete(obj);
}
}
}
}
actions.remove(0); actions.remove(0);
if (current_action >= 0) { if (current_action >= 0) {
current_action--; current_action--;
@ -290,10 +322,6 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
case Operation::TYPE_REFERENCE: { case Operation::TYPE_REFERENCE: {
//do nothing //do nothing
} break; } break;
default: {
ERR_PRINT("Invalid enum value of type UndoRedo::Operation::Type. Please report this as bug.");
}
} }
} }
} }

View File

@ -53,21 +53,17 @@ public:
private: private:
struct Operation { struct Operation {
public:
enum Type { enum Type {
TYPE_INVALID,
TYPE_METHOD, TYPE_METHOD,
TYPE_PROPERTY, TYPE_PROPERTY,
TYPE_REFERENCE TYPE_REFERENCE
}; };
Type type = TYPE_INVALID; Type type;
Ref<Reference> ref; Ref<Reference> ref;
ObjectID object; ObjectID object;
String name; String name;
Variant args[VARIANT_ARG_MAX]; Variant args[VARIANT_ARG_MAX];
~Operation();
}; };
struct Action { struct Action {