Can I pass FILE object across DLLs boundaries?
Asked Answered
H

2

6

I have a C++ framework where some calculations are delegated to (sometimes auto generated) C functions or C++ functions with external "C" linkage. These are low-level routines that must be evaluated very fast and with minimal overhead and they typically reside in separate shared objects/DLLs. Their current signature is something along the lines of:

int my_generated_function(const double* input, double* output, double* work);

which will reside in a shared library loaded using dlopen on POSIX or LoadLibrary on Windows. The corresponding function pointers are extracted using dlsym(handle, "my_generated_function") on POSIX or GetProcAddress(handle, TEXT("my_generated_function")) on Windows.

Is it safe and portable to augment the signature with a FILE object pointer?

int my_generated_function(const double* input, double* output, double* work,
                          FILE* logfile);

Note that the shared object containing my_generated_function might have been compiled with a different (but binary compatible) compiler than the code that loads the shared object.

Homerus answered 6/9, 2017 at 14:57 Comment(6)
I was not implying that when I wrote "C functions or C++ functions with external "C" linkage". I meant that the function is either pure C or C++ code. In the latter case, it has extern "C".Homerus
I'd say it would depend on the fact whether the called dll is compiled using same c-runtime as calling exe/dllIndispensable
@ArtemyVysotsky What's the implication of this? What if the code is compiled with two different versions of the same compiler or a combination of gcc and clang (which are binary compatible) for example?Homerus
@Olaf I know what it means. It means that it uses C name mangling. Try to answer the actual question.Homerus
Since a FILE * is an opaque pointer to some object or something within the runtime, this means that the DLL and the user of the DLL need to be using the same runtime. Different runtime versions could conceivably have different FILE object layouts. And the runtime in use by whatever component does the file open will need to share its tables and data with whatever other components, DLLs, that are being used. I am not sure if a DLL would load its own specific runtime that would be different from that of the using process or not.Fauch
@RichardChambers in case of /MT or /MTd - it willIndispensable
G
8

You can think of the FILE* as an opaque handle. The problem is that the actual object under this handle, in other words, the definition of the FILE structure, and its implementation details, are compiler/CRT specific.

So, to my knowledge, there's no guarantee that the FILE implementation of e.g. Visual Studio 2008 or 2010 is the same of the ones that come in VS2015 or 2017. In other words, even if the name of the structure (FILE) is the same, the implementation details may very well change from one version of the CRT to another.

So, I'd suggest to not have a FILE* at the DLL boundaries, unless you want to constrain your clients to use the same version of the VC++ compiler/CRT.

On the other hand, if you need a cross-compiler/CRT compatible handle at the DLL interface boundary, I'd suggest using the Win32 HANDLE type (the one that is returned from APIs like CreateFile). This is defined at the OS level, so it's independent from the particular VC++ compiler/CRT.

If you want to get the Win32 HANDLE from a FILE*, you can use _get_osfhandle with _fileno, as explained in this SO answer.

Gymkhana answered 6/9, 2017 at 17:58 Comment(0)
I
-1

There is a good article (Potential errors passing CRT objects across DLL boundaries) from Microsoft explaining that problem:

Each copy of the CRT library has a separate and distinct state, kept in thread local storage by your app or DLL.

CRT objects such as file handles, environment variables, and locales are only valid for the copy of the CRT in the app or DLL where these objects were allocated or set. When a DLL and its clients use different copies of the CRT library, you can't expect these CRT objects to be used correctly when passed across the DLL boundary.

Interlingua answered 3/8, 2022 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.