Godot Version
4.5.2.stable
Question
The GDExtension I’m making with Godot-cpp crashes without any errors when I call it’s node queue.free() but only when I compile it with target=template_release. How do I debug something like this?
I think that the problem might be on using = default for the destructors, even though it works for the debug without any warnings or errors. I tried adding UtilityFunction::print() statements to the destructors to check if they’re called, but the crash happens before I see anything in the console.
Attach debugger, look at stacktrace, though you mentioned that it doesn’t provide errors, so then i would be breaking just before the deletion and stepping through the code. You will need a godot compiled with symbols to make sense of the stacktrace.
The times I see this sort of thing for myself is when i have an infinite loop, or something weird with memory. i highly doubt its because of defaulting the destructor, that would leave dangling pointers at worst, not immediately crash your application.
Thank you, I’ll try that!
if you find a solution to your issue, try to report back on the steps you took to solve so that if someone else stumbles across this later they can follow in your footsteps.
Don’t worry, when I do, I will! Might take a few days for me to get to it, though.
Apologies for the delay. I took way longer than I should’ve to find it due to personal skill issues and other stuff at work.
Upon checking Window’s Event Viewer, there were entries for all the crashes the program had. The module failing is called ntdll.dll and the exception code is 0xc0000374. Googling it shows that it’s a Heap corruption. It did look like a memory allocation issue but now I’m sure, at least.
I had to unfortunately install Visual Studio (NOT Visual Studio Code) to use it’s debugger. I also added this line to the SConstruct file to compile the debugging symbols:
env['CCPDBFLAGS'] = '/Zi /Fd${TARGET}.pdb'
Upon running the Visual Studio debugger, it pointed this part of the code as the culprit for the crashes:
QVChunk::QVChunk():StaticBody3D(){
terrain_data = memnew_arr(int, DATA_SIZE);
for (int i = 0; i < DATA_SIZE; i++){
terrain_data[i] = 0;
}
}
void QVChunk::_notification(int p_what){
switch (p_what){
case NOTIFICATION_READY:
collision_shape = memnew(CollisionShape3D);
mesh_instance = memnew(MeshInstance3D);
add_child(collision_shape);
add_child(mesh_instance);
mesh_instance->set_mesh(memnew(ArrayMesh));
break;
case NOTIFICATION_EXIT_TREE:
if (terrain_data != nullptr){
memdelete(terrain_data); // <----- CAUSING CRASH
}
if (collision_shape != nullptr){
memdelete(collision_shape);
}
if (mesh_instance != nullptr){
memdelete(mesh_instance);
}
break;
}
}
Commenting out the whole NOTIFICATION_EXIT_TREE case block fixed it. Checked it with the debugger and it also not leaks any memory.
I have no idea why I don’t have to delete an array I allocated manually on object creation. I can see how deleting collision_shape and mesh_instance might not be needed, perhaps their memory is freed completely upon freeing the parent node. But not terrain_data. Maybe I don’t understand the difference between memnew() and new, I thought it was the same thing.