godotengine / godot

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

OS.execute returns ERR_CANT_FORK #38808

Open aabmets opened 4 years ago

aabmets commented 4 years ago

Godot version: 3.2.1

OS/device including version: Windows 10

Issue description: I need to run a batch file, which sets some env vars and launches a java applet, from inside Godot. The only way how is to use OS.execute: OS.execute("C:/build/gateway/bin/run.bat", [], false)

Contents of the .bat file:

set JAVA_HOME=c:\jdk
set PATH=%JAVA_HOME%\bin;%PATH%
set config_file="C:\build\gateway\root\conf.yaml"
set config_path="C:\build\gateway\root\"
set RUNTIME_PATH="C:\build\gateway\root\;dist\ibgroup.web.core.iblink.router.clientportal.gw.jar;build\lib\runtime\*"
java -Djava.net.preferIPv4Stack=true -Dvertx.disableDnsResolver=true -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory -Dnologback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener -Dnolog4j.debug=true -Dnolog4j2.debug=true -classpath %RUNTIME_PATH% ibgroup.web.core.clientportal.gw.GatewayStart

When the OS.execute method is called in an exported Godot project with debugging, the debug window throws the following error:

ERROR: execute: Condition "ret == 0" is true. Returned: ERR_CANT_FORK
   At: platform/windows/os_windows.cpp:2749

As much as I have been able to learn from searching through the archives, this error is earliest from Oct 30, 2017 and it still has not been fixed!

Here's the kicker! When I run the run.bat manually from inside a cmd shell, it works perfectly!

I'm constructively disappointed that GDScript continues to be a flaming trainwreck.

Instead of crashing and burning like jet fuel through steel beams, the OS.execute should just figure out by itself what it needs to do to make the called program run properly like it's been asked to.

Calinou commented 4 years ago

I'm sad and very disappointed that GDScript continues to be a flaming trainwreck.

I have to remind you that we have a Code of Conduct. Please stay constructive.

bojidar-bg commented 4 years ago

Well, flaming or not, running a bat file as a command-line application should probably work, or if it is impossible to make it work without ugly hacks, a note in the documentation could be added telling users to use e.g. cmd.exe to run bat files.

TheDuriel commented 4 years ago

Did you try?

OS.execute("CMD.exe", ["C:/build/gateway/bin/run.bat"])

Or running Godot as admin?

aabmets commented 4 years ago

Did you try?

OS.execute("CMD.exe", ["C:/build/gateway/bin/run.bat"])

Or running Godot as admin?

Okay, I did it now, and the debug window gives the following error: 'un.bat"' is not recognized as an internal or external command, operable program or batch file.

Can someone please explain how can this result be even remotely possible?

TheDuriel commented 4 years ago

Seems like a Windows issue at that point. (Since thats not a Godot error at all.) Make sure not to escape the characters.

RevoluPowered commented 4 years ago

windows is fun, maybe this? OS.execute("CMD.exe", ["C:\\build\\gateway\\bin\\run.bat"])

aabmets commented 4 years ago

Seems like a Windows issue at that point. (Since thats not a Godot error at all.) Make sure not to escape the characters.

windows is fun, maybe this? OS.execute("CMD.exe", ["C:\\build\\gateway\\bin\\run.bat"])

I also tried OS.execute("CMD.exe", ["C:\\build\\gateway\\bin\\run.bat"]) But this does not run anything, it only produces: Microsoft Windows [Version 10.0.18363.836] (c) 2019 Microsoft Corporation. All rights reserved. as if I had not given it any parameters at all.

TheDuriel commented 4 years ago

Meaning it ran the CMD and your command just fine. Leaving the result up to Windows.

What even is this bat?

aabmets commented 4 years ago

Meaning it ran the CMD and your command just fine. Leaving the result up to Windows.

What even is this bat?

No, it did not run anything fine, as the bat is supposed to start a server on localhost, and on success it writes a confirmation log to cmdline.

aabmets commented 4 years ago

I think I figured out why it's impossible to make it work: We can't use neither / nor \ characters in OS.execute args, as Godot messes up their translation into the cmdline. For example: arg ["C:/remedy"] is interpreted by the cmdline as "C:emedy", but we can't use \ neither, because Godot needs \\ to pass a \, but in OS.execute Godot does not remove the escape char and the cmdline goes tits up when it reads \\ in an arg.

TheDuriel commented 4 years ago

use a multiline string and only escape \ once.

Also do remember that Windows does not care. And that / is valid too in most cases.

aabmets commented 4 years ago

Did you try? OS.execute("CMD.exe", ["C:/build/gateway/bin/run.bat"]) Or running Godot as admin?

Okay, I did it now, and the debug window gives the following error: 'un.bat"' is not recognized as an internal or external command, operable program or batch file.

Can someone please explain how can this result be even remotely possible?

If windows doesn't care about /-s, then how would you explain this result? So instead Godot messed up the string before it passed it to cmdline?

If it's Godots fault, then it's a bug, as Godot is supposed to pass strings to cmdline as is without any formatting.

name-here commented 4 years ago

It seems like Godot replaces backslash+character sequences in strings (ex. \t -> [TAB]), though syntax highlighting does not show this (unlike other code editors, where such sequences are shown in a different color). I think the built in editor's lack of syntax highlighting here is one of the things causing confusion.

bojidar-bg commented 4 years ago

Godot uses CreateProcessW in OS::execute. The CreateProcessW documentation has the following line when explaining the parameters of CreateProcessW:

To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file. (link)

The documentation of cmd.exe also confirms the fact that the /c flag is necessary to run the command.

As Godot does not change the executable to CMD.exe or add the /c flag in any way, it is necessary to do both manually. Like this:

OS.execute("CMD.exe", ["/c", "C:\\build\\gateway\\bin\\run.bat"])

# instead of OS.execute("C:\\build\\gateway\\bin\\run.bat")

(Note: OS.execute can also use _wpopen when blocking is set to true. I'm unable to find documentation which explains how it works with batch files, however.)

rsubtil commented 4 years ago

I didn't see this mentioned anywhere in the thread: maybe Godot is interpreting /r as a carriage-return?

bojidar-bg commented 4 years ago

@Ev1lbl0w /r could be interpreted as something else than just characters in 4 places: GDScript, OS.execute, whatever API OS.execute uses, and the executed application.

name-here commented 4 years ago

I think there may have been some confusion between backslashes and slashes in the comments above. Also, unfortunately, the Godot editor shows no indication that it is going to replace \r and the like. It seems like better syntax highlighting might avoid the 'un.bat"' confusion. Does anyone know where the syntax highlighting settings are in Godot's code?

Calinou commented 4 years ago

Does anyone know where the syntax highlighting settings are in Godot's code?

The GDScript-specific highlighting bits are in modules/gdscript/editor/gdscript_highlighter.cpp.

That said, many escape codes are common to all languages Godot supports, so we could add them to the common syntax highlighter which I think is part of editor/code_editor.cpp.

girng commented 4 years ago

Great explanation @bojidar-bg! @aspenforest did you try OS.execute("CMD.exe", ["/c", "C:\\build\\gateway\\bin\\run.bat"])?

ditikos commented 4 years ago

I don't suppose this works on windows, right? OS.execute("CMD.exe", ["/c", @"c:\build\gateway\bin\run.bat"]).

I recall having the @ in front of windows string paths would translate the path correctly in visual c#, I don't know if this is passed in cmd.exe as well, the way I wrote it. --- Ah --- probably a syntactic sugar for c#: https://docs.microsoft.com/en-us/dotnet/api/system.io.path?view=netcore-3.1

Maybe implement the program in mono/c# ? (long shot suggestion)

Anutrix commented 4 years ago

@aspenforest Now that https://github.com/godotengine/godot/issues/38803 is fixed by https://github.com/godotengine/godot/pull/38856, can you test again?

ghost commented 2 years ago

This is still an issue btw in latest 3.x branch. Seems on Windows you need special magical Windoze way to run things:

OS.execute("powershell", ["code"], false) or this OS.execute("CMD.exe", ["\C", "code"], false