Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#1973 _USE_32BIT_TIME_T issue.

WSL
pending
Earnie Boyd
None
Bug
fixed
Feature_in_WSL_4.0
False
2013-06-26
2013-05-16
Earnie Boyd
No

Related

Issues: #1975
Issues: #1984

Discussion

<< < 1 2 3 4 .. 9 > >> (Page 2 of 9)
  • Twylite
    Twylite
    2013-05-23

    _USE_32BIT_TIME_T is not supposed to do what you're expecting it to do. It's supposed to call MSVCRT80+ functions that use a 32-bit time_t (i.e. gmtime32), as opposed to MSVCRT80+ functions that use a 64-bit time_t (i.e. gmtime64). It's not supposed to call MSVCRT (6.x) functions (i.e. gmtime).

    Defining _USE_32BIT_TIME_T doesn't magically allow your application to link against MSVCRT (6.x). It has nothing to do with MSVCRT 6.x. It's only understood by (the headers for) MSVCRT 8.x+ and will choose between two 8.x-specific behaviours (neither of which is backwards compatible with 6.x).

    http://msdn.microsoft.com/en-us/library/0z9czt0w%28v=vs.80%29.aspx: "In Visual C++ 2005, gmtime is an inline function which evaluates to _gmtime64 and time_t is equivalent to __time64_t. If you need to force the compiler to interpret time_t as the old 32-bit time_t, you can define _USE_32BIT_TIME_T. Doing this will cause gmtime to be in-lined to _gmtime32. This is not recommended because your application may fail after January 18, 2038, and it is not allowed on 64-bit platforms."

    This is implemented (in the MSVC headers) by include/time.inl.

    To resolve this problem you HAVE to match the headers with the CRT you are linking against. That either means pointing at a different include path for the CRT, or telling the compiler (via a preprocessor define) which CRT you're linking against and modifying the headers to do the right thing.

     
  • Twylite
    Twylite
    2013-05-23

    Earnie: "The issue with TCL is that the win/tclWinPort.h file sets _USE_32BIT_TIME_T explicitly. This causes the XP user to need to add -lmsvcr80 to build the application on XP while the Vista user could build TCL and execute it without -lmsvcr80 assuming the imports for the functions are added to libmsvcrt.a."

    No, the issue is that your compiler is supplying the headers for MSVCRT 8.x (or doing some trickery to achieve the equivalent), and linking against MSVCRT 6.x. The headers for MSVCRT 6.x don't understand _USE_32BIT_TIME_T and silently ignore it, so 'gmtime' resolves to the correct function in MSVCRT.DLL.

    Looking at https://sourceforge.net/p/mingw/mingw-org-wsl/ci/master/tree/include/time.h#l159 I can see the wrong assumption that is being made on line 156: it is assumed that if _USE_32BIT_TIME_T is defined then you want to link against the xxx32() functions. If you were compiling with MSVC the distinction would be more nuanced: MSVC6 headers (for MSVCRT.DLL v6.x) don't understand _USE_32BIT_TIME_T and link against the xxx() functions; MSVC8 headers (for MSVCRT80.DLL v8.x+) link against xxx64() functions by default (if _USE_32BIT_TIME_T is not defined) or xxx32() functions is _USE_32BIT_TIME_T is defined.

    The logic you want (in time.h) is:

      #if (MSVCRT_VERSION >= 800) && defined(_USE_32BIT_TIME_T) && defined(_HAVE_32BIT_TIME_T)
        // inline functions xxx() that call xxx32() in MSVCRT80+.DLL
      #elif (MSVCRT_VERSION >= 800)
        // inline functions xxx() that call xxx64() in MSVCRT80+.DLL
      #else
        // no special handling, functions xxx() are in MSVCRT.DLL
      #endif
    

    This of course assumes that the compiler is given the correct MSVCRT_VERSION for the lib you are going to link against.

     
    Last edit: Keith Marshall 2013-05-23
  • Jan Nijtmans
    Jan Nijtmans
    2013-05-23

    The logic you want (in time.h) is:
    ...
    Or, if you assume Windows XP with 64-bit time_t by default:

    #ifndef _USE_32BIT_TIME_T
    // inline functions xxx() that call xxx64() in any MSVCRT??.DLL
    #elif (MSVCRT_VERSION >= 800)
    // inline functions xxx() that call xxx32() in MSVCRT80+.DLL
    #else
    // no special handling, functions xxx() are in MSVCRT.DLL
    #endif
    

    Then, a user who requires 95/98/ME compatibility has two
    options to get it:
    1) define _USE_32BIT_TIME_T, which gives back a 32-bit time_t
    2) set MSVCRT_VERSION to 800 and link with -lmsvcrt80
    (and distribute msvcrt80.dll with the application).
    That would work fine too, although it's not 100%
    compatible with what Microsoft does. For Tcl this
    would work fine.

     
    Last edit: Keith Marshall 2013-05-23
  • Keith Marshall
    Keith Marshall
    2013-05-23

    Guys,

    Please use correct markup, for inlined code.

    These references to MSVCR80.DLL vs. MSVCRT.DLL v6.x aren't helpful. Neither are suggestions that users should rely on MSVCR80.DLL, and redistribute it. The bottom line is that MSVCR80.DLL, AFAIK, cannot be legitimately redistributed by anyone who lacks a paid for licence for a version of Visual Studio which grants that privilege; this is a non-free burden, which MinGW.org will never impose on its users.

    MinGW GCC links, by default, against MSVCRT.DLL, (the system DLL distributed as standard with every MS-Windows operating system). End of story: this is not negotiable. The issue here is that different versions of MS-Windows distribute incompatible variants of MSVCRT.DLL. It is these incompatibilities for which Earnie is attempting to implement a satisfactory work around -- I hesitate to say solution. One thing is certain: "redistribute MSVCR80.DLL" is not, and likely never will be, any part of that work around.

     
  • Twylite
    Twylite
    2013-05-23

    Apologies for the markup; I have not yet familiarized myself with SF's updated tracker.

    I'm not suggesting that you should redistribute MSVCR80.DLL if you don't want to; just that your headers must match your DLL.

    If you are linking against MSVCRT.DLL, then your headers must correctly translate gmtime() and friends into gmtime(), and not into gmtime32(). The (unpatched) headers attempt to call gmtime32() if _USE_32BIT_TIME_T is set, and gmtime64() otherwise, which is consistent with what you must do to link against MSVCRT80.DLL. When the C source asks for 'gmtime' your headers must supply a definition that links against your chosen runtime library (right now they don't).

    The logic I suggest works in all cases: by default it will resolve to names that link against MSVCRT.DLL; but if you choose to link against MSVCR80.DLL (and define MSVCRT_VERSION to 800 or higher) that will work too.

    If you don't use this logic then all projects that can be built with both MinGW GCC and MSVC need to have special handling for _USE_32BIT_TIME_T when building with MinGW GCC (because it doesn't respect the rule that headers must match the DLL) -- this is why Jan views this as a MinGW GCC bug and not a Tcl bug.

    With regards to the legality of redistributing MSVCR80+: Microsoft makes the redist installers available for free download (search for 'vcredist_x86.exe'). MSVCR110.DLL is redistributable with your application if you have a (free) license for MSVS 2012 Express (see http://msdn.microsoft.com/en-US/vstudio/hh857605). I understand the situation for earlier MSVCR*.DLL was less clear.

     
  • Twylite
    Twylite
    2013-05-23

    @Jan: "Or, if you assume Windows XP with 64-bit time_t by default:"

    What? This is not what the Microsoft C runtime headers do (which is what MinGW GCC should be trying to emulate, since they want to link against Microsoft's runtime DLL(s)).

    Moreover there is no support for 64-bit time_t on XP unless you redistribute MSVCR80+. MSVCRT.DLL does not have xxx64() functions, so your proposed change means that every project WITHOUT _USE_32BIT_TIME_T won't link. That's a hostile approach.

     
    • Keith Marshall
      Keith Marshall
      2013-05-23

      Moreover there is no support for 64-bit time_t on XP unless you redistribute MSVCR80+. MSVCRT.DLL does not have xxx64() functions ...

      Err ... no, this is not so. On XP:

      pexports msvcrt.dll | grep time
      

      shows me that, e.g., both _time64() and time() are available; it is _time32() which is lacking -- presumably time() itself is equivalent to the _time32() of later versions.

      OTOH, on Win7, the same command shows me that all three of time(), _time32(), and _time64() are exported. Reading between the lines of MSDN, it seems likely that by the time, (no pun intended), that MSVCRT.DLL had evolved to the Win7 version, (with the change apparently occurring in Vista), time() has become a trampoline for _time64(), unless a compile time redirection to _time32() is mandated by the inclusion of a definition for _USE_32BIT_TIME_T.

      If you are linking against MSVCRT.DLL, then your headers must correctly translate gmtime() and friends into gmtime(), and not into gmtime32(). The (unpatched) headers attempt to call gmtime32() if _USE_32BIT_TIME_T is set, and gmtime64() otherwise, which is consistent with what you must do to link against MSVCRT80.DLL

      Again ... no, not entirely; it is also consistent with the requirement, AIUI, when linking against MSVCRT.DLL, on Win7 (or perhaps Vista) and later. You are correct in respect of XP, however. The issue is that the goal posts move, depending on which MS-Windows version the end user has.

      ... Jan views this as a MinGW GCC bug and not a Tcl bug.

      It's likely that Earnie hasn't got it right yet, but I'd contend that it is actually a bug in both; it will just manifest differently for the two products, depending on which version of MS-Windows the end user happens to deploy on.

       
  • Earnie Boyd
    Earnie Boyd
    2013-05-23

    It's likely that Earnie hasn't got it right yet, but I'd contend that it is actually a bug in both; it will just manifest differently for the two products, depending on which version of MS-Windows the end user happens to deploy on.

    And of greater concern are those that build with MSVCRT.DLL supporting _USE_32BIT_TIME_T's *32 functions and try to distribute to XP. That is why I consider it a TCL issue; maybe not a bug but it will be a big surprise to many projects using TCL as a library of choice. SourceNavigator comes to mind.

    I'll review the code to determine if I can do some trickery for the case of MSVCRT_VERSION < 800 and _USE_32BIT_TIME_T is defined. I think it will be beneficial to any using GCC but that will not be equivalent to what MSVC does but we're not anywhere near equivalent anyway. The best thing will be to create __mingwrt_* equivalents so that we don't have any surprises for those distributing software; maybe for 5.x series.

     
  • Twylite
    Twylite
    2013-05-23

    Let me rephrase this from the perspective of a developer using MSVC. The last MS compiler that links against MSVCRT.DLL by default is MSVC6. The C runtime headers shipped with MSVC6 have no reference to *time64() at all.

    Windows XP shipped with MSVCRT.DLL ver 7.0, which includes the time64() functions. To access them you need to use headers in the platform SDK. All platform SDKs that support Windows XP provide time64() definitions. The last platform SDK that works with MSVC6 is Feb 2003 (Win2003 SP1); all SDKs up to and including that one always use a 32-bit time_t for a 32-bit compile (and a 64-bit time_t for a 64-bit compile). So if you wanted to use a 64-bit time_t in a 32-bit app then you used __time64_t and explicitly called *time64().

    If you are building with a compiler later than MSVC6 then you will link against an MSVCRxx.DLL (xx > 70), and the C runtime headers shipped with the compiler expect that you are going to link against that DLL.

    So if I as an MSVC-based developer compile a source tree for a 32-bit app with MSVC6 (so that it will run on any XP+ PC without me redistributing an MSVCRxx.DLL) then (1) when I declare a time_t it will be 32-bit; (2) when I call localtime() it will resolve to MSVCRT.DLL:localtime; and (3) it doesn't matter whether or not _USE_32BIT_TIME_T is defined in the source.

    If I compile the same source tree as a 32-bit app with MSVC2005-2012 then (1) when I declare a time_t it will be 32-bit if _USE_32BIT_TIME_T is defined and 64-bit otherwise; (2) when I call localtime() it will resolve to MSVCRxx.DLL:localtimeyy() where yy is 32 if _USE_32BIT_TIME_T is defined and 64 otherwise; and (3) I must redistribute MSVCRxx.DLL.

    So sources with _USE_32BIT_TIME_T defined will compile and link correctly with all versions of the MSVC compiler. Sources without _USE_32BIT_TIME_T may behave differently between MSVC6 and MSVC2005+.

    So if you want to maintain source compatibility for 32-bit builds (I'm assuming that's the goal) then (A) if the source has _USE_32BIT_TIME_T then you must use a 32-bit time_t; (B) if you're linking against MSVCRT.DLL then you must call time() for a 32-bit time_t, or time64() for a 64-bit time_t -- ignore the fact that some versions of MSVCRT export time32(), these aren't prototyped in any MS header for MSVCRT.DLL (in either VC6 or the platform SDK) so they don't officially exist ; (C) if the source doesn't have _USE_32BIT_TIME_T then you need to decide on whether you're going to emulate MSVC6 or MSVC2005+ behaviour (the former assumes 32-bit time_t, the latter assumes 64-bit time_t); (D) if you want to allow the option to link against MSVCR80+ then (D.1) time_t should default to 64-bits in the absence of _USE_32BIT_TIME_T and (D.2) time() should resolve to *time32() for 32-bit time_t.

    Point (B) above assumes that newer versions of MSVCRT.DLL have time() equivalent to time32() (rather than *time64() ). This must be the case if apps built with MSVC6 run on Windows 7.

    Depending on your answer to (C), Jan's proposal (that I previously argued against) may be right, assuming similar preprocessor logic around the definition of time_t.

     
  • Twylite
    Twylite
    2013-05-23

    Earnie: "And of greater concern are those that build with MSVCRT.DLL supporting _USE_32BIT_TIME_T's *32 functions and try to distribute to XP. That is why I consider it a TCL issue"

    Is there a disconnect between who chooses the headers and who chooses the library? That is, does GCC supply the C runtime headers, and Tcl's Makefile explicitly links against 'msvcrt.lib' or something like that? Then I can characterise this as a Tcl build problem.

    But as I see it, Tcl calls e.g. localtime(). The C runtime headers offered up by MinGW GCC turn that into _localtime32(). Then GCC links against msvcrt.lib (which may not have a _localtime32). That's quite clearly a MinGW GCC issue.

     
<< < 1 2 3 4 .. 9 > >> (Page 2 of 9)