summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuslan Mustakov <r.mustakov@gmail.com>2017-08-19 19:41:11 +0700
committerRuslan Mustakov <r.mustakov@gmail.com>2017-09-14 19:40:36 +0700
commitf08bc0df7c16a6d12292628ec8cc2e015047c450 (patch)
tree73b9bdaf5441798340bcbddcd96edc2430a9ccd0
parent9ac940677c9febc5f1c52782a717df61b0224344 (diff)
Construct Variants from Reference properly in GDNative
Previously godot_variant_new_object constructed Variant without accounting for the fact that the Object can be a Reference, so refcount was not increased and References were destructed prematurely. Also, Reference::init_ref did not propagate refcount increment to the script instance, which led to desync of refcount info on the script side and Godot side.
-rw-r--r--core/reference.cpp13
-rw-r--r--core/reference.h2
-rw-r--r--core/variant.cpp4
-rw-r--r--modules/gdnative/gdnative/variant.cpp17
4 files changed, 27 insertions, 9 deletions
diff --git a/core/reference.cpp b/core/reference.cpp
index bb70628cbe..7f93922d22 100644
--- a/core/reference.cpp
+++ b/core/reference.cpp
@@ -33,7 +33,7 @@
bool Reference::init_ref() {
- if (refcount.ref()) {
+ if (reference()) {
// this may fail in the scenario of two threads assigning the pointer for the FIRST TIME
// at the same time, which is never likely to happen (would be crazy to do)
@@ -41,7 +41,7 @@ bool Reference::init_ref() {
if (refcount_init.get() > 0) {
refcount_init.unref();
- refcount.unref(); // first referencing is already 1, so compensate for the ref above
+ unreference(); // first referencing is already 1, so compensate for the ref above
}
return true;
@@ -62,13 +62,16 @@ int Reference::reference_get_count() const {
return refcount.get();
}
-void Reference::reference() {
+bool Reference::reference() {
+ bool success = refcount.ref();
- refcount.ref();
- if (get_script_instance()) {
+ if (success && get_script_instance()) {
get_script_instance()->refcount_incremented();
}
+
+ return success;
}
+
bool Reference::unreference() {
bool die = refcount.unref();
diff --git a/core/reference.h b/core/reference.h
index ca3ae60418..bafc164276 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -51,7 +51,7 @@ protected:
public:
_FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() < 1; }
bool init_ref();
- void reference();
+ bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
int reference_get_count() const;
diff --git a/core/variant.cpp b/core/variant.cpp
index 74f6b6a711..10d86152ee 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -2259,8 +2259,8 @@ Variant::Variant(const RefPtr &p_resource) {
type = OBJECT;
memnew_placement(_data._mem, ObjData);
- REF ref = p_resource;
- _get_obj().obj = ref.ptr();
+ REF *ref = reinterpret_cast<REF *>(p_resource.get_data());
+ _get_obj().obj = ref->ptr();
_get_obj().ref = p_resource;
}
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index b61f80b1f9..1b2aae607f 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "gdnative/variant.h"
+#include "core/reference.h"
#include "core/variant.h"
#ifdef __cplusplus
@@ -158,7 +159,21 @@ void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid)
void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) {
Variant *dest = (Variant *)r_dest;
Object *obj = (Object *)p_obj;
- memnew_placement_custom(dest, Variant, Variant(obj));
+ Reference *reference = Object::cast_to<Reference>(obj);
+ REF ref;
+ if (reference) {
+ ref = REF(reference);
+ }
+ if (!ref.is_null()) {
+ memnew_placement_custom(dest, Variant, Variant(ref.get_ref_ptr()));
+ } else {
+#if defined(DEBUG_METHODS_ENABLED)
+ if (reference) {
+ ERR_PRINT("Reference object has 0 refcount in godot_variant_new_object - you lost it somewhere.");
+ }
+#endif
+ memnew_placement_custom(dest, Variant, Variant(obj));
+ }
}
void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict) {