Prevent read-after-free in the queued CallableCustomStaticMethodPointer.

(cherry picked from commit eb81e8b2dc)
This commit is contained in:
bruvzg 2023-11-23 23:22:08 +02:00 committed by Yuri Sizov
parent 326314eaa9
commit d3713220b8
1 changed files with 3 additions and 27 deletions

View File

@ -81,35 +81,27 @@ template <class T, class... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
#ifdef DEBUG_ENABLED
uint64_t object_id; uint64_t object_id;
#endif
void (T::*method)(P...); void (T::*method)(P...);
} data; } data;
public: public:
virtual ObjectID get_object() const { virtual ObjectID get_object() const {
#ifdef DEBUG_ENABLED
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
return ObjectID(); return ObjectID();
} }
#endif
return data.instance->get_instance_id(); return data.instance->get_instance_id();
} }
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
#endif
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error); call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
} }
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) { CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance; data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id(); data.object_id = p_instance->get_instance_id();
#endif
data.method = p_method; data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data)); _setup((uint32_t *)&data, sizeof(Data));
} }
@ -135,36 +127,28 @@ template <class T, class R, class... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase { class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
#ifdef DEBUG_ENABLED
uint64_t object_id; uint64_t object_id;
#endif
R(T::*method) R(T::*method)
(P...); (P...);
} data; } data;
public: public:
virtual ObjectID get_object() const { virtual ObjectID get_object() const {
#ifdef DEBUG_ENABLED
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
return ObjectID(); return ObjectID();
} }
#endif
return data.instance->get_instance_id(); return data.instance->get_instance_id();
} }
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
#endif
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
} }
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) { CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance; data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id(); data.object_id = p_instance->get_instance_id();
#endif
data.method = p_method; data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data)); _setup((uint32_t *)&data, sizeof(Data));
} }
@ -190,36 +174,28 @@ template <class T, class R, class... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase { class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
#ifdef DEBUG_ENABLED
uint64_t object_id; uint64_t object_id;
#endif
R(T::*method) R(T::*method)
(P...) const; (P...) const;
} data; } data;
public: public:
virtual ObjectID get_object() const override { virtual ObjectID get_object() const override {
#ifdef DEBUG_ENABLED
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
return ObjectID(); return ObjectID();
} }
#endif
return data.instance->get_instance_id(); return data.instance->get_instance_id();
} }
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
#endif
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
} }
CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) { CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance; data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id(); data.object_id = p_instance->get_instance_id();
#endif
data.method = p_method; data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data)); _setup((uint32_t *)&data, sizeof(Data));
} }