The layout of 'struct dirent' in WSL 4.0 uses the time_t type. However, the width of time_t can be either 32 bits or 64 bits, with the latter being the default in WSL 4.0.
Presumably, when the dirent functions were compiled for inclusion in the libmingwex library, the compilation used the 64-bit default definition of time_t.
This means that applications that define _USE_32BIT_TIME_T will use an incompatible definition of 'struct dirent', which will break any code that calls the dirent functions.
I attach a test program, due to Diego Casorran dcasorran@gmail.com. When compiled with _USE_32BIT_TIME_T defined, it outputs bogus information.
Issues: #2098
Issues: #2112
Issues: #2113
Issues: #2125
Issues: #2180
Here's a possible patch to fix this.
Thanks for the report, and the patch. It seems sensible for me to follow this up, alongside [#2098]. I'll take a look, later this week.
Related
Issues:
#2098I'll do this one Keith and create a point release.
Well, please don't rush in headlong, and release another screw-up. I'm not convinced that Eli's proposed patch is entirely sufficient.
After further consideration, I'm becoming more convinced that it is not. Here are some of my concerns:
time_tfields should be explicitly declared as__time64_t; whilelong longmay be equivalent, it doesn't convey the same sense of purpose.struct _wdirent.time_tfields to represent64-bitexplicit types neglects any likelihood that the particular implementations of_findfirst(),_findnext(),_wfindfirst(), and_wfindnext(), within the particular version of MSVCRT.DLL on any end user's platform, may return a32-bit time_trepresentation;dirent.calso needs to call variants of these, which guarantee to return__time64_t. A perusal of MSDN suggests that the best choice, for maximum backward compatibility (at least as far as Win98/WinNT4), would be_tfindfirst64(), (which maps as either_findfirst64()or_wfindfirst64()), and_tfindnext64(), (which maps as either_findnext64()or_wfindnext64())._tfindfirst64()and_tfindnext64(), in place of the ambiguous_tfindfirst()and_tfindnext(), then thestruct direntandstruct _wdirentdeclarations must be adapted to match explicit__finddata64_tand__wfinddata64_trespectively, in place of ambiguous_finddata_tand_wfinddata_tstruct types; this adds an additional implied requirement that the file size field must change from_fsize_t, to become auint64_tcompatible entity.io.halso requires a correction, to provide a declaration forstruct __wfinddata64_t; it is currently declared asstruct _wfinddata64_t, (missing an underscore), which according to this MSDN reference, isn't a data type known to MSVC.And yes, in performing this analysis, I've also worked up the necessary implementation; however, it is currently intermingled with my proposed solution for [#2098].
Related
Issues:
#2098I agree except that the given test case does DTRT with the applied patch. Can you separate the intermingled patch to let us have a look at what affects this issue? The decision needs to be made for 4.1 or a point release of 4.0.
This brings up a point that we need to modify anything in libmingwex that uses the dirent structure to take the size of the structure passed into parameters into consideration and perhaps break out into
*32() and *64()functions and mapped accordingly in the headers. I'm talking things like src/libcrt/tchar/dirent.c that provides us with _topendir and friends. _USE_32BIT_TIME_T is a maddening monster created by the MS mad scientists to cause damage to those who just need to use functions opendir(), readdir() and the like.It may DTRT on your box, Eli's box, and my box, but can we guarantee that it will DTRT on Joe Soap's old box, with an MSVCRT.DLL version which predates the
_USE_32_BIT_TIME_Tinsanity? I don't think we can, unless we use_find*()variants which use an unambiguous_finddata_timplementation. Of these,_findfirst64()and friends suit well, and are historically longest lived.I don't think we need to complicate it with
*32()and*64()variants; a64-bitimplementation should be sufficient for all cases.Although intermingled, the two patches don't intersect; separation wasn't particularly difficult. The section specific to this ticket is attached; notice that it does adapt
src/libcrt/tchar/dirent.c, as required to always use the__finddata64_tand__wfinddata64_tdata representations; (it also includes my corrections for__wfinddata64_tmisspelling, inio.h).Wouldn't using
_findfirst64limit the usability of libmingwex to old versions of MSVCRT.DLL, which did not have this function?According to this MSDN reference,
_findfirst64()and friends are available in all MSVCRT.DLL versions from Win98 and WinNT (which I assume means WinNT4) onwards; (the_w*()variants are on the WinNT derivatives only). I'm not too bothered about supporting anything which predates those; the use of64-bittypes for thetime_tfields will break the implementation on anything older anyway.It's your call, but I used
long longdeliberately, for the following reasons:__time64_tis a "cooked" type, it is not known to the compiler unless other headers are included.long longis built-in, so it will always DTRT.FTR: with my patch applied, and the provided
dirent_bug-2.cmodified, (to account for the increased size of thed_sizefield, and to make it easier to compare returned size values withlsoutput):and with reference data, (as shown by MSYS
ls):for the
_USE_32BIT_TIME_Tcase, I see (correct) output:and without
_USE_32BIT_TIME_T, equally correct:I will use Keith's patch to apply the fix for this issue and do a release of 4.0.4 hopefully before Monday. I will merge the fix to 4.1-dev as well; fix in 4.0-dev, merge 4.0-dev fix in master, tag master with 4.0.4 and then merge master fix to 4.1-dev.
Hmm. I'm bewildered. I don't know how I got it to compile, but yesterday it did; today it didn't. Investigating, I find a bunch more bogus references to
_wfinddata64_t, ininclude/tchar.handinclude/wchar.h; fixing those resolves the issue.Updated patch is attached.
Just wanted to let you know that I agree with Keith's solution. The only remark to the patch is the following in "dirent.c":
Why not simply search/replace all occurrences of _finddata_t in this file
with __finddata64_t (and the same for _wfinddata_t)?
Of course, I could have done so. I considered it, but decided against; there are two reasons, neither especially compelling, (but then neither is there a compelling reason to require the search and replace):--
__finddata_tand_wfinddatatare macros, so why not use that to our advantage, by ensuring that they are defined to suit our requirements? Doing so obviates any possibility, however slight, of missing any substitution.Last edit: Keith Marshall 2013-11-06
Hmm. MSDN may say this, but it appears to be untrue. Thus, as discussed in this mailing list thread, I've reimplemented
dirent.cto eliminate all references to any function in the_findfirst()/_findnext()family, using the Windows API functions,FindFirstFile()andFindNextFile()instead. I have committed this replacement implementation to thelegacybranch of themingw-wslgit repository; it will be included in the nextmingwrt-3.xrelease.As a side effect of this reimplementation, I've also eliminated all references to
_finddata_tstructures, and to anytime_tmembers within thedirentandDIRstructures. While this causes an ABI change, and is not something I do lightly, I believe it is justified in this case, because the existing structure layout is potentially ambiguous anyway, due to Microsoft's_USE_32BIT_TIME_Tinsanity; as a consequence, users must be advised to recompile all third party libraries which they use in conjunction with the newmingwrt.Additionally, in this reimplementation, I have added the prefix
__mingw_to each publicly visible function name symbol withindirent.c, (thus providing the necessary infrastructure to address issue [#2098]). All references to these functions, withinmingwrtitself, will use the prefixed name; however, I have also added separate trampoline functions, as stubs inlibmingwex.a, to ensure that user code may continue to access the implementation using the original function names.Related
Issues:
#2098