[PATCH] frontend: report non-seekable Windows handles to mpg123
"Maya R. Odinezenko via Lame-dev" <[email protected]> Sun, 26 Jul 2026 17:41:20 -0400
| Newsgroups | gmane.comp.audio.mp3.lame |
|---|---|
| Message-ID | <CAFCgL3nowy41bdBmt=jzLM+BDqjHDdEh_4W3usXf2nyHft_fDg@mail.gmail.com> |
Hello, MP3 data piped into the Windows frontend can be decoded incorrectly without a nonzero exit status. In native cmd.exe pipelines, the unpatched frontend produced 182,204 bytes instead of 176,400 and exited 0. The cmd.exe pipeline output matched decoding the same audio encoded without a Xing/Info frame, so encoder-delay and padding trimming were lost. Under MSYS2 bash, the same defect failed with a nonzero status instead. The Windows mpg123 FILE * bridge supplies a seek callback. mpg123_open_handle() calls get_fileinfo(), which seeks to the end and peeks at 128 bytes for ID3v1. Microsoft documents the fseek() return value as undefined on devices incapable of seeking. On the tested pipe, the call reported success, causing mpg123 to treat the pipe as seekable and consume those 128 bytes without being able to rewind. The value reported by ftell() reflects bytes buffered in the pipe rather than a stream length, so the failure mode depends on pipe occupancy. The patch checks the native handle type with GetFileType() and retains the existing fseek() path only for FILE_TYPE_DISK. Other handle types are reported non-seekable before any data is read. Pathnames and standard input redirected from a regular file remain disk handles and follow the existing path. Testing of the patched lame frontend covered macOS, Debian, Windows UCRT64, and Windows MINGW64/MSVCRT. After the patch, decoded PCM was identical for pathname, redirected regular-file standard input, and genuine-pipe routes. The patch is against trunk r6662. Yours, Maya -- >8 -- From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Maya <[email protected]> Date: Sun, 26 Jul 2026 15:33:17 -0400 Subject: [PATCH] frontend: report non-seekable Windows handles to mpg123 MP3 input from a genuine Windows pipe can silently produce incorrect decoded output. In native cmd.exe pipelines, the affected frontend produced 182,204 bytes instead of 176,400 and exited with status 0; under MSYS2 it failed with a nonzero status. The cmd.exe pipeline output matched decoding the same audio encoded without a Xing/Info frame, so encoder-delay and padding trimming had been lost. LAME's Windows FILE * reader bridge installs its seek callback with mpg123_replace_reader_handle(). mpg123_open_handle() reaches get_fileinfo(), whose first operation seeks to the end to determine the stream length and inspect ID3v1. On Windows the fseek() return value is undefined for a device that cannot seek. On a pipe it reported success, so mpg123 classified the stream as seekable, read 128 bytes for the ID3v1 check, and could not return to the beginning. The value reported by ftell() reflects bytes buffered in the pipe rather than a stream length, so the failure mode depends on pipe occupancy. Classify the native handle with GetFileType() before seeking. Keep the existing fseek() path only for FILE_TYPE_DISK and report other handles as non-seekable without reading or repositioning the stream. Ordinary pathnames and standard input redirected from a regular file are disk handles and keep the existing path. Non-Windows builds are unaffected because the added code remains within the existing _WIN32 branch. With the patch, lame produced identical decoded PCM for pathname, redirected regular-file standard input, and genuine-pipe routes on macOS, Debian, Windows UCRT64, and Windows MINGW64/MSVCRT. On Windows, the callback consumed zero bytes before recognizing the pipe as non-seekable. --- frontend/get_audio.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/get_audio.c b/frontend/get_audio.c index 16145c7..f75a170 100644 --- a/frontend/get_audio.c +++ b/frontend/get_audio.c @@ -77,8 +77,10 @@ char *strchr(), *strrchr(); # include <kernel.h> # include <sys/swis.h> #elif defined(_WIN32) +# include <io.h> # include <sys/types.h> # include <sys/stat.h> +# include <windows.h> #else # include <sys/stat.h> #endif @@ -2064,6 +2066,13 @@ static mpg123_ssize_t lame123_read_from_file(void* handle, void* buffer, size_t static off_t lame123_seek_in_file(void* handle, off_t offset, int direction) { + HANDLE const os_handle = + (HANDLE) _get_osfhandle(_fileno((FILE*) handle)); + + /* fseek() has undefined behavior for non-seeking Windows devices. */ + if (os_handle == INVALID_HANDLE_VALUE || + GetFileType(os_handle) != FILE_TYPE_DISK) + return (off_t)-1; if (fseek((FILE*)handle, offset, direction) != 0) return (off_t)-1; return ftell((FILE*)handle);