Keith Marshall
keith****@users*****
Tue Apr 17 19:38:46 JST 2018
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I've no idea why, but for some reason the following was never delivered to me; I discovered it in, and am reproducing it in its entirety from, the on-line archive. On 12/04/18 08:23, Ray Satiro wrote: > I did a search and found that it was addressed [1] and the solution > was at one point _lseeki64: > > __int64 _fseeki64( FILE *stream, __int64 offset, int whence ) { > return _lseeki64( _fileno( stream ), offset, whence ); } > > My problem with that is it's blind to the FILE buffering. Strictly. it's the other way around: the buffering within the FILE's __iob structure isn't aware of the lseek() activity, which occurs at a lower level behind its back, and so may leave the __iob pointers in a state which is inconsistent with the lower level stream pointer. > Assume FILE *f opened rb with contents "abcdef": > > printf("%c\n", fgetc(f)); printf("%c\n", fgetc(f)); _lseeki64( > _fileno( f ), 4, SEEK_SET); printf("%c\n", fgetc(f)); > > The third fgetc call is going to get the third character 'c' and > not the fifth 'e'. Indeed, yes; the stream pointer has been relocated to the 'e', but the __iob pointers still refer to stale data, within the __iob buffer, and thus indicate that next available character is the 'c'. > If I put an fflush after the lseek I will get the fifth character, The fflush() call invalidates the __iob buffer, so forcing the next read to load fresh data, from the relocated lower level stream pointer position. I might be inclined to place the fflush() *before* the call to lseek(); however... > but according to msdn fflush is documented to not do that and > explicitly retain the FILE buffer for files opened for just read > [2]. ...the Microsoft documentation has changed, since the WinXP era; contrast your [2] with the corresponding 2012 vintage equivalent: https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/9yky46tz(v=vs.90) Notice that the earlier documentation *does* explicitly state that a call to fflush() on an input stream clears the (__iob) buffer, and so the next read DTRT. That should, thus, deliver the desired behaviour, and indeed, does appear to do so on WinXP -- reasonably so, because we would expect WinXP's MSVCRT.DLL implementation to behave as specified in the earlier documentation. That's all well and good; however, if the behaviour in later MSVCRT.DLL versions changed, in line with the newer documentation, then we can no longer trust fflush() to DTRT, for any application built with an expectation for working consistently across evolving Windows version boundaries. It may be worth noting that, according to the ISO-C standards, the use of fflush() on input streams results in undefined behaviour; Microsoft may offer implementation-defined behaviour, in this case, but to rely on it is prejudicial to portability, and in any case, we (apparently) cannot rely on consistent implementation-defined behaviour, spanning Windows versions. A possibly more robust implementation of _fseeki64(), suitable for use on any Windows version prior to Vista, may be: __CRT_ALIAS __int64 _fseeki64 ( FILE *__file, __int64 __pos, int __whence ) { fseek( __file, 0, SEEK_CUR ); return _lseeki64( _fileno(__file), __pos, __whence ); } (i.e. using 32-bit fseek(), rather than fflush(), to invalidate the __iob buffer, before the _lseeki64() call). That should get around any possibility of undefined behaviour, resulting from the use of fflush() on an input stream. It should also be suitable for use regardless of Windows version, although it may be preferable to use the MSVCRT.DLL implementation where it exists, (i.e. on Vista and later). > I am thinking about using fseeko64 and ftello64. That looks ok > except for ftello64 I might need fflush needed prior to call on > write streams [3][4]. Are there any downsides / bugs in the o64 > functions? Yes. It follows from the above that the need to call fflush(), (and it is needed for fseeko64(), but I don't think it is for ftello64() as it is currently implemented), may result in undefined behaviour when fseeko64() is called on an input stream. > How are you guys handling 64-bit offsets in FILE when building a > program for >=XP ? Don't you mean <=XP? It's not something I've given much thought to, (although, perhaps I should). The inline _fseeki64() implementation I've proposed above certainly DTRT, on WinXP, at least for the scenario you've described. I'm wondering if it may be advisable to replace our existing ftello64() and fseeko64() implementations with something similar (untested): __CRT_ALIAS __off64_t ftello64( FILE *__file ) { fseek( __file, 0, SEEK_CUR ); return (__off64_t)_telli64( _fileno(__file) ); } __CRT_ALIAS __off64_t fseeko64 ( FILE *__file, __off64_t __pos, int __whence ) { fseek( __file, 0, SEEK_CUR ); return (__off64_t)_lseeki64 ( _fileno(__file), (__int64)__pos, __whence ); } > Thanks > > [1]: https://sourceforge.net/p/mingw/bugs/2021/ [2]: > https://msdn.microsoft.com/en-us/library/9yky46tz.aspx#Anchor_2 > [3]: > http://mingw.5.n7.nabble.com/ftello64-returning-wrong-values-td1097.html > > > [4]: https://cboard.cprogramming.com/windows-programming/68331-fseek-vs-fseeko64;-whats-difference.html - -- Regards, Keith. Public key available from keys.gnupg.net Key fingerprint: C19E C018 1547 DE50 E1D4 8F53 C0AD 36C6 347E 5A3F -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.20 (GNU/Linux) iQIcBAEBAgAGBQJa1c61AAoJEMCtNsY0flo/n8UQAISxXVBzNmFDUFV1+91Gf0qP iBrM2R98xMTrDCJIMkkZFBzeWjMUWFFMMzdxUpw7Gpv519VjM9lkx0jNktAhtsDh S//YM/QyMmeky/eugKKt8yNFdxfHtStjQlVMtv0LSqXKrpX9p8twCBQTX12f5hKv wSMACL+1qHnDRQsn8PAsyQK6kukL1beETAqGhporVWXXE6q6cy5obc1KZsKsMpu1 iZmznHG7BTWLswrtwfhOevnXuiG4QxMCzAj6+vZJnyClkme6ayOotq1GyEIIgFM0 lCnxilfYLluxaZIcG0SEadNaKvOn0nO003YgEAnJB+LGbnU56TOskDAgZW7xc+7O P5SluLMpa0rrjInqkeAB57DCAbdRq1B4DVrGKqCqOrHvx94vX9qf5QawSGdFMK5T eX1FMml6hgSKOcAwYDzk5fcY1hO9u1h3ZtKPfUjkRSWpavUjlefVEqZ1M1oXykg5 FKF5Cw+X/YnK1lRAbNmgvIZfS3bqpPGyOf47yYB7Qv44Sx6mIzKB9DL8DVZWx3I8 34kOli82O6XPYfp3YBu69ZHc7K9mnOl9xURyMG3Nzwko4DZa9AKPsfiH++Anwutp DxrT0j+4V4D4cGuULABh3b9lg66Sakxix5goX00z5hDID7+JTr/a8//hpm+1eEz+ DXJR13zn60jHXQYyIiPH =ra8T -----END PGP SIGNATURE-----