See one inline comment below.

On Wednesday 27 November 2024 18:33:32 Pali Rohár wrote:
> Visual C++ CRT DLL libraries older than VC70 / msvcr70.dll have different
> ABI of __getmainargs() and __wgetmainargs() functions. Their return value
> is void, instead of int. This includes VC++ libs crtdll.dll, msvcrt10.dll,
> msvcrt20.dll, msvcrt40.dll, msvcr40d.dll, msvcrt.dll and msvcrtd.dll.
> 
> Same applies for OS system msvcrt.dll library for older systems than
> Windows XP.
> 
> System version of msvcrt.dll library since Windows XP has same ABI of
> __getmainargs() and __wgetmainargs() functions as Visal C++ msvcr70.dll
> library.
> 
> MinGW-w64 already provides declaration of __getmainargs() and
> __wgetmainargs() with int return value. So it is expected that these
> functions in MinGW-w64 perspective returns int and let caller to handle
> errors.
> 
> Import libraries for crtdll.dll, msvcrt10.dll and msvcrt20.dll have already
> wrappers around __getmainargs() and __wgetmainargs() which handle this kind
> of ABI incompatibility.
> 
> Add a new wrappers around __getmainargs() and __wgetmainargs() also for
> msvcrt40.dll, msvcr40d.dll and msvcrtd.dll import libraries to correctly
> return integer value 0.
> 
> For msvcrt.dll library is situation quite complicated as its ABI is not
> stable and was changed in Windows XP version. But the problem is only with
> i386 version as all AMD64 and ARM systems were released after Windows XP.
> 
> As int return value on i386 is stored in the eax register we can call this
> function from C even with wrong return value in declaration and ignoring it
> return value. This function does not touch argc/argv/envp arguments on
> error, so we can use this fact to detect failure independently of return
> value ABI. With this trick is it possible to achieve i386 implementation of
> MinGW-w64 wrappers around __getmainargs() and __wgetmainargs() which would
> work with both Visual C++ ABI and also with Window XP ABI.
> ---
>  mingw-w64-crt/Makefile.am                   | 10 +++++--
>  mingw-w64-crt/lib-common/msvcrt.def.in      |  6 ++--
>  mingw-w64-crt/lib32/msvcr40d.def.in         |  4 +--
>  mingw-w64-crt/lib32/msvcrt40.def.in         |  4 +--
>  mingw-w64-crt/lib32/msvcrtd.def.in          |  4 +--
>  mingw-w64-crt/misc/crtdll__getmainargs.c    |  4 +++
>  mingw-w64-crt/misc/msvcrt20__getmainargs.c  |  4 +++
>  mingw-w64-crt/misc/msvcrt20__wgetmainargs.c |  4 +++
>  mingw-w64-crt/misc/msvcrt40__getmainargs.c  | 19 ++++++++++++
>  mingw-w64-crt/misc/msvcrt40__wgetmainargs.c | 19 ++++++++++++
>  mingw-w64-crt/misc/msvcrt__getmainargs.c    | 32 +++++++++++++++++++++
>  mingw-w64-crt/misc/msvcrt__wgetmainargs.c   | 32 +++++++++++++++++++++
>  12 files changed, 132 insertions(+), 10 deletions(-)
>  create mode 100644 mingw-w64-crt/misc/msvcrt40__getmainargs.c
>  create mode 100644 mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
>  create mode 100644 mingw-w64-crt/misc/msvcrt__getmainargs.c
>  create mode 100644 mingw-w64-crt/misc/msvcrt__wgetmainargs.c
> 
> diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
> index 22bb117a0faf..b41411bb9797 100644
> --- a/mingw-w64-crt/Makefile.am
> +++ b/mingw-w64-crt/Makefile.am
> @@ -463,6 +463,8 @@ src_ucrtbasearm64=\
>  src_msvcrt32=\
>    $(src_msvcrt) \
>    $(src_msvcrt_add_x86) \
> +  misc/msvcrt__getmainargs.c \
> +  misc/msvcrt__wgetmainargs.c \
>    math/i386__copysignf.c \
>    misc/___mb_cur_max_func.c \
>    misc/__p__osplatform.c \
> @@ -822,14 +824,18 @@ src_msvcrt40=\
>    $(src_pre_msvcr71) \
>    $(src_pre_msvcr80) \
>    $(src_pre_msvcr100) \
> -  $(src_pre_msvcr120)
> +  $(src_pre_msvcr120) \
> +  misc/msvcrt40__getmainargs.c \
> +  misc/msvcrt40__wgetmainargs.c
>  
>  src_msvcrtd=\
>    $(src_pre_msvcr70) \
>    $(src_pre_msvcr71) \
>    $(src_pre_msvcr80) \
>    $(src_pre_msvcr100) \
> -  $(src_pre_msvcr120)
> +  $(src_pre_msvcr120) \
> +  misc/msvcrt40__getmainargs.c \
> +  misc/msvcrt40__wgetmainargs.c
>  
>  src_msvcr70=\
>    $(src_pre_msvcr71) \
> diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in 
> b/mingw-w64-crt/lib-common/msvcrt.def.in
> index feeeb1c35552..945ce61408f5 100644
> --- a/mingw-w64-crt/lib-common/msvcrt.def.in
> +++ b/mingw-w64-crt/lib-common/msvcrt.def.in
> @@ -459,7 +459,8 @@ __crtLCMapStringA
>  __dllonexit
>  __doserrno
>  __fpecode
> -__getmainargs
> +F_I386(__msvcrt_getmainargs == __getmainargs) ; pre-XP i386 msvcrt.dll's 
> __getmainargs is incompatible with mingw-w64's __getmainargs, real 
> __getmainargs provided by emu
> +F_NON_I386(__getmainargs)
>  F_X86_ANY(__initenv DATA) ; arm32 and arm64 __initenv provided by emu
>  __isascii
>  __iscsym
> @@ -507,7 +508,8 @@ __toascii
>  __unDName
>  F_X86_ANY(__unguarded_readlc_active DATA)
>  __wargv DATA
> -__wgetmainargs
> +F_I386(__msvcrt_wgetmainargs == __wgetmainargs) ; pre-XP i386 msvcrt.dll's 
> __wgetmainargs is incompatible with mingw-w64's __wgetmainargs, real 
> __wgetmainargs provided by emu
> +F_NON_I386(__wgetmainargs)
>  F_X86_ANY(__winitenv DATA) ; arm32 and arm64 __winitenv provided by emu
>  F_I386(_abnormal_termination)
>  _access
> diff --git a/mingw-w64-crt/lib32/msvcr40d.def.in 
> b/mingw-w64-crt/lib32/msvcr40d.def.in
> index 9a108cb06a6f..590400770339 100644
> --- a/mingw-w64-crt/lib32/msvcr40d.def.in
> +++ b/mingw-w64-crt/lib32/msvcr40d.def.in
> @@ -1022,7 +1022,7 @@ __STRINGTOLD
>  __dllonexit
>  __doserrno
>  __fpecode
> -__getmainargs
> +__msvcrt40_getmainargs == __getmainargs ; msvcr40d.dll's __getmainargs is 
> incompatible with mingw-w64's __getmainargs, real __getmainargs provided by 
> emu
>  __isascii
>  __iscsym
>  __iscsymf
> @@ -1063,7 +1063,7 @@ __threadhandle
>  __threadid
>  __toascii
>  __unDName
> -__wgetmainargs
> +__msvcrt40_wgetmainargs == __wgetmainargs ; msvcr40d.dll's __wgetmainargs is 
> incompatible with mingw-w64's __wgetmainargs, real __wgetmainargs provided by 
> emu
>  _abnormal_termination
>  _access
>  _adj_fdiv_m16i ; msvc symbol is without decoration but callee pop stack 
> (like stdcall @4)
> diff --git a/mingw-w64-crt/lib32/msvcrt40.def.in 
> b/mingw-w64-crt/lib32/msvcrt40.def.in
> index 88ae2bd2399f..80541502a0b6 100644
> --- a/mingw-w64-crt/lib32/msvcrt40.def.in
> +++ b/mingw-w64-crt/lib32/msvcrt40.def.in
> @@ -999,7 +999,7 @@ __STRINGTOLD
>  __dllonexit
>  __doserrno
>  __fpecode
> -__getmainargs
> +__msvcrt40_getmainargs == __getmainargs ; msvcrt40.dll's __getmainargs is 
> incompatible with mingw-w64's __getmainargs, real __getmainargs provided by 
> emu
>  __isascii
>  __iscsym
>  __iscsymf
> @@ -1037,7 +1037,7 @@ __threadhandle
>  __threadid
>  __toascii
>  __unDName
> -__wgetmainargs
> +__msvcrt40_wgetmainargs == __wgetmainargs ; msvcrt40.dll's __wgetmainargs is 
> incompatible with mingw-w64's __wgetmainargs, real __wgetmainargs provided by 
> emu
>  _abnormal_termination
>  _access
>  _adj_fdiv_m16i ; msvc symbol is without decoration but callee pop stack 
> (like stdcall @4)
> diff --git a/mingw-w64-crt/lib32/msvcrtd.def.in 
> b/mingw-w64-crt/lib32/msvcrtd.def.in
> index 4313c797a179..976374a29c3a 100644
> --- a/mingw-w64-crt/lib32/msvcrtd.def.in
> +++ b/mingw-w64-crt/lib32/msvcrtd.def.in
> @@ -165,7 +165,7 @@ __crtLCMapStringA
>  __dllonexit
>  __doserrno
>  __fpecode
> -__getmainargs
> +__msvcrt40_getmainargs == __getmainargs ; msvcrtd.dll's __getmainargs has 
> same API as msvcrt40.dll's __getmainargs, real __getmainargs provided by emu
>  __initenv DATA
>  __isascii
>  __iscsym
> @@ -216,7 +216,7 @@ __toascii
>  __unDName
>  __unguarded_readlc_active DATA
>  __wargv DATA
> -__wgetmainargs
> +__msvcrt40_wgetmainargs == __wgetmainargs ; msvcrtd.dll's __wgetmainargs has 
> same API as msvcrt40.dll's __wgetmainargs, real __wgetmainargs provided by emu
>  __winitenv DATA
>  _abnormal_termination
>  _access
> diff --git a/mingw-w64-crt/misc/crtdll__getmainargs.c 
> b/mingw-w64-crt/misc/crtdll__getmainargs.c
> index 81e37aa5555d..61401ca3f81a 100644
> --- a/mingw-w64-crt/misc/crtdll__getmainargs.c
> +++ b/mingw-w64-crt/misc/crtdll__getmainargs.c
> @@ -10,6 +10,10 @@
>  _CRTIMP void __cdecl __GetMainArgs(int *argc, char ***argv, char ***envp, 
> int expand_wildcards);
>  int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
> expand_wildcards, __UNUSED_PARAM(_startupinfo *startup_info))
>  {
> +  /*
> +   * crtdll.dll's __GetMainArgs() function terminates process on error.
> +   * If it returns back to the caller then it means that it succeeded.
> +   */
>    __GetMainArgs(argc, argv, envp, expand_wildcards);
>    return 0;
>  }
> diff --git a/mingw-w64-crt/misc/msvcrt20__getmainargs.c 
> b/mingw-w64-crt/misc/msvcrt20__getmainargs.c
> index 3162a20ab359..7a119297d646 100644
> --- a/mingw-w64-crt/misc/msvcrt20__getmainargs.c
> +++ b/mingw-w64-crt/misc/msvcrt20__getmainargs.c
> @@ -10,6 +10,10 @@
>  _CRTIMP void __cdecl __msvcrt20_getmainargs(int *argc, char ***argv, char 
> ***envp, int expand_wildcards, int newmode);
>  int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
>  {
> +  /*
> +   * msvcrt20.dll's __getmainargs() function terminates process on error.
> +   * If it returns back to the caller then it means that it succeeded.
> +   */
>    __msvcrt20_getmainargs(argc, argv, envp, expand_wildcards, 
> startup_info->newmode);
>    return 0;
>  }
> diff --git a/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c 
> b/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
> index c8338bb0aca0..7a8207295f81 100644
> --- a/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
> +++ b/mingw-w64-crt/misc/msvcrt20__wgetmainargs.c
> @@ -10,6 +10,10 @@
>  _CRTIMP void __cdecl __msvcrt20_wgetmainargs(int *argc, wchar_t ***argv, 
> wchar_t ***envp, int expand_wildcards, int newmode);
>  int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
>  {
> +  /*
> +   * msvcrt20.dll's __wgetmainargs() function terminates process on error.
> +   * If it returns back to the caller then it means that it succeeded.
> +   */
>    __msvcrt20_wgetmainargs(argc, argv, envp, expand_wildcards, 
> startup_info->newmode);
>    return 0;
>  }
> diff --git a/mingw-w64-crt/misc/msvcrt40__getmainargs.c 
> b/mingw-w64-crt/misc/msvcrt40__getmainargs.c
> new file mode 100644
> index 000000000000..541db331c6ed
> --- /dev/null
> +++ b/mingw-w64-crt/misc/msvcrt40__getmainargs.c
> @@ -0,0 +1,19 @@
> +/**
> + * This file has no copyright assigned and is placed in the Public Domain.
> + * This file is part of the mingw-w64 runtime package.
> + * No warranty is given; refer to the file DISCLAIMER.PD within this package.
> + */
> +
> +#include <internal.h>
> +
> +/* Define __getmainargs() function via msvcrt40.dll __getmainargs() function 
> */
> +_CRTIMP void __cdecl __msvcrt40_getmainargs(int *argc, char ***argv, char 
> ***envp, int expand_wildcards, _startupinfo *startup_info);
> +int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
> +{
> +  /*
> +   * msvcrt40.dll's __getmainargs() function terminates process on error.
> +   * If it returns back to the caller then it means that it succeeded.
> +   */
> +  __msvcrt40_getmainargs(argc, argv, envp, expand_wildcards, startup_info);
> +  return 0;
> +}
> diff --git a/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c 
> b/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
> new file mode 100644
> index 000000000000..631b87b03fa8
> --- /dev/null
> +++ b/mingw-w64-crt/misc/msvcrt40__wgetmainargs.c
> @@ -0,0 +1,19 @@
> +/**
> + * This file has no copyright assigned and is placed in the Public Domain.
> + * This file is part of the mingw-w64 runtime package.
> + * No warranty is given; refer to the file DISCLAIMER.PD within this package.
> + */
> +
> +#include <internal.h>
> +
> +/* Define __wgetmainargs() function via msvcrt40.dll __wgetmainargs() 
> function */
> +_CRTIMP void __cdecl __msvcrt40_wgetmainargs(int *argc, wchar_t ***argv, 
> wchar_t ***envp, int expand_wildcards, _startupinfo *startup_info);
> +int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
> +{
> +  /*
> +   * msvcrt40.dll's __wgetmainargs() function terminates process on error.
> +   * If it returns back to the caller then it means that it succeeded.
> +   */
> +  __msvcrt40_wgetmainargs(argc, argv, envp, expand_wildcards, startup_info);
> +  return 0;
> +}
> diff --git a/mingw-w64-crt/misc/msvcrt__getmainargs.c 
> b/mingw-w64-crt/misc/msvcrt__getmainargs.c
> new file mode 100644
> index 000000000000..95c301f1fa54
> --- /dev/null
> +++ b/mingw-w64-crt/misc/msvcrt__getmainargs.c
> @@ -0,0 +1,32 @@
> +/**
> + * This file has no copyright assigned and is placed in the Public Domain.
> + * This file is part of the mingw-w64 runtime package.
> + * No warranty is given; refer to the file DISCLAIMER.PD within this package.
> + */
> +
> +#include <internal.h>
> +
> +/* Define __getmainargs() function via msvcrt.dll __getmainargs() function */
> +_CRTIMP int __cdecl __msvcrt_getmainargs(int *argc, char ***argv, char 
> ***envp, int expand_wildcards, _startupinfo *startup_info);
> +int __cdecl __getmainargs(int *argc, char ***argv, char ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
> +{
> +  /*
> +   * ABI of msvcrt.dll __getmainargs() function was changed in Windows XP.
> +   * In Windows 2000 and older versions of msvcrt.dll, including the original
> +   * Visual C++ 6.0 msvcrt.dll version, __getmainargs() has void return value
> +   * and it terminate process on failure. Since Windows XP this function has
> +   * int return value and returns -1 on failure. It is up to the caller to
> +   * terminate process. As int return value on i386 is stored in the eax
> +   * register we can call this function from C even with wrong return value 
> in
> +   * declaration and ignoring it return value. This function does not touch
> +   * argc/argv/envp arguments on error, so we can use this fact to detect
> +   * failure independently of return value ABI.
> +   */
> +  *argc = -1;
> +  *argv = NULL;
> +  *envp = NULL;
> +  (void)__msvcrt_getmainargs(argc, argv, envp, expand_wildcards, 
> startup_info);
> +  if (*argc == -1 || *argv == NULL || *envp == NULL)
> +    return -1;
> +  return 0;
> +}
> diff --git a/mingw-w64-crt/misc/msvcrt__wgetmainargs.c 
> b/mingw-w64-crt/misc/msvcrt__wgetmainargs.c
> new file mode 100644
> index 000000000000..35e9d596f933
> --- /dev/null
> +++ b/mingw-w64-crt/misc/msvcrt__wgetmainargs.c
> @@ -0,0 +1,32 @@
> +/**
> + * This file has no copyright assigned and is placed in the Public Domain.
> + * This file is part of the mingw-w64 runtime package.
> + * No warranty is given; refer to the file DISCLAIMER.PD within this package.
> + */
> +
> +#include <internal.h>
> +
> +/* Define __wgetmainargs() function via msvcrt.dll __wgetmainargs() function 
> */
> +_CRTIMP void __cdecl __msvcrt_wgetmainargs(int *argc, wchar_t ***argv, 
> wchar_t ***envp, int expand_wildcards, _startupinfo *startup_info);

           ^^^^
           int

For consistency between __msvcrt_wgetmainargs and __msvcrt_getmainargs
functions, the __msvcrt_wgetmainargs should be declared with "int"
return value too.

I spotted this inconsistency just now.

> +int __cdecl __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***envp, int 
> expand_wildcards, _startupinfo *startup_info)
> +{
> +  /*
> +   * ABI of msvcrt.dll __wgetmainargs() function was changed in Windows XP.
> +   * In Windows 2000 and older versions of msvcrt.dll, including the original
> +   * Visual C++ 6.0 msvcrt.dll version, __wgetmainargs() has void return 
> value
> +   * and it terminate process on failure. Since Windows XP this function has
> +   * int return value and returns -1 on failure. It is up to the caller to
> +   * terminate process. As int return value on i386 is stored in the eax
> +   * register we can call this function from C even with wrong return value 
> in
> +   * declaration and ignoring it return value. This function does not touch
> +   * argc/argv/envp arguments on error, so we can use this fact to detect
> +   * failure independently of return value ABI.
> +   */
> +  *argc = -1;
> +  *argv = NULL;
> +  *envp = NULL;
> +  (void)__msvcrt_wgetmainargs(argc, argv, envp, expand_wildcards, 
> startup_info);
> +  if (*argc == -1 || *argv == NULL || *envp == NULL)
> +    return -1;
> +  return 0;
> +}
> -- 
> 2.20.1
> 


_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to