godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.71k stars 20.12k forks source link

Godot's command-line debugger does not quit application when passing `quit` command immediately #51387

Open Xrayez opened 3 years ago

Xrayez commented 3 years ago

Godot version

3.4 beta

System information

Windows 10

Issue description

While running tests and using Godot's --debug/-d option, passing quit/q command to Godot's debugger does not immediately quits application if there's a script error, as the help message suggests when you pass help/h.

Godot Engine v3.4.beta.goost.Xrayez.8f891535d - https://godotengine.org
OpenGL ES 2.0 Renderer: GeForce GTX 750 Ti/PCIe/SSE2
OpenGL ES Batching: ON

 ---  Gut  ---
[INFO]:  using [C:/Users/Xrayez/AppData/Roaming/Godot/app_userdata/Goost Tests] for temporary output.
Godot version:  3.4.0
GUT version:  7.1.0

Debugger Break, Reason: 'Parser Error: The argument 'arg_count' is never used in the function 'add_test_option'. If this is intended, prefix it with an underscore: '_arg_count' (warning treated as error)'
*Frame 0 - res://goost/core/test_command_line_parser.gd:9 in function ''
Enter "help" for assistance.
debug> q
SCRIPT ERROR: Parse Error: The argument 'arg_count' is never used in the function 'add_test_option'. If this is intended, prefix it with an underscore: '_arg_count' (warning treated as error)
          at: GDScript::reload (res://goost/core/test_command_line_parser.gd:9)
ERROR: Method failed. Returning: ERR_PARSE_ERROR
   at: GDScript::reload (modules\gdscript\gdscript.cpp:566)

Debugger Break, Reason: 'Parser Error: The argument 'arg_count' is never used in the function 'add_test_option'. If this is intended, prefix it with an underscore: '_arg_count' (warning treated as error)'
*Frame 0 - res://goost/core/test_command_line_parser.gd:9 in function ''
Enter "help" for assistance.
debug> q
SCRIPT ERROR: Parse Error: The argument 'arg_count' is never used in the function 'add_test_option'. If this is intended, prefix it with an underscore: '_arg_count' (warning treated as error)
          at: GDScript::reload (res://goost/core/test_command_line_parser.gd:9)
ERROR: Method failed. Returning: ERR_PARSE_ERROR
   at: GDScript::reload (modules\gdscript\gdscript.cpp:566)

Debugger Break, Reason: 'Invalid call. Nonexistent function 'new' in base 'GDScript'.'
*Frame 0 - res://addons/gut/test_collector.gd:48 in function 'get_new'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid set index 'gut' (on base: 'Nil') with value of type 'Control (gut.gd)'.'
*Frame 0 - res://addons/gut/gut.gd:548 in function '_setup_script'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid call. Nonexistent function 'has_method' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:599 in function '_call_deprecated_script_method'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid call. Nonexistent function 'before_all' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:718 in function '_call_before_all'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid call. Nonexistent function 'has_method' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:599 in function '_call_deprecated_script_method'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid call. Nonexistent function 'after_all' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:741 in function '_call_after_all'
Enter "help" for assistance.
debug> q

Debugger Break, Reason: 'Invalid call. Nonexistent function 'get_children' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:343 in function '_log_test_children_warning'
Enter "help" for assistance.
debug> q
ERROR: Parameter "p_child" is null.
   at: Node::remove_child (scene\main\node.cpp:1182)

Debugger Break, Reason: 'Invalid call. Nonexistent function 'get_assert_count' in base 'Nil'.'
*Frame 0 - res://addons/gut/gut.gd:871 in function '_test_the_scripts'
Enter "help" for assistance.
debug> q

The above output is from Goost, namely while working on goostengine/goost#123.

Steps to reproduce

Create a test project with main scene/script:

extends Node2D

# Calling methods that assert here does not
# allow to quit debugging session immediately.
func _ready():
    test_loop()
    test_individual()
    test_loop()
    test_individual()
    test_individual()
    test_loop()
    test_loop()
    test_individual()

# When the function's body is called in _ready(), the following work fine.

func test_loop():
    for i in 5:
        assert(false, "Oh no, Godot crashed again!")

func test_individual():
    assert(false, "Oh no, Godot crashed again!")
    assert(false, "Oh no, Godot crashed again!")
    assert(false, "Oh no, Godot crashed again!")
    assert(false, "Oh no, Godot crashed again!")
    assert(false, "Oh no, Godot crashed again!")

Then run:

godot --path "/path/to/test/project" --debug

Then press q and press Enter several times in succession until Godot finally quits.

The workaround: do not use --debug option, but then you may miss important error this way. Using Ctrl + C does not always work either while debugging this way to catch keyboard interrupt, so I have to forcefully kill Godot application, which is very inconvenient.

Minimal reproduction project

cannot-quit-godot.zip

Calinou commented 3 years ago

See also https://github.com/godotengine/godot/issues/19775 and https://github.com/godotengine/godot/issues/50170.

dbnicholson commented 1 month ago

I was running into similar issues with the debugger and took a closer look. The problem is that the quit command only tells the main loop to quit but it doesn't actually stop the GDScript VM. Like in the example above, it's quite likely that the error is encountered in the middle of a function call that will run until completion before the next iteration of the main loop.

94804 seems to fix it, but I think it's likely incomplete for really stopping the scripting engine.