This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: The "os.execl" call doesn't give programs exit code
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Amaury.Forgeot.d'Arc, amaury.forgeotdarc, brian.curtin, kayhayen, pitrou, tim.golden
Priority: normal Keywords:

Created on 2012-01-15 23:05 by kayhayen, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (7)
msg151304 - (view) Author: Kay Hayen (kayhayen) Date: 2012-01-15 23:05
Hello,

I am the author of the Python compiler Nuitka. It has the ability to immediately execute the created executable file. For that I am using "os.execl" to immediately replace the compiler and run the freshly created binary instead.

This worked well so far, but as of late, I am also checking the exit codes, and it turns out that even for failing programs, the exit code is "0" on Windows, even though the compiled binary is exiting with "1".

Investigating further, I made a simple program:

-------
import os
os.execl( "FailingProgram.exe", "lala" )
-------

And it turns out, it's giving me "0", whereas when executed directly "FailingProgram.exe" gives "1". Checking %errorlevel% manually that is, my test framework uses "subprocess" module and gets "0".

The same code works fine (preserves exit code) under Linux. I didn't find the windows specific code responsible for implementing "os.execv" under Win32. I am suspecting that somehow "cmd.exe" may not be propagating the error code, but for that to confirm I would need pointers.

Thanks in advance,
Kay
msg151305 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-01-15 23:13
Python's os.execl simply calls Windows' execv() function, which AFAIK has nothing to do with cmd.exe.
msg151325 - (view) Author: Kay Hayen (kayhayen) Date: 2012-01-16 06:08
Well, I saw that code, but expected that there must be more to it. But I found out, the bug is actually caused by at least MinGW. See below how I build a program with it, that does "execl" on an error exiting program and then the "errorlevel" variable is "0", whereas direct execution gives "1".

I don't have MSVC installed, so I cannot tell if it is affected as well. I will report this as a bug to MinGW then.

c:\Users\hayen\Nuitka>gcc -v
Es werden eingebaute Spezifikationen verwendet.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/lib/../libexec/gcc/mingw32/4.6.2/lto-wrapper.exe
Ziel: mingw32
Konfiguriert mit: ../gcc-4.6.2/configure --enable-languages=c,c++,ada,fortran,ob
jc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libg
omp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-
runtime-libs --build=mingw32 --prefix=/mingw
Thread-Modell: win32
gcc-Version 4.6.2 (GCC)

c:\Users\hayen\Nuitka>gcc exec_sample.cpp

c:\Users\hayen\Nuitka>type exec_sample.cpp

#include <unistd.h>
#include <stdio.h>


int main()
{
    puts( "Hello bad world!" );

    execl( "badprogram.exe", "badprogram", "what" );

    puts( "Look, this is not happening!" );
    return 2;
}


c:\Users\hayen\Nuitka>.\a.exe
Hello bad world!

c:\Users\hayen\Nuitka>Traceback (most recent call last):
  File "tests\syntax\RelativeNonPackageImport.py", line 20, in <module>
    from . import whatever
ValueError: Attempted relative import in non-package

c:\Users\hayen\Nuitka>echo %errorlevel%
0

c:\Users\hayen\Nuitka>.\badprogram.exe
Traceback (most recent call last):
  File "tests\syntax\RelativeNonPackageImport.py", line 20, in <module>
    from . import whatever
ValueError: Attempted relative import in non-package

c:\Users\hayen\Nuitka>echo %errorlevel%
1
msg151430 - (view) Author: Amaury Forgeot d'Arc (Amaury.Forgeot.d'Arc) * Date: 2012-01-17 07:26
immediately execute the created executable file. For that I am using
"os.execl" to immediately replace the compiler and run the freshly created
binary instead.
>
> This worked well so far, but as of late, I am also checking the exit
codes, and it turns out that even for failing programs, the exit code is
"0" on Windows, even though the compiled binary is exiting with "1".

This is expected behavior on Windows: exec does not replace the existing
process like with Unix, it creates a new process and exit(0) the caller.
msg151434 - (view) Author: Kay Hayen (kayhayen) Date: 2012-01-17 09:28
Does the Python standard library not offer anything that does replace with current process code with another? I checked with subprocess, and admittedly it's not that. Does Win32 API offer nothing for that?
msg151438 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2012-01-17 10:04
No. On Windows the only way to start a new executable is to create a new process (with the CreateProcess function, which all spawn* and exec* functions ultimately call), and this yields a new PID.
This is a fundamental difference with unix, where the only way to create a process is to clone the current one with fork().

And yes, this makes launchers more difficult to write on Windows.  For a discussion see the paragraph "Process Launching" in http://www.python.org/dev/peps/pep-0397/
msg164360 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2012-06-29 22:07
Closing as it's been pending for six months and I see nothing further to add
History
Date User Action Args
2022-04-11 14:57:25adminsetgithub: 58001
2012-06-29 22:07:55tim.goldensetstatus: pending -> closed

messages: + msg164360
stage: resolved
2012-01-17 10:04:28amaury.forgeotdarcsetstatus: open -> pending

nosy: + amaury.forgeotdarc
messages: + msg151438

resolution: not a bug
2012-01-17 09:28:40kayhayensetmessages: + msg151434
2012-01-17 07:26:41Amaury.Forgeot.d'Arcsetnosy: + Amaury.Forgeot.d'Arc
messages: + msg151430
2012-01-16 06:08:49kayhayensetmessages: + msg151325
2012-01-15 23:13:26pitrousetnosy: + tim.golden, brian.curtin, pitrou
messages: + msg151305
2012-01-15 23:05:03kayhayencreate