1
0
Fork 0

Fix variant rejecting dying RefCounted

This commit is contained in:
Zhehang Ding 2025-01-08 15:29:29 +08:00
parent d2ada64a03
commit f40646901b
2 changed files with 38 additions and 8 deletions

View File

@ -1092,10 +1092,16 @@ void Variant::ObjData::ref(const ObjData &p_from) {
*this = p_from;
if (id.is_ref_counted()) {
RefCounted *reference = static_cast<RefCounted *>(obj);
// Assuming reference is not null because id.is_ref_counted() was true.
if (!reference->reference()) {
*this = ObjData();
RefCounted *reference = static_cast<RefCounted *>(obj);
// The RefCounted object might be dying (count == 0) but there are
// still reasons of using it (e.g. predeleted callback). In such case
// we treat it as a regular object and do not attempt to ref-count it
// (will not succeed and end up with a null object).
if (reference->get_reference_count() > 0) {
if (!reference->reference()) {
*this = ObjData();
}
}
}
@ -1114,8 +1120,10 @@ void Variant::ObjData::ref_pointer(Object *p_object) {
*this = ObjData{ p_object->get_instance_id(), p_object };
if (p_object->is_ref_counted()) {
RefCounted *reference = static_cast<RefCounted *>(p_object);
if (!reference->init_ref()) {
*this = ObjData();
if (reference->get_reference_count() > 0) {
if (!reference->init_ref()) {
*this = ObjData();
}
}
}
} else {
@ -1129,9 +1137,11 @@ void Variant::ObjData::unref() {
// Mirrors Ref::unref in refcounted.h
if (id.is_ref_counted()) {
RefCounted *reference = static_cast<RefCounted *>(obj);
// Assuming reference is not null because id.is_ref_counted() was true.
if (reference->unreference()) {
memdelete(reference);
if (reference->get_reference_count() > 0) {
// Assuming reference is not null because id.is_ref_counted() was true.
if (reference->unreference()) {
memdelete(reference);
}
}
}
*this = ObjData();

View File

@ -31,8 +31,10 @@
#ifndef TEST_VARIANT_H
#define TEST_VARIANT_H
#include "core/object/ref_counted.h"
#include "core/variant/variant.h"
#include "core/variant/variant_parser.h"
#include "core/variant/variant_utility.h"
#include "tests/test_macros.h"
@ -2216,6 +2218,24 @@ TEST_CASE("[Variant] Operator NOT") {
}
}
TEST_CASE("[Variant] Constructed from a dying RefCounted") {
RefCounted *obj = memnew(RefCounted);
const uint64_t obj_id = obj->get_instance_id();
obj->init_ref();
CHECK(obj->get_reference_count() == 1);
obj->unreference();
CHECK(obj->get_reference_count() == 0);
{
Variant v(obj);
CHECK(!v.is_null());
CHECK(VariantUtilityFunctions::is_instance_valid(v));
Object *o = v;
CHECK(o == (Object *)obj);
}
CHECK(VariantUtilityFunctions::is_instance_id_valid(obj_id));
memdelete(obj);
}
} // namespace TestVariant
#endif // TEST_VARIANT_H