Accessing InputMap from C++

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By yosagi

Hi.
I’m trying to read (and modify) InputMap from C++ via GDNative.
I could write a code to access InputMap, but it makes the engine crash on exit.
The root cause seems something related to reference counting. Any advise please?

Platform: Windows 64bit
Version: 3.1.1.stable.official, 3.2.dev.custom_build.d2f38dbb2

A following code fragment is a core part of my code.

void godot::MyNode::_init()
{
  godot::Array al = godot::InputMap::get_singleton()->get_actions();
  for (int idx = 0; idx < al.size(); ++idx) {
    const godot::Array events= godot::InputMap::get_singleton()->get_action_list(al[idx]);
    for (int ei = 0; ei < events.size(); ei++) {
      const Ref<InputEvent> ev = events[ei];
      //const InputEvent *ev = events[ei];

Referencing ‘events[ei]’ with Ref or raw pointer causes the crash with a following message.

ERROR: ScriptServer::get_language: Index p_idx=0 out of size (_language_count=0)
   At: core\script_language.cpp:84

Simplified stack trace:

godot.windows.tools.64.exe!Reference::unreference() Line 97	C++
godot.windows.tools.64.exe!Ref<Reference>::unref() Line 280	C++
godot.windows.tools.64.exe!RefPtr::unref() Line 83	C++
godot.windows.tools.64.exe!Variant::clear() Line 1111	C++
godot.windows.tools.64.exe!Variant::~Variant() Line 422	C++

godot.windows.tools.64.exe!CowData<Variant>::~CowData<Variant>() Line 369	C++
godot.windows.tools.64.exe!Vector<Variant>::~Vector<Variant>() Line 126	C++

godot.windows.tools.64.exe!Array::~Array() Line 421	C++

godot.windows.tools.64.exe!Variant::~Variant() Line 422	C++

godot.windows.tools.64.exe!List<Pair<Variant const *,Variant>,DefaultAllocator>::~List<Pair<Variant const *,Variant>,DefaultAllocator>() Line 711	C++

godot.windows.tools.64.exe!Dictionary::~Dictionary() Line 289	C++

godot.windows.tools.64.exe!Variant::~Variant() Line 422	C++

godot.windows.tools.64.exe!memdelete_allocator<Map<StringName,ProjectSettings::VariantContainer,Comparator<StringName>,DefaultAllocator>::Element,DefaultAllocator>(Map<StringName,ProjectSettings::VariantContainer,Comparator<StringName>,DefaultAllocator>::Element * p_class) Line 133	C++

godot.windows.tools.64.exe!Map<StringName,ProjectSettings::VariantContainer,Comparator<StringName>,DefaultAllocator>::~Map<StringName,ProjectSettings::VariantContainer,Comparator<StringName>,DefaultAllocator>() Line 684	C++
godot.windows.tools.64.exe!ProjectSettings::~ProjectSettings() Line 1212	C++
godot.windows.tools.64.exe!Main::cleanup() Line 2094	C++

The code around Reference::unreference():97:

	if (instance_binding_count > 0) {
		for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
			if (_script_instance_bindings[i]) {
				bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
				die = die && script_ret;
			}
		}
	}

‘instance_binding_count’ was 1. Since ScriptServer::finish_languages() was called before Main::cleanup():2094 (at Main::cleanup():2055), I think ‘instance_binding_count’ should not be non-zero at this point.
But I could not find how this condition can be achieved.

I’ve copy-pasted the wrong stack trace on my post. The stack trace I showed was not a result from the code alone. It was produced with the code and a cleanup code below:

extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o)
{
  godot::Array al=godot::InputMap::get_singleton()->get_actions();
  for (int idx = 0; idx < al.size(); ++idx) {
    godot::InputMap::get_singleton()->erase_action(al[idx]);
  }
  godot::Godot::gdnative_terminate(o);
}

Without this cleanup code, the engine crashes at earlier stage with the similar reason.

 	godot.windows.tools.64.exe!Reference::unreference() Line 97	C++
 	godot.windows.tools.64.exe!Ref<InputEvent>::unref() Line 280	C++
 	godot.windows.tools.64.exe!Ref<InputEvent>::~Ref<InputEvent>() Line 298	C++
 	[External Code]	
 	godot.windows.tools.64.exe!memdelete_allocator<List<Ref<InputEvent>,DefaultAllocator>::Element,DefaultAllocator>(List<Ref<InputEvent>,DefaultAllocator>::Element * p_class) Line 133	C++
 	godot.windows.tools.64.exe!List<Ref<InputEvent>,DefaultAllocator>::_Data::erase(const List<Ref<InputEvent>,DefaultAllocator>::Element * p_I) Line 174	C++
 	godot.windows.tools.64.exe!List<Ref<InputEvent>,DefaultAllocator>::erase(const List<Ref<InputEvent>,DefaultAllocator>::Element * p_I) Line 368	C++
 	godot.windows.tools.64.exe!List<Ref<InputEvent>,DefaultAllocator>::clear() Line 405	C++
 	godot.windows.tools.64.exe!List<Ref<InputEvent>,DefaultAllocator>::~List<Ref<InputEvent>,DefaultAllocator>() Line 711	C++
 	[External Code]	
 	godot.windows.tools.64.exe!memdelete_allocator<Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::Element,DefaultAllocator>(Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::Element * p_class) Line 133	C++
 	godot.windows.tools.64.exe!Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::_cleanup_tree(Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::Element * p_element) Line 509	C++
 	godot.windows.tools.64.exe!Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::_cleanup_tree(Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::Element * p_element) Line 507	C++
 	godot.windows.tools.64.exe!Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::_cleanup_tree(Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::Element * p_element) Line 507	C++
 	godot.windows.tools.64.exe!Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::clear() Line 664	C++
 	godot.windows.tools.64.exe!Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>::~Map<StringName,InputMap::Action,Comparator<StringName>,DefaultAllocator>() Line 684	C++
 	[External Code]	
 	godot.windows.tools.64.exe!memdelete<InputMap>(InputMap * p_class) Line 122	C++
 	godot.windows.tools.64.exe!Main::cleanup() Line 2090	C++
 	godot.windows.tools.64.exe!widechar_main(int argc, wchar_t * * argv) Line 153	C++
 	godot.windows.tools.64.exe!_main() Line 173	C++
 	godot.windows.tools.64.exe!main(int _argc, char * * _argv) Line 185	C++

yosagi | 2019-10-23 03:55