http://bugs.winehq.org/show_bug.cgi?id=40200 Rodrigo Batista de Moraes <rodrigobatsmoraes@hotmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |rodrigobatsmoraes@hotmail.c | |om --- Comment #5 from Rodrigo Batista de Moraes <rodrigobatsmoraes@hotmail.com> --- I ran into a problem with `ftell()` when using unbuffered streams in `msvcrt.dll` under Wine. I don't know whether this is what the original reporter encountered, but below is the problem I found, along with a test program that reproduces it. I can create another bug report for it if anyone prefers that. I found this bug while trying to get a Windows build of libfst (GTKWave's FST waveform format parser) to run under Wine. The diagnostics and reproduction below were found by an agentic AI. On a stream made unbuffered with `setvbuf(f, NULL, _IONBF, 0)`, after an `fgetc()`, the stream position reported by `ftell()`, `_ftelli64()` and `fgetpos()` is one byte too far. The position used by `fseek(..., SEEK_CUR)` is off in the same way, so `fseek(f, 0, SEEK_CUR)` followed by `fgetc()` skips a byte. With the default buffering (no `setvbuf()` call), all of them are correct. Seen with wine-11.18 (Arch Linux package), in a new 64-bit prefix, with a program linked against `msvcrt.dll`. Test program, `ftell_ionbf.c`: ```c #include <stdio.h> int main(void) { FILE *f; #ifdef _WIN32 fpos_t pos; #endif int i, c; f = fopen("ftell_ionbf.bin", "wb"); for (i = 0; i < 64; i++) fputc(i, f); fclose(f); f = fopen("ftell_ionbf.bin", "rb"); setvbuf(f, NULL, _IONBF, 0); fseek(f, 32, SEEK_SET); c = fgetc(f); printf("fgetc returned %d\n", c); printf("ftell = %ld\n", ftell(f)); #ifdef _WIN32 /* fpos_t is a plain integer on Windows but a struct in glibc */ fgetpos(f, &pos); printf("_ftelli64 = %lld\n", (long long)_ftelli64(f)); printf("fgetpos = %lld\n", (long long)pos); #endif fseek(f, 0, SEEK_CUR); c = fgetc(f); printf("fgetc after fseek(f, 0, SEEK_CUR) = %d\n", c); fclose(f); return 0; } ``` Steps: 1. Build it with a MinGW-w64 cross-compiler that targets `msvcrt.dll`, e.g.: ```sh x86_64-w64-mingw32-gcc -o ftell_ionbf.exe ftell_ionbf.c ``` (I built it with llvm-mingw 20261006, msvcrt variant: `x86_64-w64-mingw32-clang -o ftell_ionbf.exe ftell_ionbf.c`. `objdump -p ftell_ionbf.exe | grep 'DLL Name'` lists `msvcrt.dll` and `KERNEL32.dll`.) 2. Run it in a new prefix, from the directory holding the `.exe` (it writes a 64-byte file, `ftell_ionbf.bin`, into the current directory): ```sh export WINEPREFIX=$(mktemp -d)/prefix wine ftell_ionbf.exe ``` Output under Wine: ```text fgetc returned 32 ftell = 34 _ftelli64 = 34 fgetpos = 34 fgetc after fseek(f, 0, SEEK_CUR) = 34 ``` The same program built natively on Linux: ```text fgetc returned 32 ftell = 33 fgetc after fseek(f, 0, SEEK_CUR) = 33 ``` Removing the `setvbuf()` line gives 33 everywhere under Wine, so the problem is specific to unbuffered streams. It looks as though `fgetc()` on an unbuffered stream reads ahead into the `FILE`'s internal one-character buffer, and the position calculation does not subtract the character remaining in it. I don't have a Windows machine to test this on, but the project where I found this bug has a Windows CI build, and the output there is the same as on Linux. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.