Skip to content

StringName errors can cause stack overflow through infinite recursion #108838

@mihe

Description

@mihe

Tested versions

  • Reproducible in: 4.5.beta [71a9948]
  • Not reproducible in: 4.4.1.stable

System information

Godot v4.5.beta (71a9948) - macOS Sequoia (15.5.0) - Multi-window, 1 monitor - Metal (Mobile) - integrated Apple M2 Pro (Apple8) - Apple M2 Pro (10 threads) - 32.00 GiB memory

Issue description

In short, because we now (as of #91006) have a way for things like ERR_FAIL_COND and other error macros to create a StringName as part of its error printing, the errors found in the StringName class itself can (and do) cause a stack overflow through infinite recursion when actually emitted.

The call stack (for 2 recursions) looks something like this:

StringName::unref() (core/string/string_name.cpp:113)
StringName::operator=(StringName const&) (core/string/string_name.cpp:190)
Array::set_typed(unsigned int, StringName const&, Variant const&) (core/variant/array.cpp:885)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:61)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:60)
CoreBind::OS::LoggerBind::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/core_bind.cpp:272)
CompositeLogger::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/io/logger.cpp:259)
_err_print_error(char const*, char const*, int, char const*, char const*, bool, ErrorHandlerType) (core/error/error_macros.cpp:95)
_err_print_error(char const*, char const*, int, char const*, bool, ErrorHandlerType) (core/error/error_macros.cpp:85)
StringName::unref() (core/string/string_name.cpp:114)
StringName::operator=(StringName const&) (core/string/string_name.cpp:190)
Array::set_typed(unsigned int, StringName const&, Variant const&) (core/variant/array.cpp:885)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:61)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:60)
CoreBind::OS::LoggerBind::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/core_bind.cpp:272)
CompositeLogger::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/io/logger.cpp:259)
_err_print_error(char const*, char const*, int, char const*, char const*, bool, ErrorHandlerType) (core/error/error_macros.cpp:95)
_err_print_error(char const*, char const*, int, char const*, bool, ErrorHandlerType) (core/error/error_macros.cpp:85)
StringName::unref() (core/string/string_name.cpp:114)
StringName::operator=(StringName const&) (core/string/string_name.cpp:190)
Array::set_typed(unsigned int, StringName const&, Variant const&) (core/variant/array.cpp:885)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:61)
TypedArray<ScriptBacktrace>::TypedArray() (core/variant/typed_array.h:60)
CoreBind::OS::LoggerBind::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/core_bind.cpp:272)
CompositeLogger::log_error(char const*, char const*, int, char const*, char const*, bool, Logger::ErrorType, Vector<Ref<ScriptBacktrace>> const&) (core/io/logger.cpp:259)
_err_print_error(char const*, char const*, int, char const*, char const*, bool, ErrorHandlerType) (core/error/error_macros.cpp:95)
_err_print_error(char const*, char const*, int, String const&, bool, ErrorHandlerType) (core/error/error_macros.cpp:89)
PagedAllocator<Variant::Pools::BucketMedium, true, 4096u>::~PagedAllocator() (core/templates/paged_allocator.h:169)
__cxa_finalize_ranges (@__cxa_finalize_ranges:123)
exit (@exit:14)
-[GodotApplicationDelegate applicationWillTerminate:] (platform/macos/godot_application_delegate.mm:302)
__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ (@__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__:40)
___CFXRegistrationPost_block_invoke (@___CFXRegistrationPost_block_invoke:26)
_CFXRegistrationPost (@_CFXRegistrationPost:112)
_CFXNotificationPost (@_CFXNotificationPost:188)
-[NSNotificationCenter postNotificationName:object:userInfo:] (@-[NSNotificationCenter postNotificationName:object:userInfo:]:25)
-[NSApplication terminate:] (@-[NSApplication terminate:]:418)
OS_MacOS_NSApp::terminate() (platform/macos/os_macos.mm:1134)
invocation function for block in OS_MacOS_NSApp::start_main() (platform/macos/os_macos.mm:1101)
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ (@__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__:12)
__CFRunLoopDoObservers (@__CFRunLoopDoObservers:137)
__CFRunLoopRun (@__CFRunLoopRun:239)
CFRunLoopRunSpecific (@CFRunLoopRunSpecific:146)
RunCurrentEventLoopInMode (@RunCurrentEventLoopInMode:84)
ReceiveNextEventCommon (@ReceiveNextEventCommon:172)
_BlockUntilNextEventMatchingListInModeWithFilter (@_BlockUntilNextEventMatchingListInModeWithFilter:22)
_DPSNextEvent (@_DPSNextEvent:174)
-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (@-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]:175)
-[NSApplication run] (@-[NSApplication run]:123)
main (platform/macos/godot_main_macos.mm:126)
start (@start:1522)

... where the error printed from StringName::unref is this:

ERR_FAIL_COND(!configured);

It's possible that this could have happened even before #91006 as well, but I'll label this a regression for now.

Steps to reproduce

N/A

Minimal reproduction project (MRP)

Unfortunately I have not been successful in making an MRP for this, but I hope the call stack speaks for itself.

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Release Blocker

Relationships

None yet

Development

No branches or pull requests

Issue actions