From fa405a8337e21fc1c0d2a9386952e5eacbde5072 Mon Sep 17 00:00:00 2001 From: Emmanuel Leblond Date: Tue, 29 Nov 2022 18:12:47 +0100 Subject: [PATCH] Fix lifetime of StringName objects returned by Wrapped::_get_property_list --- include/godot_cpp/classes/wrapped.hpp | 413 +++++++++++++------------- 1 file changed, 207 insertions(+), 206 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 867ce371..dfc2748f 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -69,6 +69,7 @@ protected: static GDNativeBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { return false; } static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr r_out) {} + ::godot::List<::godot::PropertyInfo> plist_owned; GDNativePropertyInfo *plist = nullptr; uint32_t plist_size = 0; @@ -93,212 +94,212 @@ public: } // namespace godot -#define GDCLASS(m_class, m_inherits) \ -private: \ - void operator=(const m_class &p_rval) {} \ - friend class ::godot::ClassDB; \ - \ -protected: \ - virtual const ::godot::StringName *_get_extension_class_name() const override { \ - static ::godot::StringName string_name = get_class_static(); \ - return &string_name; \ - } \ - \ - virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ - return &___binding_callbacks; \ - } \ - \ - static void (*_get_bind_methods())() { \ - return &m_class::_bind_methods; \ - } \ - \ - static void (::godot::Wrapped::*_get_notification())(int) { \ - return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \ - } \ - \ - static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \ - return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \ - } \ - \ - static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \ - return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \ - } \ - \ - static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \ - return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \ - } \ - \ - static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \ - return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \ - } \ - \ - static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) { \ - return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &)) & m_class::_property_get_revert; \ - } \ - \ - static ::godot::String (::godot::Wrapped::*_get_to_string())() { \ - return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string; \ - } \ - \ - template \ - static void register_virtuals() { \ - m_inherits::register_virtuals(); \ - } \ - \ -public: \ - static void initialize_class() { \ - static bool initialized = false; \ - if (initialized) { \ - return; \ - } \ - m_inherits::initialize_class(); \ - if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ - _bind_methods(); \ - m_inherits::register_virtuals(); \ - } \ - initialized = true; \ - } \ - \ - static ::godot::StringName &get_class_static() { \ - static ::godot::StringName string_name = ::godot::StringName(#m_class); \ - return string_name; \ - } \ - \ - static ::godot::StringName &get_parent_class_static() { \ - return m_inherits::get_class_static(); \ - } \ - \ - static GDNativeObjectPtr create(void *data) { \ - m_class *new_object = memnew(m_class); \ - return new_object->_owner; \ - } \ - \ - static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \ - if (p_instance && m_class::_get_notification()) { \ - if (m_class::_get_notification() != m_inherits::_get_notification()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - return cls->_notification(p_what); \ - } \ - m_inherits::notification_bind(p_instance, p_what); \ - } \ - } \ - \ - static GDNativeBool set_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value) { \ - if (p_instance && m_class::_get_set()) { \ - if (m_class::_get_set() != m_inherits::_get_set()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - return cls->_set(*reinterpret_cast(p_name), *reinterpret_cast(p_value)); \ - } \ - return m_inherits::set_bind(p_instance, p_name, p_value); \ - } \ - return false; \ - } \ - \ - static GDNativeBool get_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ - if (p_instance && m_class::_get_get()) { \ - if (m_class::_get_get() != m_inherits::_get_get()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - return cls->_get(*reinterpret_cast(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \ - } \ - return m_inherits::get_bind(p_instance, p_name, r_ret); \ - } \ - return false; \ - } \ - \ - static const GDNativePropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \ - if (p_instance && m_class::_get_get_property_list()) { \ - if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - ::godot::List<::godot::PropertyInfo> list; \ - cls->_get_property_list(&list); \ - ERR_FAIL_COND_V_MSG(cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \ - cls->plist = reinterpret_cast(memalloc(sizeof(GDNativePropertyInfo) * list.size())); \ - cls->plist_size = 0; \ - for (const ::godot::PropertyInfo &E : list) { \ - cls->plist[cls->plist_size].type = static_cast(E.type); \ - cls->plist[cls->plist_size].name = E.name._native_ptr(); \ - cls->plist[cls->plist_size].hint = E.hint; \ - cls->plist[cls->plist_size].hint_string = E.hint_string._native_ptr(); \ - cls->plist[cls->plist_size].class_name = E.class_name._native_ptr(); \ - cls->plist[cls->plist_size].usage = E.usage; \ - cls->plist_size++; \ - } \ - if (r_count) \ - *r_count = cls->plist_size; \ - return cls->plist; \ - } \ - return m_inherits::get_property_list_bind(p_instance, r_count); \ - } \ - return nullptr; \ - } \ - \ - static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list) { \ - if (p_instance) { \ - m_class *cls = reinterpret_cast(p_instance); \ - ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \ - memfree(cls->plist); \ - cls->plist = nullptr; \ - cls->plist_size = 0; \ - } \ - } \ - \ - static GDNativeBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name) { \ - if (p_instance && m_class::_get_property_can_revert()) { \ - if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - return cls->_property_can_revert(*reinterpret_cast(p_name)); \ - } \ - return m_inherits::property_can_revert_bind(p_instance, p_name); \ - } \ - return false; \ - } \ - \ - static GDNativeBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ - if (p_instance && m_class::_get_property_get_revert()) { \ - if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - return cls->_property_get_revert(*reinterpret_cast(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \ - } \ - return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \ - } \ - return false; \ - } \ - \ - static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr r_out) { \ - if (p_instance && m_class::_get_to_string()) { \ - if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \ - m_class *cls = reinterpret_cast(p_instance); \ - *reinterpret_cast<::godot::String *>(r_out) = cls->_to_string(); \ - *r_is_valid = true; \ - return; \ - } \ - m_inherits::to_string_bind(p_instance, r_is_valid, r_out); \ - } \ - } \ - \ - static void free(void *data, GDExtensionClassInstancePtr ptr) { \ - if (ptr) { \ - m_class *cls = reinterpret_cast(ptr); \ - cls->~m_class(); \ - ::godot::Memory::free_static(cls); \ - } \ - } \ - \ - static void *___binding_create_callback(void *p_token, void *p_instance) { \ - return nullptr; \ - } \ - \ - static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ - } \ - \ - static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ - return true; \ - } \ - \ - static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ - ___binding_create_callback, \ - ___binding_free_callback, \ - ___binding_reference_callback, \ +#define GDCLASS(m_class, m_inherits) \ +private: \ + void operator=(const m_class &p_rval) {} \ + friend class ::godot::ClassDB; \ + \ +protected: \ + virtual const ::godot::StringName *_get_extension_class_name() const override { \ + static ::godot::StringName string_name = get_class_static(); \ + return &string_name; \ + } \ + \ + virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ + return &___binding_callbacks; \ + } \ + \ + static void (*_get_bind_methods())() { \ + return &m_class::_bind_methods; \ + } \ + \ + static void (::godot::Wrapped::*_get_notification())(int) { \ + return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \ + } \ + \ + static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \ + return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \ + } \ + \ + static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \ + return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \ + } \ + \ + static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \ + return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \ + } \ + \ + static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \ + return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \ + } \ + \ + static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) { \ + return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &)) & m_class::_property_get_revert; \ + } \ + \ + static ::godot::String (::godot::Wrapped::*_get_to_string())() { \ + return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string; \ + } \ + \ + template \ + static void register_virtuals() { \ + m_inherits::register_virtuals(); \ + } \ + \ +public: \ + static void initialize_class() { \ + static bool initialized = false; \ + if (initialized) { \ + return; \ + } \ + m_inherits::initialize_class(); \ + if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ + _bind_methods(); \ + m_inherits::register_virtuals(); \ + } \ + initialized = true; \ + } \ + \ + static ::godot::StringName &get_class_static() { \ + static ::godot::StringName string_name = ::godot::StringName(#m_class); \ + return string_name; \ + } \ + \ + static ::godot::StringName &get_parent_class_static() { \ + return m_inherits::get_class_static(); \ + } \ + \ + static GDNativeObjectPtr create(void *data) { \ + m_class *new_object = memnew(m_class); \ + return new_object->_owner; \ + } \ + \ + static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \ + if (p_instance && m_class::_get_notification()) { \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_notification(p_what); \ + } \ + m_inherits::notification_bind(p_instance, p_what); \ + } \ + } \ + \ + static GDNativeBool set_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value) { \ + if (p_instance && m_class::_get_set()) { \ + if (m_class::_get_set() != m_inherits::_get_set()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_set(*reinterpret_cast(p_name), *reinterpret_cast(p_value)); \ + } \ + return m_inherits::set_bind(p_instance, p_name, p_value); \ + } \ + return false; \ + } \ + \ + static GDNativeBool get_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ + if (p_instance && m_class::_get_get()) { \ + if (m_class::_get_get() != m_inherits::_get_get()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_get(*reinterpret_cast(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \ + } \ + return m_inherits::get_bind(p_instance, p_name, r_ret); \ + } \ + return false; \ + } \ + \ + static const GDNativePropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \ + if (p_instance && m_class::_get_get_property_list()) { \ + if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + ERR_FAIL_COND_V_MSG(!cls->plist_owned.is_empty() || cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \ + cls->_get_property_list(&cls->plist_owned); \ + cls->plist = reinterpret_cast(memalloc(sizeof(GDNativePropertyInfo) * cls->plist_owned.size())); \ + cls->plist_size = 0; \ + for (const ::godot::PropertyInfo &E : cls->plist_owned) { \ + cls->plist[cls->plist_size].type = static_cast(E.type); \ + cls->plist[cls->plist_size].name = E.name._native_ptr(); \ + cls->plist[cls->plist_size].hint = E.hint; \ + cls->plist[cls->plist_size].hint_string = E.hint_string._native_ptr(); \ + cls->plist[cls->plist_size].class_name = E.class_name._native_ptr(); \ + cls->plist[cls->plist_size].usage = E.usage; \ + cls->plist_size++; \ + } \ + if (r_count) \ + *r_count = cls->plist_size; \ + return cls->plist; \ + } \ + return m_inherits::get_property_list_bind(p_instance, r_count); \ + } \ + return nullptr; \ + } \ + \ + static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list) { \ + if (p_instance) { \ + m_class *cls = reinterpret_cast(p_instance); \ + ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \ + memfree(cls->plist); \ + cls->plist = nullptr; \ + cls->plist_size = 0; \ + cls->plist_owned.clear(); \ + } \ + } \ + \ + static GDNativeBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name) { \ + if (p_instance && m_class::_get_property_can_revert()) { \ + if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_property_can_revert(*reinterpret_cast(p_name)); \ + } \ + return m_inherits::property_can_revert_bind(p_instance, p_name); \ + } \ + return false; \ + } \ + \ + static GDNativeBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ + if (p_instance && m_class::_get_property_get_revert()) { \ + if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_property_get_revert(*reinterpret_cast(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \ + } \ + return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \ + } \ + return false; \ + } \ + \ + static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr r_out) { \ + if (p_instance && m_class::_get_to_string()) { \ + if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + *reinterpret_cast<::godot::String *>(r_out) = cls->_to_string(); \ + *r_is_valid = true; \ + return; \ + } \ + m_inherits::to_string_bind(p_instance, r_is_valid, r_out); \ + } \ + } \ + \ + static void free(void *data, GDExtensionClassInstancePtr ptr) { \ + if (ptr) { \ + m_class *cls = reinterpret_cast(ptr); \ + cls->~m_class(); \ + ::godot::Memory::free_static(cls); \ + } \ + } \ + \ + static void *___binding_create_callback(void *p_token, void *p_instance) { \ + return nullptr; \ + } \ + \ + static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ + } \ + \ + static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ + return true; \ + } \ + \ + static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ + ___binding_create_callback, \ + ___binding_free_callback, \ + ___binding_reference_callback, \ }; // Don't use this for your classes, use GDCLASS() instead.