Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

#1973 _USE_32BIT_TIME_T issue.

WSL
pending
Earnie Boyd
None
Bug
fixed
Feature_in_WSL_4.0
False
2014-12-14
2013-05-16
Earnie Boyd
No

Related

Issues: #1975
Issues: #1984

Discussion

<< < 1 2 3 4 > >> (Page 2 of 4)
  • Earnie Boyd
    Earnie Boyd
    2013-05-28

    Assuming when MSVCRT_VERSION < 800 that the time functions without the decorated number of bits indicator is what the decorated *32 became, I can create decorated inline functions to call the undecorated version. Then _USE_32BIT_TIME_T would not care about the MSVCRT_VERSION value.

    However, the current 4.0-dev branch does now build and effectively executes the test target on XP. I tried to set up a VM of ME to give it a go but that OS is too stubborn to use. Well, at least mingw-get update causes a library load failure not finding libexec/mingw-get/mingw-get-0.dll. I'm guessing it doesn't like the / versus .

     
  • Earnie Boyd
    Earnie Boyd
    2013-05-28

    How about something like the following for time.h? I checked ME and the *64 versions exist except for those identified below but those don't exist on XP either. What this does is allow the *32 functions to exist regardless of which version.

    --- HEAD
    +++ Modified In Working Tree
    @@ -61,7 +61,7 @@
     #endif
    
     #ifndef _TIME_T_DEFINED
    -# if defined(_USE_32BIT_TIME_T) && MSVCRT_VERSION >= 800
    +# if defined(_USE_32BIT_TIME_T)
        typedef __time32_t time_t;
     # else
        typedef __time64_t time_t;
    @@ -153,6 +153,32 @@
     _CRTIMP char*     __cdecl __MINGW_NOTHROW  _ctime32    (const __time32_t*);
     _CRTIMP struct tm* __cdecl __MINGW_NOTHROW _gmtime32   (const __time32_t*);
     _CRTIMP struct tm* __cdecl __MINGW_NOTHROW _localtime32(const __time32_t*);
    +#else
    +_CRTALIAS __time32_t __cdecl __MINGW_NOTHROW _time32  (__time32_t *_v) {
    +    _CRTIMP __time32_t __cdecl __MINGW_NOTHROW time(__time32_t*);
    +    return (time(_v));
    +}
    +_CRTALIAS double __cdecl __MINGW_NOTHROW _difftime32 (__time32_t _v1, __time32_t _v2) {
    +    _CRTIMP double __cdecl __MINGW_NOTHROW difftime(__time32_t, __time32_t);
    +    return (difftime(_v1, _v2));
    +}
    +_CRTALIAS __time32_t __cdecl __MINGW_NOTHROW _mktime32(struct tm* _v1) {
    +    _CRTIMP __time32_t __cdecl __MINGW_NOTHROW mktime(struct tm*);
    +    return (mktime(_v1));
    +}
    +_CRTALIAS char* __cdecl __MINGW_NOTHROW _ctime32(const __time32_t* _v1) {
    +    _CRTIMP char* __cdecl __MINGW_NOTHROW ctime(const __time32_t*);
    +    return (ctime(_v1));
    +}
    +_CRTALIAS struct tm* __cdecl __MINGW_NOTHROW _gmtime32(const __time32_t* _v1) {
    +    _CRTIMP struct tm* __cdecl __MINGW_NOTHROW gmtime(const __time32_t*);
    +    return (gmtime(_v1));
    +}
    +_CRTALIAS struct tm* __cdecl __MINGW_NOTHROW _localtime32(const __time32_t* _v1) {
    +    _CRTIMP struct tm* __cdecl __MINGW_NOTHROW localtime(const __time32_t*);
    +    return (localtime(_v1));
    +}
    +#endif
    
     #if defined(_USE_32BIT_TIME_T)
     _CRTALIAS time_t      __cdecl __MINGW_NOTHROW  time (time_t* _v)
    @@ -171,14 +197,17 @@
         { return(_localtime32 (_v)); }
    
     #else
    -_CRTALIAS time_t      __cdecl __MINGW_NOTHROW  time (time_t* _v)
    -    { return(_time64 (_v)); }
    +/* _difftime64 and _mkgmtime64 are missing from MSVCRT.DLL pre Vista. */
    +#if MSVCRT_VERSION >= 800
     _CRTALIAS double      __cdecl __MINGW_NOTHROW  difftime(time_t _v1, time_t _v2)
         { return(_difftime64 (_v1,_v2)); }
    -_CRTALIAS time_t      __cdecl __MINGW_NOTHROW  mktime (struct tm* _v)
    -    { return(_mktime64 (_v)); }
     _CRTALIAS time_t      __cdecl __MINGW_NOTHROW  _mkgmtime (struct tm* _v)
         { return(_mkgmtime64 (_v)); }
    +#endif
    +_CRTALIAS time_t      __cdecl __MINGW_NOTHROW  time (time_t* _v)
    +    { return(_time64 (_v)); }
    +_CRTALIAS time_t      __cdecl __MINGW_NOTHROW  mktime (struct tm* _v)
    +    { return(_mktime64 (_v)); }
     _CRTALIAS char*           __cdecl __MINGW_NOTHROW  ctime (const time_t* _v)
         { return(_ctime64 (_v)); }
     _CRTALIAS struct tm*   __cdecl __MINGW_NOTHROW gmtime (const time_t* _v)
    @@ -187,15 +216,6 @@
         { return(_localtime64 (_v)); }
     #endif /* _USE_32BIT_TIME_T */
    
    -#else /* MSVCRT_VERSION < 800 */
    -_CRTIMP time_t     __cdecl __MINGW_NOTHROW time       (time_t*);
    -_CRTIMP double     __cdecl __MINGW_NOTHROW difftime   (time_t, time_t);
    -_CRTIMP time_t     __cdecl __MINGW_NOTHROW mktime     (struct tm*);
    -_CRTIMP char*      __cdecl __MINGW_NOTHROW ctime      (const time_t*);
    -_CRTIMP struct tm* __cdecl __MINGW_NOTHROW gmtime     (const time_t*);
    -_CRTIMP struct tm* __cdecl __MINGW_NOTHROW localtime  (const time_t*);
    -#endif /* MSVCRT_VERSION >= 800 */
    -
     /*
      * _daylight: non zero if daylight savings time is used.
      * _timezone: difference in seconds between GMT and local time.
    
     
    Last edit: Earnie Boyd 2013-05-29
  • Twylite
    Twylite
    2013-05-29

    Earnie, that looks like it will work. time_t is always 32-bit with _USE_32BIT_TIME_T is defined, and always 64-bit otherwise (consistent with MSVC 2005+ - good). I see nothing wrong with the approach of providing inline xxx32() functions in cases where they are not in the DLL (i.e. MSVCRT_VERSION < 800).

     
    • Earnie Boyd
      Earnie Boyd
      2013-05-29

      Thanks Twylite. I've attached a diff for review. I've not tested yet.

      The bastard stat functions are not within MSVCRT.DLL except for those defining 64 bit regardless of the OS. Please do a careful look at the io.h changes.

       
      Last edit: Earnie Boyd 2013-05-29
  • Jan Nijtmans
    Jan Nijtmans
    2013-05-30

    Hi Earnie. Thanks for the patch. I'm OK with using inline's as well.
    Here (mingw3.patch) are some fixes for problems I saw.

     
    Attachments
  • Jan Nijtmans
    Jan Nijtmans
    2013-05-30

    Here is also a little test program (statdemo.c), which is tested
    and works fine with VS2012. If that file compiles and runs
    fine with mingw, with and without _USE_32BIT_TIME_T, then
    I'm a happy man. The lines in the "#if 0" section don't work yet.

     
    Attachments
  • Earnie Boyd
    Earnie Boyd
    2013-05-30

    Thank you for the test file Jan. I've attached the patch to the current 4.0-dev branch. I've tested with __NO_INLINE__ enabled as well as _USE_32BIT_TIME_T.

     
    • Earnie Boyd
      Earnie Boyd
      2013-05-30

      I missed some errors in wchar.h. I'll get those by tomorrow.

       
  • Earnie Boyd
    Earnie Boyd
    2013-06-04

    I pushed changes to the 4.0-dev branch. See [f908a8] for the history.

    I've tested with _USE_32BIT_TIME_T defined. Now I need to test with it undefined but wanted to get the changes pushed before I go on vacation. I had trouble because I had introduced a circular interdependency of functions which caused a never ending loop.

     

    Related

    Commit: [f908a8]

  • Jan Nijtmans
    Jan Nijtmans
    2013-06-05

    Hi Earnie,

    \<time.h> is almost correct now, just 2 typos and an endless loop when _USE_32BIT_TIME_T is defined. \<sys/stat.h> still has a few more problems, but here is a patch which corrects all of them. With this patch, those two header files are 100% correct: My "statdemo.c" fully compiles and runs now, as long as <wchar.h> is not included. The only lines from "statdemo.c" that don't work are the xxx_s() functions, but those were introduced in
    MSVCRT version 800, so it's not supposed to work in mingw with MSVCRT_VERSON = 710.

    Header file \<wchar.h> is still to be done.

    Thanks!

     
    Last edit: Jan Nijtmans 2013-06-05
    Attachments
  • Earnie Boyd
    Earnie Boyd
    2013-06-05

    Jan, why are you changing the __CRT_INLINE to _CRTALIAS and removing the __NO_INLINE__ guard in stat.h?

    In my mind, one line of code returning the value of another function is an alias. If there is more than that we need to keep the __NO_INLINE__ guard and the __CRT_INLINE declaration.

     
    Last edit: Earnie Boyd 2013-06-05
  • Jan Nijtmans
    Jan Nijtmans
    2013-06-06

    Jan, why are you changing the __CRT_INLINE to _CRTALIAS and removing the __NO_INLINE__ >guard in stat.h?

    Regarding _CRTALIAS, you know much better than me what the correct options should be. I only tried to force those to be inlined, if that's wrong then I apologize, please correct it then.

    Regarding __NO_INLINE__, I think that the inline functions are required
    when MSVCRT_VERSION<800 and the _CRTIMP functions otherwise. So, all
    occurrences of __NO_INLINE__ should be replaced by MSVCRT_VERSION>=800,
    that's what I basicall did.

    Regards,
    Jan Nijtmans

    EDIT: I added \ to each _ to escape it so that the markdown would ignore it.

     
    Last edit: Earnie Boyd 2013-06-06
    • Earnie Boyd
      Earnie Boyd
      2013-06-06

      I was thinking about this. If we create and use __CRT_MAYBE_INLINE which will be defined to either inline or empty depending on __NO_INLINE__ we can overcome this. This will have the benefit of allowing the code to be inlined during optimization and not inlined without optimization. _CRTALIAS should only be used for a one line returned call to another function so I have objections to making the changes removing __NO_INLINE__ in the current implementation. What do others think?

      #ifndef __NO_INLINE__
      #define __CRT_MAYBE_INLINE __CRT_INLINE
      #else
      #define __CRT_MAYBE_INLINE
      #endif
      
       
      Last edit: Earnie Boyd 2013-06-06
  • Jan Nijtmans
    Jan Nijtmans
    2013-06-06

    I'm fully OK with that.

     
  • Keith Marshall
    Keith Marshall
    2013-06-06

    Should the work you've been doing here propagate through utime.h? This fragment from mingw'get's archive extraction code

    #include <utime.h>
    
    static int commit_saved_entity( const char *pathname, time_t mtime )
    {
      /* Helper to set the access and modification times for a file,
       * after extraction from an archive, to match the specified "mtime";
       * (typically "mtime" is as recorded within the archive).
       */
      struct utimbuf timestamp;
    
      timestamp.actime = timestamp.modtime = mtime;
      return utime( pathname, &timestamp );
    }
    

    isn't recording valid file times on my 32-bit Win7 VM (MSVCRT.DLL v7.0.7601.17744), with headers as of WSL 4.0-dev HEAD at 22:57 GMT+1 on 2013-06-05.

     
    • Earnie Boyd
      Earnie Boyd
      2013-06-06

      You probably should use _utime() instead of utime(). The utime() function is imported from MSVCRT.DLL always (#ifndef _NO_OLDNAMES) while _utime() will change based on _USE_32BIT_TIME_T and MSVCRT_VERSION >= 800. Using utime() requires that you also define _USE_32BIT_TIME_T since utime() requires 32bit time structures and the default is 64bit time structures.

      (Using utimbuf structure will change signature based on _USE_32BIT_TIME_T since time_t is based on it. Therefore you do not need to change to _utimbuf, those two are actually the same. However utimbuf is not defined when _NO_OLDNAMES is defined.)

      The utime.h file was also wrong. Change will be uploaded soon.

       
      • Keith Marshall
        Keith Marshall
        2013-06-06

        Well, I never define _NO_OLDNAMES, because that just breaks portable standards conformance. Neither will I define _USE_32BIT_TIME_T, because I'm actually decoding the tarball timestamps, (from a 12 character ASCII representation of an octal time_t value), into a uint64_t which is then cast to a time_t for use, via the struct utimbuf fields, in the utime() call.

        The issue for mingw-get is not so much what is the size of time_t, as what size does the runtime implementation on the end user's system expect in the fields of struct utimbuf, when its particular version of utime() is invoked. If we could assume that MSVCRT.DLL's struct utimbuf always uses 32-bit time_t fields, regardless of version, then mingw-get could cast its 64-bit time_t value into the fields of a struct __utimbuf32, then cast a pointer to that as a pointer to a struct utimbuf in the utime() call, but I don't know if that is a safe assumption for all versions of MSVCRT.DLL which might exist on every system on which any end user might attempt to run a binary distribution of mingw-get.

        I really don't see how this shambolic sizeof(time_t) issue, which Microsoft have foist on us, can be adequately resolved at compile time. For mingw-get, I prefer a solution based on a run-time probe for _utime64(), which I will use if it is available; if not, I think it should then be safe to assume that struct utimbuf is congruent with struct __utimbuf32, and call utime() accordingly.

         
        • Earnie Boyd
          Earnie Boyd
          2013-06-06

          The issue for mingw-get is not so much what is the size of time_t, as what size does the runtime implementation on the end user's system expect in the fields of struct utimbuf, when its particular version of utime() is invoked.

          1. utime() will always be 32bit time_t data structures regardless of the OS and regardless of _USE_32BIT_TIME_T. The issue is that time_t changes depending on _USE_32BIT_TIME_T so if you use utime() you must define _USE_32BIT_TIME_T.

            • Should we ``#define utime _utime'' and remove the import declaration?
          2. _utime() will either be 32bit or 64bit time_t data structures depending on _USE_32BIT_TIME_T, however, if _utime() is imported from MSVCRT.DLL then it will always be 32bit time_t data structures.

          3. _utime32() does not exist in all MSVCRT.DLL but this exercise has caused the MinGW runtime to create _CRTALIAS based on the imported _utime() structure when MSVCRT_VERSION < 800.

          4. _utime64() exists in all OSes at least back to ME; I checked it on a VM of it.

          Given the above and given your requirement, I suggest you use __utimbuf64 and _utime64().

           
          • Keith Marshall
            Keith Marshall
            2013-06-06

            utime() will always be 32bit time_t data structures regardless of the OS and regardless of _USE_32BIT_TIME_T.

            Is that true for MSVCR80.DLL and later too, or just for MSVCRT.DLL? Is it 100% certain for all MSVCRT.DLL versions?

            The issue is that time_t changes depending on _USE_32BIT_TIME_T so if you use utime() you must define _USE_32BIT_TIME_T.

            Not as I've coded my fallback strategy -- see below.

            Should we ``#define utime _utime'' and remove the import declaration?

            I think it may be better to not do so, if...

            _utime() will either be 32bit or 64bit time_t data structures depending on _USE_32BIT_TIME_T, however, if _utime() is imported from MSVCRT.DLL then it will always be 32bit time_t data structures.

            ...this is the case; it seems better to me, if we have one function with a dependable data structure, irrespective of the heuristic Microsoft bullshit -- _USE_32BIT_TIME_T is a typically bad Microsoft kludge.

            _utime32() does not exist in all MSVCRT.DLL but this exercise has caused the MinGW runtime to create _CRTALIAS based on the imported _utime() structure when MSVCRT_VERSION < 800.

            But that's a compile time assumption, with absolutely no guarantee of validity for any end user system on which a distributed binary may be expected to run.

            _utime64() exists in all OSes at least back to ME; I checked it on a VM of it.

            Okay. What about Win2K? Win98? Unlikely for Win95. I no longer have test hosts for any of these, (nor installation media to create a VM), and there may be other issues which render them unsupportable anyway, but I'd like to make the best effort to keep them supported.

            Given the above and given your requirement, I suggest you use __utimbuf64 and _utime64().

            That's exactly what I' doing now, subject to a run-time probe to ensure that it really is available, (and hence to set boolean variable have_utime64_api accordingly); if that fails, I'll fall back to:

              if( have_utime64_api )
              {
                struct __utimbuf64 timestamp;
            
                timestamp.actime = timestamp.modtime = mtime;
                return _utime64( pathname, &timestamp );
              }
              else
              {
                struct __utimbuf32 timestamp;
            
                timestamp.actime = timestamp.modtime = mtime;
                return utime( pathname, (utimbuf *)(&timestamp) );
              }
            

            Which does work, (tested on VMs of Win7 32-bit and XP with no service packs), but of course both of these have _utime64(), so the fall back code remains untested.

             
            • Earnie Boyd
              Earnie Boyd
              2013-06-07

              if( have_utime64_api )

              Should always evaluate true unless maybe on Win95.

              BTW, mingw-get doesn't work on ME, it refuses to load the DLL from libexec because of / versus \.

               
  • Jan Nijtmans
    Jan Nijtmans
    2013-06-06

    I can imagine the problem with utime. In \<sys/utime.h> line 67:
    _CRTIMP int cdecl MINGW_NOTHROW utime (const char, struct utimbuf);
    This maps directly to the "utime" funcion in the dll, which assumes
    a 32-bit time_t, but all other wsl headers assume a 64-bit time_t

    Somewhere a macro (or inline function) mapping utime to _utime64 is missing.

     
  • Earnie Boyd
    Earnie Boyd
    2013-06-06

    The _USE_32BIT_TIME_T has never propagated to utime.h. I'll fix it for the next round of pushes. I'll create the _[fw]utime32() _CRTALIAS as well since of course any OS before Vista will not contain them.

     
    Last edit: Earnie Boyd 2013-06-06
  • Earnie Boyd
    Earnie Boyd
    2013-06-06

    Should we ``#define utime _utime'' and remove the import declaration?

    I'm actually tempted to do this. I thought about it once already and hesitated saying to myself that we shouldn't.

     
  • Jan Nijtmans
    Jan Nijtmans
    2013-06-07

    2013/6/7 Keith Marshall keithmarshall@users.sf.net:

    Should we ``#define utime _utime'' and remove the import declaration?

    No, we should do exactly the same as what Microsoft does in it's
    utime.h: utime should be a static inline function (_CRTALIAS)
    calling either _utime32 or _utime64 depending on _USE_32BIT_TIME_T.
    When MSVCRT_VERSION<800, _utime32 in turn should be an
    inline function calling the _utime() implementation from the dll.

    Okay. What about Win2K? Win98? Unlikely for Win95. I no longer have test
    hosts for any of these, (nor installation media to create a VM), and there
    may be other issues which render them unsupportable anyway, but I'd like to
    make the best effort to keep them supported.

    Anyone still using WinME or earlier? I would suggest for wsl-4.0 to abandon
    support for every Windows versions earlier than XP. It's already difficult
    enough the way it is now.

    Regards,
    Jan Nijtmans

     
    • Keith Marshall
      Keith Marshall
      2013-06-07

      Should we ``#define utime _utime'' and remove the import declaration?

      No, we should do exactly the same as what Microsoft does in it's
      utime.h: ...

      I don't know what Microsoft do in their utime.h; nor will I taint myself by even trying to look at it.

      I happen to agree, on this particular point, but in general, just because it's what Microsoft do, doesn't make it best practice for MinGW; Microsoft have a proven track record for some truly appalling software engineering.

      Anyone still using WinME or earlier?

      Yes. It's probably a diminishing user base, but we do occasionally see a whinge to the effect of "please don't abandon those of us who still use Win95". While I agree that it is becoming increasingly difficult, I still try to maintain the utmost backward compatibility practicable; (FWIW, although I don't use it much today, I still have one box running MS-DOS-6.22 and Windows-3.1 -- and I did boot it up as recently as a week or two ago -- and even one still running MS-DOS-2.11 -- although I haven't used that for a long time).

      My principal point here, however, is that, when you are distributing pre-compiled binaries -- as MinGW.org does -- you cannot realistically resolve this at compile time; you need a run-time probe to verify that your compile-time assumptions are valid for the particular version of MSVCRT.DLL which is actually available on the end user's box.

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