On Monday 30 December 2024 23:40:31 Pali Rohár wrote:
> On Monday 30 December 2024 18:50:57 Pali Rohár wrote:
> > On Monday 30 December 2024 15:32:16 Martin Storsjö wrote:
> > > On Thu, 12 Dec 2024, Martin Storsjö wrote:
> > > 
> > > > On Thu, 12 Dec 2024, LIU Hao wrote:
> > > > 
> > > > > 在 2024-12-12 21:17, Martin Storsjö 写道:
> > > > > > On Thu, 28 Nov 2024, Pali Rohár wrote:
> > > > > > > msvcrt.dll preinstalled as part of the Windows system provides 
> > > > > > > more
> > > > > > > functions than the original Visual C++ 6.0, but still it is
> > > > > > > compatible with
> > > > > > > the original version. So setting __MSVCRT_VERSION__ to 0x600
> > > > > > > for msvcrt.dll
> > > > > > > build is relatively sane option.
> > > > > > > 
> > > > > > > I was considering to use 0x6FF value for this case, but this
> > > > > > > would make it
> > > > > > > more complicated for applications if they need to know if they 
> > > > > > > are being
> > > > > > > compiled for msvcrt.dll library ABI. They would need to
> > > > > > > check if the macro
> > > > > > > __MSVCRT_VERSION__ is set to 0x600 (targetting the original
> > > > > > > VC++ msvcrt.dll
> > > > > > > library) or to value 0x6FFF (targettting the system msvcrt.dll 
> > > > > > > library).
> > > > > > > This looks to be additional complication as it would be
> > > > > > > needed to track all
> > > > > > > possible values for __MSVCRT_VERSION__. So using just one value 
> > > > > > > 0x600 for
> > > > > > > both cases should be enough because for system version
> > > > > > > specific version is
> > > > > > > always needed to check also _WIN32_WINNT value.
> > > > > > 
> > > > > > I think this change looks reasonable to me, but I'd like Liu
> > > > > > Hao, who suggested the 0x6FF version, to follow up here.
> > > > > 
> > > > > I'm fine with this change, too.
> > > > 
> > > > Thanks, I pushed this one now then.
> > > 
> > > It turns out that this change did cause some breakage in user projects - 
> > > see
> > > https://github.com/msys2/MINGW-packages/pull/22907.
> > > 
> > > Also see 
> > > https://codesearch.debian.net/search?q=if.*__MSVCRT_VERSION__.*0x0*%5B76%5D&literal=0&page=2
> > > - it seems that there are a number of other projects that also have
> > > conditionals relating to this, which also may run into trouble.
> > > 
> > > (E.g. with old mingw.org headers, functions like _aligned_malloc used to 
> > > be
> > > guarded within "#if __MSVCRT_VERSION__ >= 0x0700", so some projects either
> > > check __MSVCRT_VERSION__ to know whether it is available, or even try to 
> > > set
> > > __MSVCRT_VERSION__ themselves in order to opt in to using such functions,
> > > that were available in msvcrt.dll since XP.)
> > > 
> > > Not saying that this requires revisiting our decision, but it may cause 
> > > some
> > > amount of confusion and breakage in existing user code out there.
> > > 
> > > // Martin
> > 
> > That is not good. But I do not know what can be done better. If the
> > application is using #if __MSVCRT_VERSION__ >= ... and one of the
> > preprocessor branch result in broken compiled application then it is
> > obviously bug in application.
> > 
> > But I do not know what to do with it. Either we need to say that the
> > whole __MSVCRT_VERSION__ macro is now broken because it is wrongly used
> > by applications and we should rather deprecate it (by providing some
> > fixed value to let application compile) and create a new macro e.g.
> > __MSVCRT_VERSION_REAL__ which would contain the real version.
> > 
> > Or we need to say that it is application bug and do not care about it.
> > 
> > Or maybe completely remove __MSVCRT_VERSION__ macro and always provides
> > all function declarations in header files.
> > 
> > But I think that any of those options just cause new problems. This does
> > not have a sane solution at all.
> > 
> > Whatever solution is chosen, I would propose to put big warning into
> > release notes what is happening and how application code could be
> > adjusted.
> 
> I was thinking more about this problem... It looks like that most
> "problematic" SW either check or set __MSVCRT_VERSION__ macro against
> value 0x0601.
> 
> What about setting __MSVCRT_VERSION__ to value 0x0601 in configure phase
> and then in header files just do relaxed check that upper word is 0x06?
> 
>   #if (__MSVCRT_VERSION__ >> 8) == 0x06
>     ... compiling for system msvcrt.dll ...
>   #endif
> 
> So whatever 0x06?? value the application code choose, mingw-w64 header
> files would interpret it as using system msvcrt.dll.
> 
> If I'm looking correctly at this, it should also fix the problem with
> OSGeo/gdal project.
> 
> And maybe instead of 0x0601 set it in configure phase to 0x06FF what
> Liu Hao suggested?
> 
> 
> PS: Nice tool for regex searching across public git repositories is 
> sourcegraph.com:
> https://sourcegraph.com/search?q=context:global+if.*__MSVCRT_VERSION__.*0x&patternType=regexp&sm=0

To continue my investigation, I finally found the documentation from
where are those 0x0601 values coming from. In mingw32 project is this:

https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.1-trunk/tree/mingwrt/msvcrt-xref/msvcrt.def.in

 * Note that mapping of symbols is directed by __MSVCRT_VERSION__;
 * for the MSVCRT.DLL versions shipped with the various versions of
 * MS-Windows, this must be a 32-bit unsigned long value with the
 * high order 16-bits set to zero, and the low order 16-bits set
 * to the appropriate platform specific hexadecimal value:--
 *
 *   NT4                        0x0400UL
 *   Win98                      0x0410UL
 *   Win98-SE                   0x0412UL
 *   Win2K                      0x0500UL
 *   WinXP                      0x0501UL
 *   Vista                      0x0600UL
 *   Win7                       0x0601UL
 *
 * Conversely, to map symbols exported by the non-free MSVCRxx.DLL
 * variants shipped with MSVC, __MSVCRT_VERSION__ is specified with
 * its low order 20-bits set to zero, while the high order 12-bits
 * are set to identify the the DLL version of interest:--
 *
 *   MSVCR70.DLL                0x07000000UL
 *   MSVCR71.DLL                0x07100000UL
 *   MSVCR80.DLL                0x08000000UL
 *   MSVCR90.DLL                0x09000000UL
 *   MSVCR100.DLL               0x10000000UL
 *   MSVCR110.DLL               0x11000000UL
 *   MSVCR120.DLL               0x12000000UL

But it looks like that those "big" numbers are not used in the header
files of mingw32. Seems that those "big" numbers are only for the
msvcrt.def.in templating. Because in header files there are checks like
this:

  #if __MSVCRT_VERSION__ >= __MSVCR61_DLL || _WIN32_WINNT >= _WIN32_WINNT_WIN2K
  ...
  #endif

Or:

  #if __MSVCRT_VERSION__ >= __MSVCR80_DLL
  ...
  #endif

Or:

  #if __MSVCRT_VERSION__ >= __MSVCR80_DLL || _WIN32_WINNT >= _WIN32_WINNT_VISTA
  ...
  #endif

In mingw32 file include/msvcrtver.h is this content:

/* When it is intended to link an application with any one of the
 * MSVC version specific MSVCRxx.DLL libraries, rather than with the
 * OS default MSVCRT.DLL, the particular substitute MSVCRxx.DLL may
 * be specified as any one of the following...
 */
#define __MSVCR60_DLL           0x0600
#define __MSVCR61_DLL           0x0601
#define __MSVCR70_DLL           0x0700
#define __MSVCR71_DLL           0x0701
#define __MSVCR80_DLL           0x0800
#define __MSVCR90_DLL           0x0900
#define __MSVCR100_DLL          0x1000
#define __MSVCR110_DLL          0x1100
#define __MSVCR120_DLL          0x1200

#ifndef __MSVCRT_VERSION__
/* This may be set, when the intent is to link with any of the above
 * non-freely distributable MSVCRxx.DLL libraries, rather than with the
 * pseudo-free MSVCRT.DLL provided as an OS component.  High byte is the
 * major version number, low byte is the minor; however, users are advised
 * to use custom GCC specs files to set this, while also substituting the
 * appropriate library in place of MSVCRT.DLL, rather than to simply set
 * it directly.
 *
 * It should be noted that __MSVCRT_VERSION__ is NOT a good indicator of
 * evolving MSVCRT.DLL features; that is better accomplished by using the
 * NTDDI_VERSION setting from the Windows API.  Thus, users of MSVCRT.DLL
 * should NOT set __MSVCRT_VERSION__, leaving us to establish a default,
 * equivalent to MSVCR60.DLL, which seems reasonably well aligned with
 * the feature set of the earliest MSVCRT.DLL version we support.
 */
# define __MSVCRT_VERSION__  __MSVCR60_DLL
#endif


So it looks like that current mingw32 is setting 0x0600 as default value
for __MSVCRT_VERSION__.


Next, I looked into mingw-org-wsl git repo history and I found out that
in more released mingw32 versions following patterns in header files:

  /* These require msvcr70.dll or higher. */
  #if __MSVCRT_VERSION__ >= 0x0700
   _CRTIMP void * __cdecl __MINGW_NOTHROW _aligned_offset_malloc(size_t, 
size_t, size_t);
   _CRTIMP void * __cdecl __MINGW_NOTHROW _aligned_offset_realloc(void*, 
size_t, size_t, size_t);
   _CRTIMP void * __cdecl __MINGW_NOTHROW _aligned_offset_recalloc(void*, 
size_t, size_t, size_t, size_t);
  ...
  #endif

  /* This require msvcr70.dll or higher. */
  #if __MSVCRT_VERSION__ >= 0x0700
  _CRTIMP int __cdecl _set_SSE2_enable (int);
  #endif /* __MSVCRT_VERSION__ >= 0x0700 */

  #if __MSVCRT_VERSION__ >= 0x0800
  _CRTIMP int __cdecl __MINGW_NOTHROW   _utime32 (const char*, struct 
__utimbuf32*);
  _CRTIMP int __cdecl __MINGW_NOTHROW   _wutime32 (const wchar_t*, struct 
__utimbuf32*);
  _CRTIMP int __cdecl __MINGW_NOTHROW   _futime32 (int, struct __utimbuf32*);
  ...
  #endif

Also there are patterns:

  #if __MSVCRT_VERSION__ >= 0x0601
  _CRTIMP int __cdecl __MINGW_NOTHROW _wstat64 (const wchar_t*, struct 
__stat64*);
  #endif /* __MSVCRT_VERSION__ >= 0x0601 */


So it means that those "big" values 0x07000000UL were never used at all
in header file, and that values 0x0400UL-0x0601UL for system msvcrt.dll
are/were used.

Also in all older versions was __MSVCRT_VERSION__ by default set to the
0x0600 value.

With all information, it looks now clear why applications are checking
__MSVCRT_VERSION__ against 0x0601 value or are changing to higher value.
It means that they want Windows 7 APIs.

But as mingw32 used in past 0x0600 as default value, we should not have
issues with this value if we use it as default too.



What is quite problem is the interpretation of __MSVCRT_VERSION__ in
mingw-w64 header files. It is because it is interpreted differently in
mingw32 and mingw-w64.

Interpretation of __MSVCRT_VERSION__ by mingw-w64 is currently:

crtdll   - 0x000
msvcrt10 - 0x100
msvcrt20 - 0x200
msvcrt40 - 0x400
msvcrt   - 0x600
msvcr70  - 0x700
msvcr71  - 0x701
msvcr80  - 0x800
msvcr90  - 0x900
msvcr100 - 0xA00
msvcr110 - 0xB00
msvcr120 - 0xC00
ucrt     - 0xE00...0xFFF or >= 0x1400

Different meaning is for following values:

Value   mingw32 meaning     mingw-w64 meaning
------  ------------------  -----------------
0x0400  msvcrt.dll NT4      msvcrt40.dll
0x0410  msvcrt.dll Win98Fe  NONE (could be msvcrt40.dll for >= 0x0400 check)
0x0412  msvcrt.dll Win98Se  NONE (could be msvcrt40.dll for >= 0x0400 check)
0x0500  msvcrt.dll Win2K    NONE (could be msvcrt40.dll or msvcrt.dll)
0x0501  msvcrt.dll WinXP    NONE (could be msvcrt40.dll or msvcrt.dll)
0x0600  msvcrt.dll Vista    msvcrt.dll
0x0601  msvcrt.dll Win7     NONE (could be msvcrt.dll for >= 0x0600 check)
0x0A00  NONE                msvcr100.dll
0x0B00  NONE                msvcr110.dll
0x0C00  NONE                msvcr120.dll
0x1000  msvcr100.dll        NONE (could be msvcr120.dll for >= 0x0C00 check)
0x1100  msvcr110.dll        NONE (could be msvcr120.dll for >= 0x0C00 check)
0x1200  msvcr120.dll        NONE (could be msvcr120.dll for >= 0x0C00 check)



So, based on this investigation, I think that changing default value of
__MSVCRT_VERSION__ again should not be needed. I would suggest to just
adjust checks in mingw-w64 header files for:

* OS system msvcrt.dll version (any OS):
  - #if __MSVCRT_VERSION__ > 0x400 && __MSVCRT_VERSION__ < 0x700
  - This will match any mingw32 OS system msvcrt.dll version except the Windows 
NT4
  - It does not conflict with neither mingw-w64 msvcrt40 (== 0x400) nor with 
msvcr70 (== 0x700)

* Windows 7+ OS system msvcrt.dll version:
  - #if (__MSVCRT_VERSION__ >= 0x601) || (__MSVCRT_VERSION__ == 0x600 && 
_WIN32_WINNT >= _WIN32_WINNT_WIN7)
  - First part will match mingw32 Windows7+ check, second part will match 
mingw-w64 check

* msvcr100+:
  - (__MSVCRT_VERSION__ >= 0xA00 && __MSVCRT_VERSION__ < 0x1000) || 
(__MSVCRT_VERSION__ >= 0x1000)
  - First part is for mingw-w64, second for mingw32

* msvcr110+:
  - (__MSVCRT_VERSION__ >= 0xB00 && __MSVCRT_VERSION__ < 0x1000) || 
(__MSVCRT_VERSION__ >= 0x1100)
  - First part is for mingw-w64, second for mingw32

* msvcr120+:
  - (__MSVCRT_VERSION__ >= 0xC00 && __MSVCRT_VERSION__ < 0x1000) || 
(__MSVCRT_VERSION__ >= 0x1200)
  - First part is for mingw-w64, second for mingw32


Would be this enough to finally fix those issues with __MSVCRT_VERSION__?


_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to