Repository: godot
Issue: `ptrcall` handles `godot_array` return values inconsistently with regards to initialization
Labels: bug,topic:gdextension

**Godot version:** Current master (`3306935`)

**OS/device including version:** N/A

**Issue description:**

In `core/method_ptrcall.h`, methods that return `Array`, e.g. `Node::get_children`, directly *overwrites* the return pointer. To prevent memory leaks, the pointer needs to point to an *uninitialized* `godot_array`:

```cpp
// https://github.com/godotengine/godot/blob/33069352890e24370a424b8397b27ca1210d7acc/core/method_ptrcall.h#L45
#define MAKE_PTRARG(m_type)                                            \
	template <>                                                        \
	struct PtrToArg<m_type> {                                          \
		_FORCE_INLINE_ static m_type convert(const void *p_ptr) {      \
			return *reinterpret_cast<const m_type *>(p_ptr);           \
		}                                                              \
		_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
			*((m_type *)p_ptr) = p_val;                                \
		}                                                              \
	};                                                                 \
	template <>                                                        \
	struct PtrToArg<const m_type &> {                                  \
		_FORCE_INLINE_ static m_type convert(const void *p_ptr) {      \
			return *reinterpret_cast<const m_type *>(p_ptr);           \
		}                                                              \
		_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
			*((m_type *)p_ptr) = p_val;                                \
		}                                                              \
	}

// ...

MAKE_PTRARG(Array);
```

However, methods that return `Vector<T>` natively, e.g. `Camera::get_frustum`, assume initialized arrays behind the pointer:

```cpp
// https://github.com/godotengine/godot/blob/33069352890e24370a424b8397b27ca1210d7acc/core/method_ptrcall.h#L289
#define MAKE_VECARR(m_type)                                                    \
	template <>                                                                \
	struct PtrToArg<Vector<m_type>> {                                          \
		_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) {      \
			const Array *arr = reinterpret_cast<const Array *>(p_ptr);         \
			Vector<m_type> ret;                                                \
			int len = arr->size();                                             \
			ret.resize(len);                                                   \
			for (int i = 0; i < len; i++) {                                    \
				ret.write[i] = (*arr)[i];                                      \
			}                                                                  \
			return ret;                                                        \
		}                                                                      \
		_FORCE_INLINE_ static void encode(Vector<m_type> p_vec, void *p_ptr) { \
			Array *arr = reinterpret_cast<Array *>(p_ptr);                     \
			int len = p_vec.size();                                            \
			arr->resize(len);                                                  \
			for (int i = 0; i < len; i++) {                                    \
				(*arr)[i] = p_vec[i];                                          \
			}                                                                  \
		}                                                                      \
	};                                                                         \
	template <>                                                                \
	struct PtrToArg<const Vector<m_type> &> {                                  \
		_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) {      \
			const Array *arr = reinterpret_cast<const Array *>(p_ptr);         \
			Vector<m_type> ret;                                                \
			int len = arr->size();                                             \
			ret.resize(len);                                                   \
			for (int i = 0; i < len; i++) {                                    \
				ret.write[i] = (*arr)[i];                                      \
			}                                                                  \
			return ret;                                                        \
		}                                                                      \
	}

MAKE_VECARR(Variant);
MAKE_VECARR(RID);
MAKE_VECARR(Plane);
```

In `api.json`, both methods show up as `"return_type": "Array"`. As a result, there is no way for consumers of the GDNative API to handle this consistently without leaking memory.

**Steps to reproduce:**

- Call `Node::get_children` using ptrcall with an uninitialized return pointer. The call completes successfully.
- Call `Camera::get_frustum` using ptrcall with an uninitialized return pointer. Godot segfaults.

**Minimal reproduction project:**

A reproduction project using the Rust bindings is provided by @DVDos: https://github.com/godot-rust/godot-rust/files/4781294/minimal_rust_422.zip

Original issue in the godot-rust repo: https://github.com/godot-rust/godot-rust/issues/422