From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 313F241D45 for ; Wed, 20 Apr 2022 12:48:09 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CE8DE68B3B8; Wed, 20 Apr 2022 15:48:06 +0300 (EEST) Received: from mail8.parnet.fi (mail8.parnet.fi [77.234.108.134]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9149B68B3A8 for ; Wed, 20 Apr 2022 15:48:00 +0300 (EEST) Received: from mail9.parnet.fi (mail9.parnet.fi [77.234.108.21]) by mail8.parnet.fi with ESMTP id 23KClx7p029376-23KClx7q029376 for ; Wed, 20 Apr 2022 15:47:59 +0300 Received: from foo.martin.st (host-97-187.parnet.fi [77.234.97.187]) by mail9.parnet.fi (Postfix) with ESMTPS id B52EDA1513 for ; Wed, 20 Apr 2022 15:47:59 +0300 (EEST) Date: Wed, 20 Apr 2022 15:47:59 +0300 (EEST) From: =?ISO-8859-15?Q?Martin_Storsj=F6?= To: ffmpeg-devel@ffmpeg.org Message-ID: <3174427a-8eb7-b2c-eca4-242d8c9d32c@martin.st> MIME-Version: 1.0 X-FE-Policy-ID: 3:14:2:SYSTEM Subject: [FFmpeg-devel] av_fopen_utf8 and cross-DLL CRT object sharing issue on Windows X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: Hi, I just became aware of the av_fopen_utf8 function - which was introduced to fix path name translations on Windows - actually has a notable design flaw. Background: On Windows, a process can contain more than one C runtime (CRT); the system comes with two shared ones (UCRT and msvcrt.dll) and in MSVC builds, each DLL/EXE can have one statically linked in instead of linking against a shared library CRT (and that's actually the default configuration when building with MSVC). This means that CRT objects (file descriptors from open(), FILE* opened with fopen/fdopen) mustn't be shared across DLLs; such an object must be opened, accessed and closed within the same DLL. The issue: This was fixed for the avpriv_open() function in e743e7ae6ee7e535c4394bec6fe6650d2b0dbf65 by duplicating the file_open.c source file in all libav* libraries (in MSVC builds, and renaming avpriv_open to ff_open), so that each library gets their own copy of ff_open (which isn't exported), so that all calls to open/read/write/close are done within the same DLL. When av_fopen_utf8 was added afterwards, in 85cabf1ca98fcc502fcf5b8d6bfb6d8061c2caef, this issue wasn't taken into account - although the issue is somewhat eased by lucky coincidence. As av_fopen_utf8 is implemented in the same source file, libavutil/file_open.c, which gets duplicated in all libraries that use it, all uses of the function in other libraries (such as libavformat) actually end up using their own copy of it. (This also means that all the libav* DLLs export this function.) But for any users of the function outside of the ffmpeg libraries, this function (in libavutil, or whichever library it ends up imported from) returns a FILE* allocated by libavutil's CRT, which then can't be used with the fread/fwrite/fclose/whatever functions in the DLL/EXE that called it. One concrete example of this is that the function is used for the twopass log file in fftools/ffmpeg_opt.c. To see the issue in action, build ffmpeg with MSVC with this config: ../ffmpeg/configure --enable-shared --toolchain=msvc --prefix= Then try to do a twopass encoding with it: ffmpeg -i -an -c:v ffv1 -pass 1 -f null - ffmpeg -i -an -c:v ffv1 -pass 2 -y test-2pass.mkv The same issue would appear anywhere this function is used from libavutil built as a DLL, from a caller built with a different CRT choice (e.g. often if mixing mingw/MSVC builds, which otherwise is supported just fine). (If built with a shared CRT, i.e. configured with --extra-cflags=-MD, it does work though.) As this is a public function, we can't really do many tricks like we do within the libraries. (On the other hand, while it is a public function, it doesn't seem to be used much outside of ffmpeg, other than in ffmpeg API bindings for other languages.) I guess the only really robust solution would be to turn av_fopen_utf8 into a static inline function within the headers, essentially inlineing a copy of wchar_filename.h there, so that it expands to a call to the callers' _wfopen or similar. But that would end up polluting users' code by implicitly including windows.h everywhere, which really isn't nice to do either. Or should we just document this issue, discourage further external use of the function, and fold this function into a ffmpeg-internal inline helper like libavutil/whcar_filename.h? // Martin _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".