Better prints messages (#46)

This commit is contained in:
Rafał Mikrut 2021-04-24 17:53:09 +02:00 committed by GitHub
parent 4d82f9f873
commit 4a4a1543d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 317 additions and 171 deletions

View File

@ -2,28 +2,21 @@ extends Node
var regression_test_project : bool = true # Set it to true in RegressionTestProject
# Contains info about disabled classes
# Also allows to get list of available classes
### Contains info about disabled classes and allows to take info about allowed methods
var properties_exceptions : Array = [
"user_data",
"config_file",
"",
"",
]
# Globablly disabled functions for all classes
var function_exceptions : Array = [
"_set_user_data",
"get_packet", # TODO
"create_from_mesh",
"_gui_input", # TODO probably missing cherrypick #GH 47636
"_input",
"_unhandled_input",
"_unhandled_key_input",
"connect_to_signal", # Should be chrrypicked
# They exists without assigment like Class.method, because they may be a parent of other objects and children also should have disabled child.method, its children also etc. which is too much to do
"connect_to_signal", # GH 47572
"set_config_file", # GH 45997
"class_get_property", # GH 47573
"class_set_property", # GH 47573
#"connect_to_signal", # GH 47572
"_editor_settings_changed",# GH 45979
"_submenu_timeout", # GH 45981
"_gui_input", # GH 45998
"_unhandled_key_input", # GH 45998
"_thread_done", #GH 46000
"generate", #GH 46001
"_proximity_group_broadcast", #GH 46002
@ -31,13 +24,10 @@ var function_exceptions : Array = [
"create_from", #GH 46004
"create_from_blend_shape", #GH 46004
"append_from", #GH 46004
"_unhandled_input", # TODO
"_input", # TODO
"_set_tile_data", #GH 46015
"get", #GH 46019
"instance_has", #GH 46020
"get_var", #GH 46096
"force_drag", #GH 46114
"set_script", #GH 46120
"getvar", #GH 46019
"get_available_chars", #GH 46118
@ -47,22 +37,16 @@ var function_exceptions : Array = [
"set_editor_hint", #GH 46252
"get_item_at_position", #TODO hard to find
"set_probe_data", #GH 46570
"_range_click_timeout",
"draw", #GH 46648
"_range_click_timeout", #GH 46648
"get_indexed", #GH 46019
"_vp_input", # TODO
"_vp_unhandled_input", # TODO
"remove_joy_mapping", #GH 46754
"add_joy_mapping", #GH 46754
"add_vertex", #GH 47066
"create_client", # TODO, strange memory leak
"create_shape_owner", #47135
"shape_owner_get_owner", #47135
"collide", #GH 46137
"collide_and_get_contacts", #GH 46137
"collide_with_motion", #GH 46137
"collide_with_motion_and_get_contacts", #GH 46137
"get_bind_bone", #GH 47358
"get_bind_name", #GH 47358
"get_bind_pose", #GH 47358
# TODO Check this later
"propagate_notification",
@ -162,67 +146,10 @@ var function_exceptions : Array = [
"raise",
"add_child",
"add_child_below_node",
]
var exported : Array = [
"get_bind_bone",
"get_bind_name",
"get_bind_pose",
"add_sibling",
]
# List of slow functions, which may frooze project(not simple executing each function alone)
var slow_functions : Array = [
"interpolate_baked",
"get_baked_length",
"get_baked_points",
"get_closest_offset",
"get_closest_point", # Only Curve, but looks that a lot of other classes uses this
"get_baked_up_vectors",
"interpolate_baked_up_vector",
"tessellate",
"get_baked_tilts",
"set_enabled_inputs",
"grow_mask",
"force_update_transform",
# In 3d view some options are really slow, needs to be limited
"set_rings",
"set_amount", # Particles
# Just a little slow functions
"is_enabler_enabled",
"set_enabler",
"get_aabb",
"set_aabb",
"is_on_screen"
]
# Specific classes which are initialized in specific way e.g. var undo_redo = get_undo_redo() instead var undo_redo = UndoRedo.new()
var only_instance : Array = [
"UndoRedo",
"Object",
"JSONRPC",
"MainLoop",
"SceneTree",
"ARVRPositionalTracker",
]
var invalid_signals : Array = [
"multi_selected",
"item_collapsed",
"button_pressed",
"",
"",
"",
# Probably Vararg
"tween_step",
"tween_completed",
"tween_started",
"data_channel_received",
"",
]
# Used only in ValueCreator
# Globally disabled classes which causes bugs or are very hard to us
var disabled_classes : Array = [
"ProjectSettings", # Don't mess with project settings, because they can broke entire your workflow
"EditorSettings", # Also don't mess with editor settings
@ -239,6 +166,8 @@ var disabled_classes : Array = [
"IP_Unix",
"JNISingleton",
# Only one class - JavaClass returns Null when using JavaClass.new().get_class
"JavaClass",
# Just don't use these because they are not normal things
"_Thread",
@ -246,53 +175,63 @@ var disabled_classes : Array = [
"_Mutex",
]
# GH 47358
func _init():
function_exceptions.append_array(exported)
# Checks if function can be executed
# Looks at its arguments an
func check_if_is_allowed(method_data : Dictionary) -> bool:
# Function is virtual, so we just skip it
# Function is virtual or vararg, so we just skip it
if method_data["flags"] == method_data["flags"] | METHOD_FLAG_VIRTUAL:
return false
if method_data["flags"] == method_data["flags"] | 128: # VARARG TODO, Godot issue, add missing flag binding
return false
for arg in method_data["args"]:
var name_of_class : String = arg["class_name"]
if name_of_class.empty():
continue
if !ClassDB.class_exists(name_of_class): # This is enum not object, but we allow it
continue
if name_of_class in disabled_classes:
return false
if name_of_class.find("Server") != -1 && ClassDB.class_exists(name_of_class) && !ClassDB.is_parent_class(name_of_class,"Reference"):
return false
if name_of_class.find("Editor") != -1: # TODO not sure about it
# Editor stuff usually aren't good choice for arhuments
if name_of_class.find("Editor") != -1 || name_of_class.find("SkinReference") != -1:
return false
# In case of adding new type, this prevents from crashing due not recognizing this type
# In case of removing/rename type, just comment e.g. TYPE_ARRAY and all occurencies on e.g. switch statement with it
var t : int = arg["type"]
if !(t == TYPE_NIL || t == TYPE_AABB || t == TYPE_ARRAY || t == TYPE_BASIS || t == TYPE_BOOL || t == TYPE_COLOR || t == TYPE_COLOR_ARRAY || t == TYPE_DICTIONARY || t == TYPE_INT || t == TYPE_INT_ARRAY || t == TYPE_NODE_PATH || t == TYPE_OBJECT || t == TYPE_PLANE || t == TYPE_QUAT || t == TYPE_RAW_ARRAY || t == TYPE_REAL || t == TYPE_REAL_ARRAY || t == TYPE_RECT2 || t == TYPE_RID || t == TYPE_STRING || t == TYPE_TRANSFORM || t == TYPE_TRANSFORM2D || t == TYPE_VECTOR2 || t == TYPE_VECTOR2_ARRAY || t == TYPE_VECTOR3 || t == TYPE_VECTOR3_ARRAY):
print("----------------------------------------------------------- TODO - MISSING TYPE, ADD SUPPORT IT") # Add assert here to get info which type is missing
return false
#This is only for RegressionTestProject, because it needs for now clear visual info what is going on screen, but some nodes broke view
if regression_test_project:
# That means that this is constant, not class
if !ClassDB.class_exists(name_of_class):
continue
if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"):
return false
# In case of adding new type, this prevents from crashing due not recognizing this type
var t : int = arg["type"]
if !(t == TYPE_NIL || t == TYPE_AABB || t == TYPE_ARRAY || t == TYPE_BASIS || t == TYPE_BOOL || t == TYPE_COLOR || t == TYPE_COLOR_ARRAY || t == TYPE_DICTIONARY || t == TYPE_INT || t == TYPE_INT_ARRAY || t == TYPE_NODE_PATH || t == TYPE_OBJECT || t == TYPE_PLANE || t == TYPE_QUAT || t == TYPE_RAW_ARRAY || t == TYPE_REAL || t == TYPE_REAL_ARRAY || t == TYPE_RECT2 || t == TYPE_RID || t == TYPE_STRING || t == TYPE_TRANSFORM || t == TYPE_TRANSFORM2D || t == TYPE_VECTOR2 || t == TYPE_VECTOR2_ARRAY || t == TYPE_VECTOR3 || t == TYPE_VECTOR3_ARRAY):
print("----------------------------------------------------------- TODO - MISSING TYPE, ADD SUPPORT IT")
return false
return true
# Return all available classes to instance and test
func remove_disabled_methods(method_list : Array, exceptions : Array) -> void:
for exception in exceptions:
var index: int = -1
for method_index in range(method_list.size()):
if method_list[method_index]["name"] == exception:
index = method_index
break
if index != -1:
method_list.remove(index)
# Return all available classes which can be used
func get_list_of_available_classes(must_be_instantable : bool = true) -> Array:
var full_class_list : Array = Array(ClassDB.get_class_list())
var classes : Array = []
full_class_list.sort()
var c = 0
var rr = 0
# var rr = 0
for name_of_class in full_class_list:
rr += 1
# rr += 1
if name_of_class in disabled_classes:
continue
@ -306,7 +245,7 @@ func get_list_of_available_classes(must_be_instantable : bool = true) -> Array:
if name_of_class.find("Server") != -1 && !ClassDB.is_parent_class(name_of_class,"Reference"):
continue
if name_of_class.find("Editor") != -1: # TODO not sure about it
if name_of_class.find("Editor") != -1 && regression_test_project:
continue

View File

@ -1,18 +1,32 @@
extends Node
# Execute every object function
### Script:
### - takes all available classes
### - checks if method is allowed
### - checks each argument if is allowed(in case e.g. adding new, to prevent crashes due not recognizing types)
### - print info if needed to console
### - execute function with parameters
var debug_print: bool = true
var add_to_tree: bool = false # Adds nodes to tree, freeze godot when removing a lot of nodes
var use_parent_methods: bool = false # Allows Node2D use Node methods etc. - it is a little slow option which rarely shows
var use_always_new_object: bool = true # Don't allow to "remeber" other function effects
var exiting: bool = true
var exiting: bool = false
func _ready() -> void:
if BasicData.regression_test_project:
ValueCreator.random = false # Results in RegressionTestProject must be always reproducible
else:
ValueCreator.random = true
ValueCreator.number = 100
ValueCreator.should_be_always_valid = false
if BasicData.regression_test_project:
tests_all_functions()
func _process(_delta: float) -> void:
if !BasicData.regression_test_project:
tests_all_functions()
@ -23,44 +37,54 @@ func _process(_delta: float) -> void:
# Test all functions
func tests_all_functions() -> void:
for name_of_class in BasicData.get_list_of_available_classes():
if debug_print:
print("\n#################### " + name_of_class + " ####################")
var object: Object = ClassDB.instance(name_of_class)
assert(object != null, "Object must be instantable")
if add_to_tree:
if object is Node:
add_child(object)
var method_list: Array = ClassDB.class_get_method_list(name_of_class, !use_parent_methods)
## Exception
for exception in BasicData.function_exceptions:
var index: int = -1
for method_index in range(method_list.size()):
if method_list[method_index]["name"] == exception:
index = method_index
break
if index != -1:
method_list.remove(index)
# Removes excluded methods
BasicData.remove_disabled_methods(method_list, BasicData.function_exceptions)
if debug_print:
print("#################### " + name_of_class +" ####################")
for _i in range(1):
for method_data in method_list:
if !BasicData.check_if_is_allowed(method_data):
continue
if debug_print:
print(name_of_class + "." + method_data["name"])
var arguments: Array = ParseArgumentType.parse_and_return_objects(method_data, name_of_class, debug_print)
if debug_print:
var to_print: String = "GDSCRIPT CODE: "
if (
ClassDB.is_parent_class(name_of_class, "Object")
&& !ClassDB.is_parent_class(name_of_class, "Node")
&& !ClassDB.is_parent_class(name_of_class, "Reference")
&& !ClassDB.class_has_method(name_of_class, "new")
):
to_print += "ClassDB.instance(\"" + name_of_class + "\")." + method_data["name"] + "("
else:
to_print += name_of_class.trim_prefix("_") + ".new()." + method_data["name"] + "("
for i in arguments.size():
to_print += ParseArgumentType.return_gdscript_code_which_run_this_object(arguments[i])
if i != arguments.size() - 1:
to_print += ", "
to_print += ")"
print(to_print)
var arguments: Array = ParseArgumentType.parse_and_return_objects(method_data, debug_print)
object.callv(method_data["name"], arguments)
for argument in arguments:
if argument != null:
if argument is Node:
argument.queue_free()
elif argument is Object && !(argument is Reference):
argument.free()
if argument is Node:
argument.queue_free()
elif argument is Object && !(argument is Reference):
argument.free()
if use_always_new_object:
assert(object != null, "Object must be instantable")
if object is Node:
object.queue_free()
elif object is Object && !(object is Reference):

View File

@ -1,7 +1,9 @@
extends Node
# Parse arguments and return needed info/objects etc.
### Scripts to arguments and return needed info about them.
### Class which contains informations about used
class SingleArgument:
var name: String # E.G. var roman, can be empty, so temp variable isn't created(nodes and objects must be created with temp_variable due to memory leaks)
var type: String # np. Vector2 or Object
@ -15,10 +17,6 @@ class SingleArgument:
func create_gdscript_arguments(arguments: Array) -> Array:
var argument_array: Array = []
ValueCreator.number = 10
ValueCreator.random = true
ValueCreator.should_be_always_valid = true # DO NOT CHANGE, BECAUSE NON VALID VALUES WILL SHOW GDSCRIPT ERRORS!
var counter = 0
for argument in arguments:
counter += 1
@ -122,17 +120,9 @@ func create_gdscript_arguments(arguments: Array) -> Array:
return argument_array
func parse_and_return_objects(method_data: Dictionary, debug_print: bool = false) -> Array:
func parse_and_return_objects(method_data: Dictionary, name_of_class: String, debug_print: bool = false) -> Array:
var arguments_array: Array = []
if BasicData.regression_test_project:
ValueCreator.number = 100
ValueCreator.random = false # Results in RegressionTestProject must be always reproducible
else:
ValueCreator.number = 1000
ValueCreator.random = true
ValueCreator.should_be_always_valid = false
for argument in method_data["args"]:
match argument.type:
TYPE_NIL: # Looks that this means VARIANT not null
@ -213,5 +203,196 @@ func parse_and_return_objects(method_data: Dictionary, debug_print: bool = false
assert(false, "Missing type, needs to be added to project")
if debug_print:
print("Parameters " + str(arguments_array))
print("\n" + name_of_class + "." + method_data["name"] + " --- executing with " + str(arguments_array.size()) + " parameters " + str(arguments_array))
return arguments_array
func return_gdscript_code_which_run_this_object(data) -> String:
if data == null:
return "null"
var return_string: String = ""
match typeof(data):
TYPE_NIL: # Looks that this means VARIANT not null
assert("false", "This is even possible?")
TYPE_AABB:
return_string = "AABB("
return_string += return_gdscript_code_which_run_this_object(data.position)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.size)
return_string += ")"
TYPE_ARRAY:
return_string = "Array(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_BASIS:
return_string = "Basis("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.z)
return_string += ")"
TYPE_BOOL:
if data == true:
return_string = "true"
else:
return_string = "false"
TYPE_COLOR:
return_string = "Color("
return_string += return_gdscript_code_which_run_this_object(data.r)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.g)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.b)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.a)
return_string += ")"
TYPE_COLOR_ARRAY:
return_string = "PoolColorArray(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_DICTIONARY:
return_string = "{"
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data.keys()[i])
return_string += " : "
return_string += return_gdscript_code_which_run_this_object(data.values()[i])
if i != data.size() - 1:
return_string += ", "
return_string += "}"
TYPE_INT:
return_string = str(data)
TYPE_INT_ARRAY:
return_string = "PoolIntArray(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_NODE_PATH:
return_string = "NodePath("
return_string += return_gdscript_code_which_run_this_object(str(data))
return_string += ")"
TYPE_OBJECT:
if data == null:
return_string = "null"
else:
var name_of_class: String = data.get_class()
if (
ClassDB.is_parent_class(name_of_class, "Object")
&& !ClassDB.is_parent_class(name_of_class, "Node")
&& !ClassDB.is_parent_class(name_of_class, "Reference")
&& !ClassDB.class_has_method(name_of_class, "new")
):
return_string += "ClassDB.instance(\"" + name_of_class + "\")"
else:
return_string = name_of_class.trim_prefix("_")
return_string += ".new()"
TYPE_PLANE:
return_string = "Plane("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.z)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.d)
return_string += ")"
TYPE_QUAT:
return_string = "Quat("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.z)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.w)
return_string += ")"
TYPE_RAW_ARRAY:
return_string = "PoolByteArray(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_REAL:
return_string = str(data)
TYPE_REAL_ARRAY:
return_string = "PoolRealArray(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_RECT2:
return_string = "Rect2("
return_string += return_gdscript_code_which_run_this_object(data.position)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.size)
return_string += ")"
TYPE_RID:
return_string = "RID()"
TYPE_STRING:
return_string = "\"" + data + "\""
TYPE_STRING_ARRAY:
return_string = "PoolStringArray(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_TRANSFORM:
return_string = "Transform("
return_string += return_gdscript_code_which_run_this_object(data.basis)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.origin)
return_string += ")"
TYPE_TRANSFORM2D:
return_string = "Transform2D("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.origin)
return_string += ")"
TYPE_VECTOR2:
return_string = "Vector2("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ")"
TYPE_VECTOR2_ARRAY:
return_string = "PoolVector2Array(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
TYPE_VECTOR3:
return_string = "Vector3("
return_string += return_gdscript_code_which_run_this_object(data.x)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.y)
return_string += ", "
return_string += return_gdscript_code_which_run_this_object(data.z)
return_string += ")"
TYPE_VECTOR3_ARRAY:
return_string = "PoolVector3Array(["
for i in data.size():
return_string += return_gdscript_code_which_run_this_object(data[i])
if i != data.size() - 1:
return_string += ", "
return_string += "])"
_:
assert(false, "Missing type, needs to be added to project")
return return_string

View File

@ -50,18 +50,19 @@ A scene that will probably give people a hard time quite often is `FunctionExecu
This is a fuzzer, but with removed ability to use random argument values (the arguments are identical every time it is run).
When the engine crashes, in logs usually will be something like this:
```
#################### SkeletonModification2DPhysicalBones ####################
SkeletonModification2DPhysicalBones.set_physical_bone_node
Parameters [100, ]
ERROR: Joint index out of range!
at: set_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:259)
SkeletonModification2DPhysicalBones.get_physical_bone_node
Parameters [100]
ERROR: Joint index out of range!
at: get_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:265)
SkeletonModification2DPhysicalBones.fetch_physical_bones
Parameters []
scene/resources/skeleton_modification_2d_physicalbones.cpp:186:2: runtime error: member access within null pointer of type 'struct SkeletonModificationStack2D'
#################### LineEdit ####################
LineEdit._text_changed --- executing with 0 parameters []
GDSCRIPT CODE: LineEdit.new()._text_changed()
LineEdit._toggle_draw_caret --- executing with 0 parameters []
GDSCRIPT CODE: LineEdit.new()._toggle_draw_caret()
LineEdit.set_align --- executing with 1 parameters [100]
GDSCRIPT CODE: LineEdit.new().set_align(100)
ERROR: set_align: Index (int)p_align = 100 is out of bounds (4 = 4).
At: scene/gui/line_edit.cpp:592.
scene/resources/line_edit.cpp:186:2: runtime error: member access within null pointer of type 'struct LineEdit'
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on godotengine/godot/issues
[1] bin/godot.linuxbsd.tools.64s() [0x1e697d8] (/home/runner/work/godot/godot/platform/linuxbsd/crash_handler_linuxbsd.cpp:54)
@ -70,24 +71,24 @@ Dumping the backtrace. Please include this when reporting the bug on godotengine
There are some interesting things to discuss here.
This line shows what class we are testing now
```
#################### SkeletonModification2DPhysicalBones ####################
#################### LineEdit ####################
```
which method
```
SkeletonModification2DPhysicalBones.set_physical_bone_node
LineEdit.set_align
```
and which parameters (here are two arguments - `100`, \` \`(empty string))
and which parameters
```
Parameters [100, ]
--- executing with 1 parameters [100]
```
To make testing easier, each object is created from scratch and by looking at the class definition in Godot - `set_physical_bone_node(int, String)` we can create an expression that is executed on this line:
Next you can see GDScript command which is executed and you can copy it and test manually in Godot
```
SkeletonModification2DPhysicalBones.new().set_physical_bone_node(100,"")
GDSCRIPT CODE: LineEdit.new()._toggle_draw_caret()
```
Then you can see errors caused by invalid arguments, which you can ignore if they don't cause other crashes/leaks etc.
```
ERROR: Joint index out of range!
at: get_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:265)
ERROR: set_align: Index (int)p_align = 100 is out of bounds (4 = 4).
At: scene/gui/line_edit.cpp:592.
```
At the end we can see Godot's crash log with additional information that tried to use null pointer incorrectly:
```
@ -97,14 +98,14 @@ Dumping the backtrace. Please include this when reporting the bug on godotengine
[1] bin/godot.linuxbsd.tools.64s() [0x1e697d8] (/home/runner/work/godot/godot/platform/linuxbsd/crash_handler_linuxbsd.cpp:54)
[2] /lib/x86_64-linux-gnu/libc.so.6(+0x46210) [0x7fd1ca5b0210] (??:0)
```
we can assume that this is caused by calling the function immediately before the crash:
In most situations, the latest executed function/created object is responsible for crash
```
SkeletonModification2DPhysicalBones.fetch_physical_bones
Parameters []
LineEdit.set_align --- executing with 1 parameters [100]
GDSCRIPT CODE: LineEdit.new().set_align(100)
```
We can test this by running a function in Godot that looks like this(just add `.new()` after class name and fill function arguments from `Parameters`):
So we can just take GDScript code from above, copy it into Godot and test project, which should crash engine
```
SkeletonModification2DPhysicalBones.new().fetch_physical_bones()
LineEdit.new().set_align(100)
```
## Nodes
@ -125,7 +126,8 @@ Scenes like `Physics2D.tscn` or `Lights3D.tscn` are normal scenes with specific
## 4.0 version limitations
ReparentingDeleting is in 4.0 only Reparenting - bug https://github.com/godotengine/godot/issues/45471
Some scenes available in 3.x branch, but due freezes and long loading times are disabled.
Some scenes available in 3.x branch, but due freezes and long loading times are disabled(mostly Vulkan fault).
Some patches are applied to e.g. handle rename `OS` -> `Platform` or `Transform` -> `Transform3D`
## Epilepsy Warning
Due using by project a lot of functions from each type of Node, screen may flicker, images and objects may change randomly color and size which may lead some users to health problems.