Can a std::string be passed by value across DLL boundries? - c++

Can a std::string be passed by value across DLL boundries between DLLs built with different version of Visual Studio?

No, because templated code is generated separately per module.
So, when your EXE instantiates a std::string and passes it to the DLL, the DLL will begin using a completely different implementation on it. The result is a total mess, but it often sorta almost works because implementations are very similar, or the mess is hard to detect because it's some kind of subtle heap corruption.
Even if they're both built with the same version of VS, it's very precarious / fragile, and I would not recommend it. Either use a C-style interface between modules (for example, COM), or just don't use a DLL.
More detailed explanation here: Creating c++ DLL without static methods
and here: How can I call a function of a C++ DLL that accepts a parameter of type stringstream from C#?

In general, you can not mix binary code built with different compilers, which includes different versions of the same compiler (and can even include the same compiler invoked with different commandline options), so the answer to what you are trying to do is a clear "No".
The reason is that different compilers might provide different implementations of std::string. For example, one implementation could have a fixed, static buffer, while another version doesn't, which already leads to different object sizes. There is a bunch of other things that can make the interfaces incompatible, like the underlying allocator, the internal representation. Some things will already fail to link, due to name mangling or different private APIs, which both protect you from doing something wrong.
Some notes:
Even if you didn't pass the object by value but by reference, the called code could have a different idea of what this objects looks like.
It also doesn't matter that the type is supplied by the compiler, even if you defined the class yourself and compiled two DLLs with different versions of the class definition you would have problems. Also, if you change your standard library implementation, you make your binaries incompatible, too.
It doesn't even matter that the other code is in a DLL, it also applies to code in the same executable or DLL, although headers and automatic recompilation on change make this case very unlikely.
Specifically for MS Windows, you also have a debug heap and a release heap, and memory allocated in one must not be returned to the other. For that reason, you often have two DLL, one with a 'd' suffix (the debug version) and one without. This is a case where the compiler settings already affect compatibility, but you can get around this using a parallel approach of providing two versions of your DLL, too.
To some degree, similar problems occur for C code, too, where compilers have to agree on e.g. struct layout and calling conventions. Due to greater age and lower complexity, different C compilers are effectively compatible though. This is also accepted as a necessary feature in C as opposed to C++.

Related

Using shared libraries and mismatched compilers

What are the chances using shared libraries that are compiled using different compiler versions than your program would introduce problems?
What if the language standard your programs use is different from their?
i.e Could it be a problem if I link boost libraries compiled with gcc-4.8,c++11 while compiling my code with gcc-6,c++14, for instance?
If the ABI (and API) is the same, it will work fine, according to gcc.gnu.org's ABI Policy and Guidelines, "given an application compiled with a given compiler ABI and library API, it will work correctly with a Standard C++ Library created with the same constraints."
A shared library compiled with a different ABI could work, but there are some cases of which to be aware because they could cause major bugs which would be incredibly difficult to detect.
gcc-4.8 and gcc-6 have different ABIs (Application Binary Interfaces), and so could output different compiled code in very specific cases, and cause an application to break.
However, "the GNU C++ compiler, g++, has a compiler command-line option to switch between various different C++ ABIs." (According to ABI Policy and Guidelines.)
You can read more details about specific ABI issues from gcc.gnu.org:
Short answer, close to 100% that you'll have some issues unless the library was designed with this in mind. Boost was not designed with this in mind at all, it will not work.
Long answer, it might work under certain very specific circumstances (not for boost though). There are 2 main things that come into play:
ABI compatibility
Sub-library compatibility / inlined code
The ABI is the easy part. If e.g. compiler A mangles names differently than compiler B, it won't even link. Or if they have different calling conventions (e.g. how arguments are passed through registers/stack etc) then it might link but it will not work at all / crash in pretty obvious manners. Also most compilers on the same platform have the same calling conventions (or can be configured appropriately) so this shouldn't be a huge problem.
Sub-library compatibility and inlined code is trickier. For example, let's say that you have a library that passes out an allocated object, and it's the client's job to deallocate. If the library's allocator works differently from the one in the client, then this will cause problems (e.g. the library uses compiler A's new, and the main program uses compiler B's delete).
Or there might be code in the headers (e.g. inline methods). The two compilers might compile them differently, which will cause issues.
Or the library might return a std::vector. The implementations of compiler A's vector might differ from compiler B's vector, so that won't work either.
Or there might be a struct or class passed around. The two compilers might not pack/pad them the same way, so they won't be laid out the same way in memory, and things will break.
So if the library is designed with this in mind, then it might work. Generally speaking that means that:
All calls have to be extern C to avoid name mangling.
No passing around of any externally defined structures (e.g. the STL)
Even structs might cause issues unless the packing/padding is the same in both compilers
Everything allocated by the library must also be deallocated by the library
No throwing of exceptions (which is sort of implied by extern C)
Probably a few more that I'm forgetting right now

DLL compatibility for different compilers

Try to don't judge me really hard for this question.
Will I have problems if I try to use a DLL (written in C++) in a Visual Studio project that was compiled with the MinGW toolchain (g++)?
If the answer is yes, could someone explain me why?
As far as code execution goes, if it targets Windows, then it should run.
For interoperability; it depends on the API exposed from the dll.
If it is a "C" style API then you should be fine.
If it is a C++ API with classes and STL use, then you may run into trouble using different compilers (even different settings in the compilers). C++ doesn't have a standard ABI.
As noted in the comments and probably worth touching on here; the "C" style API is more than just the function calls, compatibility includes (but not limited) to things such as;
Memory allocation; general rule is "deallocation must be done by the same code as the allocation" - i.e. in the dll such that the matching allocation/deallocation is used (e.g. new and delete, malloc and free, CustomAlloc and CustomDealloc)
Data alignment and packing, not all compilers have the same defaults
Calling conventions, again, not all compilers have the same defaults, when in doubt, be explicit on what that convention should be (e.g. __stdcall)
As for the C++ ABI, in addition to all of the above, incompatibilities include;
Name mangling
STL class and container implementations
Separate and different implementations of new and delete, with custom memory pooling etc.
Exception mechanisms, e.g. generation, and stack unwinding
These are not comprehensive lists, but they go some way to motivating the general advice that when possible, use the same toolchains and same compiler/linker settings.
The problem is not about DLL. It's about how you describe such DLL to your compiler (ie. header files and exports).
Those descriptions affect how your code expect on data layout (e.g. different compiler may have different default alignment and padding), or even different code path (e.g. resolve to different inline functions and macro, such as in STL case).
Then each compiler may have different name mangling scheme, you may need a bit hack to glue the codes.
With very special care on the above issues you should be fine using a DLL from different compiler.
No, because it is all one standard. And in fact your C++ application compiled with gcc calls system functions from OS dll files. So no matter if you call them manually or automatically, it is all the same.

compile application with gcc that is different from library compiled with different gcc version

I want to compile a c++ application with gcc 4.7 and this application is linked with a library which is compiled with gcc 4.4. I just want to know if there is no issue for it?
The answer is: it depends. And this isn't really compiler or system specific. It applies to Visual Studio as well for example.
Basically, there shouldn't be any issue doing such (this is a rather typical scenario).
However, the important question is, what kind of data is passed between the two binary files.
For example, if all strings are passed as char *, then everything is fine. Once you somewhere pass a std::string (or just a pointer or reference to one), then things will break in case the implementation changed between the two files (e.g. different STL implementation or just changed alignment).
The same is true for other things, even your own custom structs and classes. If the interface is carefully designed, there shouldn't be any issue. If the interface didn't consider such cases, then you might run into issues which could be very hard or next to impossible to debug (random crashes, problems with stack alignment, etc.).

Mixing binaries built with different compiler's versions

I would like to know, is calling code placed in a .dll, which was build with a different tool-chain, possible? And is using a .lib file build with an older compiler to build a code with a newer one possible?
I know, the second one is not preferable, but I would like to know, is it impossible.
Precisely my case looks like this:
I have a.exe file built with VC7.1 using b.lib file which was also built with VC7.1 . a.exe calls code from c.dll which was built also using b.dll. Now I want to write a new c.dll, but compile it with VC9. (I want to do so, as I need some libraries which do not provide support for building them with VC7.1 .) -- My c.dll also requires b.lib, still I have sources for it, thus I can recompile it.
So, is it possible to make it work? If not, can you provide a brief explanations, what exactly disallows this?
It is not entirely impossible. The chief problem is that you'll inevitably end up with two distinct copies of the runtime library. Copies that each keep their own state and use their own memory allocator. The DLL interface has to be carefully designed to avoid the possible mishaps that can cause.
Hard rules are that you can never throw an exception from the code in the DLL and catch it in the EXE. And that you cannot return a standard C++ library object like std::string from your DLL code, they have different implementations and the EXE cannot properly destroy the object since it uses a different allocator. And the more general rule, the DLL can never return a pointer to an object that needs to be released by the caller. CRT state can cause subtle problems, like errno not returning the proper error code and locale being set wrong. All and all, plenty of misery that's very hard to diagnose and even harder to fix.
The COM programming model is an example of one that's safe. It never exposes implementation, only pure abstract interfaces. No exceptions, only error codes. Objects are allocated by a factory and reference counted. And where absolutely necessary, it uses a common heap to allocate from, CoTaskMemAlloc(). Not a popular programming model but that's what it takes.

What problems can appear when using G++ compiled DLL (plugin) in VC++ compiled application?

I use and Application compiled with the Visual C++ Compiler. It can load plugins in form of a .dll. It is rather unimportant what exactly it does, fact is:
This includes calling functions from the .dll that return a pointer to an object of the Applications API, etc.
My question is, what problems may appear when the Application calls a function from the .dll, retrieves a pointer from it and works with it. For example, something that comes into my mind, is the size of a pointer. Is it different in VC++ and G++? If yes, this would probably crash the Application?
I don't want to use the Visual Studio IDE (which is unfortunately the "preferred" way to use the Applications SDK). Can I configure G++ to compile like VC++?
PS: I use MINGW GNU G++
As long as both application and DLL are compiled on the same machine, and as long as they both only use the C ABI, you should be fine.
What you can certainly not do is share any sort of C++ construct. For example, you mustn't new[] an array in the main application and let the DLL delete[] it. That's because there is no fixed C++ ABI, and thus no way in which any given compiler knows how a different compiler implements C++ data structures. This is even true for different versions of MSVC++, which are not ABI-compatible.
All C++ language features are going to be entirely incompatible, I'm afraid. Everything from the name-mangling to memory allocation to the virtual-call mechanism are going to be completely different and not interoperable. The best you can hope for is a quick, merciful crash.
If your components only use extern "C" interfaces to talk to one another, you can probably make this work, although even there, you'll need to be careful. Both C++ runtimes will have startup and shutdown code, and there's no guarantee that whichever linker you use to assemble the application will know how to include this code for the other compiler. You pretty much must link g++-compiled code with g++, for example.
If you use C++ features with only one compiler, and use that compiler's linker, then it gets that much more likely to work.
This should be OK if you know what you are doing. But there's some things to watch out for:
I'm assuming the interface between EXE and DLL is a "C" interface or something COM like where the only C++ classes exposed are through pure-virutal interfaces. It gets messier if you are exporting a concrete class through a DLL.
32-bit vs. 64bit. The 32-bit app won't load a 64-bit DLL and vice-versa. Make sure they match.
Calling convention. __cdecl vs __stdcall. Often times Visual Studio apps are compiled with flags that assuming __stdcall as the default calling convention (or the function prototype explicitly says so). So make sure that the g++ compilers generates code that matches the calling type expected by the EXE. Otherwise, the exported function might run, but the stack can get trashed on return. If you debug through a crash like this, there's a good chance the cdecl vs stdcall convention was incorrectly specified. Easy to fix.
C-Runtimes will not likely be shared between the EXE and DLL, so don't mix and match. A pointer allocated with new or malloc in the EXE should not be released with delete or free in the DLL (and vice versa). Likewise, FILE handles returned by fopen() can not be shared between EXE and DLL. You'll likely crash if any of this happens.... which leads me to my next point....
C++ header files with inline code cause enough headaches and are the source of issues I called out in #3. You'll be OK if the interface between DLL And EXE is a pure "C" interface.
Name mangling issues. If you run into issues where the function name exported doesn't match because of name mangling or because of a leading underscore, you can fix that up in a .DEF file. At least that's what I've done in the past with Visual Studio. Not sure if the equivalent exists in g++/MinGW. Example below. Learn to use "dumpbin.exe /exports" to you can validate your DLL is exporting function with the right name. Using extern "C" will also help fix this as well.
EXPORTS
FooBar=_Foobar#12
BlahBlah=??BlahBlah##QAE#XZ #236 NONAME
Those are the issues that I know of. I can't tell you much more since you didn't explain the interface between the DLL and EXE.
The size of a pointer won't vary; that is dependent on the platform and module bitness and not the compiler (32-bit vs 64-bit and so on).
What can vary is the size of basically everything else, and what will vary are templates.
Padding and alignment of structs tends to be compiler-dependent, and often settings-within-compiler dependent. There are so loose rules, like pointers typically being on a platform-bitness-boundary and bools having 3 bytes after them, but it's up to the compiler how to handle that.
Templates, particularly from the STL (which is different for each compiler) may have different members, sizes, padding, and mostly anything. The only standard part is the API, the backend is left to the STL implementation (there are some rules, but compilers can still compile templates differently). Passing templates between modules from one build is bad enough, but between different compilers it can often be fatal.
Things which aren't standardized (name mangling) or are highly specific by necessity (memory allocation) will also be incompatible. You can get around both of those issues by only destroying from the library that creates (good practice anyway) and using STL objects that take a deleter, for allocation, and exporting using undecorated names and/or the C style (extern "C") for exported methods.
I also seem to remember a catch with how the compilers handle virtual destructors in the vtable, with some small difference.
If you can manage to only pass references of your own objects, avoid externally visible templates entirely, work primarily with pointers and exported or virtual methods, you can avoid a vast majority of the issues (COM does precisely this, for compatibility with most compilers and languages). It can be a pain to write, but if you need that compatibility, it is possible.
To alleviate some, but not all, of the issues, using an alternate to the STL (like Qt's core library) will remove that particular problem. While throwing Qt into any old project is a hideous waste and will cause more bloat than the "boost ALL THE THINGS!!!" philosophy, it can be useful for decoupling the library and the compiler to a greater extent than using a stock STL can.
You can't pass C runtime objects between them. For example you can not open a FILE buffer in one and pass it to be used in the other. You can't free memory allocated on the other side.
The main problems are the function signatures and way parameters are passed to library code. I've had great difficulty getting VC++ dll's to work in gnu based compilers in the past. This was way back when VC++ always cost money and mingw was the free solution.
My experience was with DirectX API's. Slowly a subset got it's binaries modified by enthusiasts but it was never as up-to-date or reliable so after evaluating it I switched to a proper cross platform API, that was SDL.
This wikipedia article describes the different ways libraries can be compiled and linked. It is rather more in depth than I am able to summarise here.