Merge pull request #54433 from rxlecky/fix-undo-redo-double-free-50769
This commit is contained in:
commit
458f5b42a6
2 changed files with 21 additions and 45 deletions
|
@ -33,27 +33,22 @@
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
#include "core/resource.h"
|
#include "core/resource.h"
|
||||||
|
|
||||||
|
UndoRedo::Operation::~Operation() {
|
||||||
|
if (type == Operation::TYPE_REFERENCE) {
|
||||||
|
if (!ref.is_valid()) {
|
||||||
|
Object *obj = ObjectDB::get_instance(object);
|
||||||
|
if (obj) {
|
||||||
|
memdelete(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UndoRedo::_discard_redo() {
|
void UndoRedo::_discard_redo() {
|
||||||
if (current_action == actions.size() - 1) {
|
if (current_action == actions.size() - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
memdelete(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ERASE do data
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.resize(current_action + 1);
|
actions.resize(current_action + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,21 +63,7 @@ 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) {
|
||||||
// Clear all do ops from last action, and delete all object references
|
actions.write[current_action + 1].do_ops.clear();
|
||||||
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;
|
||||||
|
@ -223,19 +204,6 @@ 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--;
|
||||||
|
@ -322,6 +290,10 @@ 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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,17 +53,21 @@ 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 type = TYPE_INVALID;
|
||||||
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 {
|
||||||
|
|
Loading…
Reference in a new issue