godot-cpp icon indicating copy to clipboard operation
godot-cpp copied to clipboard

Automatically detecting if GODOTCPP_TARGET is misconfigured (missing)

Open hhyyrylainen opened this issue 2 months ago • 7 comments

Godot version

4.5

godot-cpp version

4.5 (e83fd0904c13356ed1d4c3d09f8bb9132bdc6b77)

System information

macOS 15.6 (24G84)

Issue description

I had a pretty silly mistake in my build configuration as I was not setting -DGODOTCPP_TARGET=template_release in release CMake builds. That for some reason made only Mac release game exports crash. Everything else somehow still worked (Windows, Linux, and Mac debugging). It took me about 3 days to track down this "simple" build misconfiguration.

So as it is so, so difficult to debug this problem, I have a suggestion that at least one godot-cpp header could be set up to cause the build to immediately fail if mismatched flags are detected. This is what I used to finally after a long day today manage to track down the problem to be build flags, but I'm not sure if these would be in general the right combination of flags to check:

#ifdef NDEBUG
#ifdef DEBUG_ENABLED
#error "Invalid configuration of Godot build flags (release incorrect)"
#endif
#else
#ifndef DEBUG_ENABLED
#error "Invalid configuration of Godot build flags (no debug)"
#endif
#endif

And interestingly enough I have had this problem in my build flags since like Godot 4.3 but it is only now causing a problem on Mac with Godot 4.5.

Steps to reproduce

  • Build a GDExtesion for Godot 4.5 on Mac with CMake using -DCMAKE_BUID_TYPE=RelWithDebInfo (or another non-debug build type)
  • Export the project for Mac as a non-debug game
  • Run the game and get an immediate crash. The crash callstack sometimes had useful info (but often it was totally useless):
Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libthrive_extension_without_avx.dylib	       0x10e62b564 0x10e628000 + 13668
1   libthrive_extension_without_avx.dylib	       0x10e66f1a8 0x10e628000 + 291240
2   libthrive_extension_without_avx.dylib	       0x10e64cbd4 0x10e628000 + 150484
3   libthrive_extension_without_avx.dylib	       0x10e632260 0x10e628000 + 41568
4   Thrive                        	       0x1081bade8 GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel) + 84
5   Thrive                        	       0x1056123b8 Main::setup2(bool) + 15008
6   Thrive                        	       0x105606f94 Main::setup(char const*, int, char**, bool) + 95644

That at least hints to where the problem was but I could not see any problems with my method registration nor was I proficient enough in Mac debugging tools to be able to catch the problem (funnily enough I had to work on a different project on Linux before I was able to find this mistake as then I was able to use valgrind to pinpoint the memory allocation problems the mismatched flags caused).

Minimal reproduction project

Any project with at least one call to ClassDB::bind_method should be sufficient to trigger the issue.

hhyyrylainen avatar Sep 29 '25 15:09 hhyyrylainen

Might be a real bug. I wrote a thing I will copy paste at the bottom

So a template_debug(default) | Release, RelWithDebInfo or MinSizeRel build crashes on macos yeah? I can only guess at this stage, but:

  1. Do you use the preprocessor flags NDEBUG, DEBUG_FEATURES to gate your code in any way that could make it crash given the non mutually exclusivity of GODOTCPP_TARGET and CMAKE_BUILT_TYPE?
  2. I cant see any changes in godot or godot-cpp that are obvious.
  3. Would a template_debug build crash on a release godot normally? I think it would yeah? It's been a while since I tested these things and i havent tried 4.5 yet.
  4. I might have to pull out my m1 mini to test

Let me know after reading this whether I need to do anything.

Pasted from doc/cmake.rst

Debug vs template_debug

The conflation of a compilation of c++ source code with debug symbols enabled, and compiling a Godot extension with debug features enabled. The two concepts are not mutually inclusive.

debug_features

Enables a pre-processor definition to selectively compile code to help users of a Godot extension with their own project.

debug features are enabled in editor and template_debug builds, which can be specified during the configure phase like so

cmake -S . -B cmake-build -DGODOTCPP_TARGET=<target choice>

Debug

Sets compiler flags so that debug symbols are generated to help godot extension developers debug their extension.

Debug is the default build type for CMake projects, to select another it depends on the generator used

For single configuration generators, add to the configure command:

-DCMAKE_BUILD_TYPE=<type>

For multi-config generators add to the build command:

--config <type>

where is one of Debug, Release, RelWithDebInfo, MinSizeRel

enetheru avatar Sep 29 '25 22:09 enetheru

Might be a real bug.

It's possible that there's some incorrectly preprocessor-guarded thing in the memory allocation. I still had one valgrind run output, which says stuff like:

==915455== Invalid write of size 8
==915455==    at 0x24F4A6FA: memnew_arr_template<GDExtensionVariantType> (memory.hpp:161)
==915455==    by 0x24F4A6FA: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:498)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:509)
==915455==    by 0x24F416CF: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.cpp:13)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F416CF: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455==  Address 0x25863fc8 is 8 bytes before a block of size 8 alloc'd
==915455==    at 0x5123B26: malloc (vg_replace_malloc.c:446)
==915455==    by 0x2F28B48: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x24F4A4BC: godot::Memory::alloc_static(unsigned long, bool) (memory.cpp:44)
==915455==    by 0x24F4A6F4: memnew_arr_template<GDExtensionVariantType> (memory.hpp:156)
==915455==    by 0x24F4A6F4: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)

And that points to this place in the code where I noticed an inconsistency with whether the allocation was padded or not:

void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
	bool prepad = false; // Already pre paded in the engine.
#else
	bool prepad = p_pad_align;
#endif

However, when correctly setting the build flag combination, that issue goes away as I discovered. But yeah it's possible that godot-cpp now incorrectly handles "partially" set debug mode in the memory allocation functions.


So a template_debug(default) | Release, RelWithDebInfo or MinSizeRel build crashes on macos yeah?

Yes, building with cmake mode RelWithDebInfo and forgetting to set the GODOTCPP_TARGET to anything (which I think defaults then to debug), causes that crash as described above. And also on Linux in a very simple template I was working on it causes memory issues. Here's more of what valgrind said:

==915455== Memcheck, a memory error detector
==915455== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==915455== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==915455== Command: ./GodotCppTemplate
==915455== 
Godot Engine v4.5.stable.official.876b29033 - https://godotengine.org
Vulkan 1.4.311 - Forward Mobile - Using Device #0: AMD - AMD Radeon RX 7900 XTX (RADV NAVI31)

==915455== Invalid write of size 8
==915455==    at 0x24F4A6FA: memnew_arr_template<GDExtensionVariantType> (memory.hpp:161)
==915455==    by 0x24F4A6FA: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:498)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:509)
==915455==    by 0x24F416CF: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.cpp:13)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F416CF: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455==  Address 0x25863fc8 is 8 bytes before a block of size 8 alloc'd
==915455==    at 0x5123B26: malloc (vg_replace_malloc.c:446)
==915455==    by 0x2F28B48: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x24F4A4BC: godot::Memory::alloc_static(unsigned long, bool) (memory.cpp:44)
==915455==    by 0x24F4A6F4: memnew_arr_template<GDExtensionVariantType> (memory.hpp:156)
==915455==    by 0x24F4A6F4: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:498)
==915455==    by 0x24F416CF: UnknownInlinedFun (method_bind.hpp:509)
==915455==    by 0x24F416CF: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.cpp:13)
==915455==    by 0x24F416CF: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F416CF: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455== 
==915455== Invalid write of size 8
==915455==    at 0x24F4A6FA: memnew_arr_template<GDExtensionVariantType> (memory.hpp:161)
==915455==    by 0x24F4A6FA: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F41861: UnknownInlinedFun (method_bind.hpp:340)
==915455==    by 0x24F41861: UnknownInlinedFun (method_bind.hpp:350)
==915455==    by 0x24F41861: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F41861: UnknownInlinedFun (GameSimulation.cpp:15)
==915455==    by 0x24F41861: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F41861: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455==  Address 0x25411438 is 8 bytes before a block of size 8 alloc'd
==915455==    at 0x5123B26: malloc (vg_replace_malloc.c:446)
==915455==    by 0x2F28B48: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x24F4A4BC: godot::Memory::alloc_static(unsigned long, bool) (memory.cpp:44)
==915455==    by 0x24F4A6F4: memnew_arr_template<GDExtensionVariantType> (memory.hpp:156)
==915455==    by 0x24F4A6F4: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F41861: UnknownInlinedFun (method_bind.hpp:340)
==915455==    by 0x24F41861: UnknownInlinedFun (method_bind.hpp:350)
==915455==    by 0x24F41861: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F41861: UnknownInlinedFun (GameSimulation.cpp:15)
==915455==    by 0x24F41861: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F41861: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455== 
==915455== Invalid write of size 8
==915455==    at 0x24F4A6FA: memnew_arr_template<GDExtensionVariantType> (memory.hpp:161)
==915455==    by 0x24F4A6FA: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F419E1: UnknownInlinedFun (method_bind.hpp:498)
==915455==    by 0x24F419E1: UnknownInlinedFun (method_bind.hpp:509)
==915455==    by 0x24F419E1: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F419E1: UnknownInlinedFun (GameSimulation.cpp:16)
==915455==    by 0x24F419E1: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F419E1: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455==  Address 0x258527c8 is 8 bytes before a block of size 8 alloc'd
==915455==    at 0x5123B26: malloc (vg_replace_malloc.c:446)
==915455==    by 0x2F28B48: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x24F4A4BC: godot::Memory::alloc_static(unsigned long, bool) (memory.cpp:44)
==915455==    by 0x24F4A6F4: memnew_arr_template<GDExtensionVariantType> (memory.hpp:156)
==915455==    by 0x24F4A6F4: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==915455==    by 0x24F419E1: UnknownInlinedFun (method_bind.hpp:498)
==915455==    by 0x24F419E1: UnknownInlinedFun (method_bind.hpp:509)
==915455==    by 0x24F419E1: UnknownInlinedFun (class_db.hpp:316)
==915455==    by 0x24F419E1: UnknownInlinedFun (GameSimulation.cpp:16)
==915455==    by 0x24F419E1: UnknownInlinedFun (GameSimulation.h:17)
==915455==    by 0x24F419E1: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) [clone .constprop.0] (class_db.hpp:283)
==915455==    by 0x24F4DC6E: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==915455==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x3447E83: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x345DD2B: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x426F09: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455==

-- I cut out a part here ---

==915455== Conditional jump or move depends on uninitialised value(s)
==915455==    at 0x2AC56EB: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x2AC8E4A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x2ACD324: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x2A3A3D5: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x2A8057E: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x274AB2A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x4D9F34: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x4270EE: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==915455==    by 0x526B574: (below main) (libc_start_call_main.h:58)
==915455== 
==915455== 
==915455== HEAP SUMMARY:
==915455==     in use at exit: 784,606 bytes in 3,759 blocks
==915455==   total heap usage: 873,861 allocs, 870,102 frees, 177,759,425 bytes allocated
==915455== 
==915455== LEAK SUMMARY:
==915455==    definitely lost: 0 bytes in 0 blocks
==915455==    indirectly lost: 0 bytes in 0 blocks
==915455==      possibly lost: 13,636 bytes in 32 blocks
==915455==    still reachable: 770,970 bytes in 3,727 blocks
==915455==         suppressed: 0 bytes in 0 blocks
==915455== Rerun with --leak-check=full to see details of leaked memory
==915455== 
==915455== Use --track-origins=yes to see where uninitialised values come from
==915455== For lists of detected and suppressed errors, rerun with: -s
==915455== ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0)

Do you use the preprocessor flags NDEBUG, DEBUG_FEATURES to gate your code in any way that could make it crash given the non mutually exclusivity of GODOTCPP_TARGET and CMAKE_BUILT_TYPE?

I use NDEBUG in my code but just for toggling a few prints and non-Godot related features.

Oh and in that very simple template project I had been working on I use no NDEBUG flag at all (but cmake does set it automatically).

Would a template_debug build crash on a release godot normally? I think it would yeah? It's been a while since I tested these things and i havent tried 4.5 yet.

In my experience that actually doesn't hit the same bug so I think I was able to replace on Linux the compiled GDExtension with a debug variant, but if I recall right on Mac that didn't work and a combination of a debug export with the debug GDExtension was required to not crash. But I might be misremembering a bit that it worked on Linux.

Let me know after reading this whether I need to do anything.

In my opinion it's not absolutely necessary to find out if there's a flag combination problem in godot-cpp now, as setting up a check against the invalid flag combination would be as good of a fix in my opinion.

Also the same problem (but the crash doesn't happen) can be triggered on Linux as well. You just need to run with valgrind to see the problem.


The conflation of a compilation of c++ source code with debug symbols enabled, and compiling a Godot extension with debug features enabled. The two concepts are not mutually inclusive.

Based on this it kind of sounds like a bug in godot-cpp, because I get the picture that doing a -DCMAKE_BUILD_TYPE=Release builds with the -DGODOTCPP_TARGET=template_debug should be a supported combination, or at least the documentation doesn't explicitly prohibit such a combination (even if it is less likely to be useful than template_release with debug build type).

hhyyrylainen avatar Sep 30 '25 06:09 hhyyrylainen

Thanks for responding in detail, now I want to build a crashing version with scons and see if they behave the same. Also I just want to be sure, your matching your godot template_debug/editor builds correctly with your godot-cpp template_debug/editor builds and not loading a template_release godot with a template_debug godot-cpp?

enetheru avatar Sep 30 '25 13:09 enetheru

Okay, so here's a re-test I just did:

  • I exported my test template project for Linux with the release library
  • I tested it just to make sure all is fine, and it still was
  • Then I deleted the libgame_extension.linux.template_release.x86_64.so file and took my template_debug variant of the same file and renamed it so that it gets loaded
  • Then I started the exported game, and it does not crash. And it can even properly call methods in the GDExtension. So you kind of can mix in the debug version to an exported release game.
  • Though, on shutdown it has memory problems:
Godot Engine v4.5.stable.official.876b29033 - https://godotengine.org
Vulkan 1.4.311 - Forward Mobile - Using Device #0: AMD - AMD Radeon RX 7900 XTX (RADV NAVI31)

free(): invalid next size (fast)
Keskeytetty (luotiin core-tiedosto)

And valgrind says:

==1762788== Memcheck, a memory error detector
==1762788== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==1762788== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==1762788== Command: ./GodotCppTemplate
==1762788== 
Godot Engine v4.5.stable.official.876b29033 - https://godotengine.org
Vulkan 1.4.311 - Forward Mobile - Using Device #0: AMD - AMD Radeon RX 7900 XTX (RADV NAVI31)

==1762788== Invalid write of size 8
==1762788==    at 0x24F52662: GDExtensionVariantType* godot::memnew_arr_template<GDExtensionVariantType>(unsigned long, char const*) (memory.hpp:161)
==1762788==    by 0x24F51D7D: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==1762788==    by 0x24F3B592: godot::MethodBindTR<unsigned long, godot::Vector3 const&>::MethodBindTR(unsigned long (godot::_gde_UnexistingClass::*)(godot::Vector3 const&)) (method_bind.hpp:498)
==1762788==    by 0x24F3AEC3: godot::MethodBind* godot::create_method_bind<Extension::GameSimulation, unsigned long, godot::Vector3 const&>(unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)) (method_bind.hpp:509)
==1762788==    by 0x24F3A6E0: godot::MethodBind* godot::ClassDB::bind_method<godot::MethodDefinition, unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)>(godot::MethodDefinition, unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)) (class_db.hpp:316)
==1762788==    by 0x24F391F5: Extension::GameSimulation::_bind_methods() (GameSimulation.cpp:13)
==1762788==    by 0x24F2E278: Extension::GameSimulation::initialize_class() (GameSimulation.h:17)
==1762788==    by 0x24F3137C: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) (class_db.hpp:283)
==1762788==    by 0x24F304C3: void godot::ClassDB::register_runtime_class<Extension::GameSimulation>() (class_db.hpp:306)
==1762788==    by 0x24F2CD45: initialize_game_extension_module(godot::ModuleInitializationLevel) (Registration.cpp:22)
==1762788==    by 0x24F56AFE: godot::GDExtensionBinding::initialize_level(void*, GDExtensionInitializationLevel) (godot.cpp:523)
==1762788==    by 0x2F4AB6A: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==1762788==  Address 0x6015138 is 8 bytes before a block of size 8 alloc'd
==1762788==    at 0x5123B26: malloc (vg_replace_malloc.c:446)
==1762788==    by 0x2F28B48: ??? (in /home/hhyyrylainen/Projects/GodotCppTemplate/builds/linux.x86_64/GodotCppTemplate)
==1762788==    by 0x24F518B8: godot::Memory::alloc_static(unsigned long, bool) (memory.cpp:44)
==1762788==    by 0x24F525F2: GDExtensionVariantType* godot::memnew_arr_template<GDExtensionVariantType>(unsigned long, char const*) (memory.hpp:156)
==1762788==    by 0x24F51D7D: godot::MethodBind::_generate_argument_types(int) (method_bind.cpp:74)
==1762788==    by 0x24F3B592: godot::MethodBindTR<unsigned long, godot::Vector3 const&>::MethodBindTR(unsigned long (godot::_gde_UnexistingClass::*)(godot::Vector3 const&)) (method_bind.hpp:498)
==1762788==    by 0x24F3AEC3: godot::MethodBind* godot::create_method_bind<Extension::GameSimulation, unsigned long, godot::Vector3 const&>(unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)) (method_bind.hpp:509)
==1762788==    by 0x24F3A6E0: godot::MethodBind* godot::ClassDB::bind_method<godot::MethodDefinition, unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)>(godot::MethodDefinition, unsigned long (Extension::GameSimulation::*)(godot::Vector3 const&)) (class_db.hpp:316)
==1762788==    by 0x24F391F5: Extension::GameSimulation::_bind_methods() (GameSimulation.cpp:13)
==1762788==    by 0x24F2E278: Extension::GameSimulation::initialize_class() (GameSimulation.h:17)
==1762788==    by 0x24F3137C: void godot::ClassDB::_register_class<Extension::GameSimulation, false>(bool, bool, bool) (class_db.hpp:283)
==1762788==    by 0x24F304C3: void godot::ClassDB::register_runtime_class<Extension::GameSimulation>() (class_db.hpp:306)

It seems to have the same problem with memory as mixing things the other way around.

So yeah there's a problem if you mix the debug template version into a release export, but it doesn't crash instantly and kind of works.

hhyyrylainen avatar Sep 30 '25 16:09 hhyyrylainen

I'm not sure if I understand this issue correctly, but if this is about how using a release build of a GDExtension with a debug build of Godot can lead to memory corruption and crashes, we already have some PRs to address that:

  • https://github.com/godotengine/godot-cpp/issues/1820
  • https://github.com/godotengine/godot/pull/108725

Godot was already in feature freeze when I made those PRs, so they couldn't be merged for Godot 4.5, but I'm hoping we can get them into Godot 4.6

dsnopek avatar Sep 30 '25 20:09 dsnopek

Oh, those do look very related to this issue. And yeah I can confirm that using a release GDExtension build with debug Godot causes those issues I just described in my previous message (https://github.com/godotengine/godot-cpp/issues/1856#issuecomment-3352953648).

But the root problem I had was the opposite case where I was using a debug version of a GDExtension with release Godot. That also causes the same memory corruption problem. Or at least that's from where I noticed the misconfiguration I had made with build flags. So I agree totally that something should be done so that this doesn't stay as a very hard bug to notice easily.

hhyyrylainen avatar Oct 01 '25 07:10 hhyyrylainen

But the root problem I had was the opposite case where I was using a debug version of a GDExtension with release Godot. That also causes the same memory corruption problem.

Hm, interesting! When I was investigating this issue previously, I only got double padding with that configuration - so, using more memory than necessary, but not corrupting memory.

Anyway, the above PRs were recently merged and should be included in Godot 4.6-dev2. Once that's released (or if you want to build Godot yourself from master), please test it when you have a chance, and let me know if it fixes the issue you were having

dsnopek avatar Oct 04 '25 19:10 dsnopek