2

A colleague and I were having an interesting discussion about memory allocation when working with shared libraries and "where" code is actually executed.

Hint: I'm explicitly looking for answers in general terms. I know that the following points would work when using the exact same compiler and settings when building the shared library and application. I want to assume that the DLL is built using a completely different compiler than the application.

Given the following struct Foo:

struct Foo
{
    int m_FooBar = 1;

    const char* GetBar()
    {
        return m_Bar.c_str();
    }

    void SetBar(const char* value)
    {
        m_Bar = value;
    }

private:
    std::string m_Bar;
};

Assuming the shared library exposes a function Foo* GetFoo() and an external application calls it:
1.) What happens if the external application calls foo->SetBar("Hello")?
Would SetBar be executed inside the DLL and thus the memory allocation of m_Bar be safe or would the memory allocation happen inside the external application and thus lead to issues?
2.) What happens if the external application copies the instance pointed to by the returned pointer?
Judging by the many posts out there warning against passing std::string over DLL boundaries I assume that caused by potential different ABIs a default copy could cause problems. Is that correct?
3.) Would it be safe to define custom copy constructors and assignment operators that construct m_Bar by calling .c_str() on the passed instance so that those methods only rely on the API of std::string and not on the ABI?

Hope some C++ gurus can answer some of these questions and shed some light on this topic.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
TorbenJ
  • 4,462
  • 11
  • 47
  • 84
  • 1
    C++ has no standard abi, this is not supposed to work if you change compiler (or whatsoeven) – OznOg Jan 30 '19 at 20:11
  • @OznOg I know that – TorbenJ Jan 30 '19 at 20:14
  • 1
    @TorbenJ Then it seems evident that the answer depends on your platform. You should mention for which platform you are asking in the question by tagging it. Edit : Since you mention DLL, I've added the `windows` tag for you. – François Andrieux Jan 30 '19 at 20:14
  • then why "I want to assume that the DLL is built using a completely different compiler than the application." – OznOg Jan 30 '19 at 20:15
  • @FrançoisAndrieux thanks. yes I only mean different compilers on the same platform not some sort of cross platform compilation – TorbenJ Jan 30 '19 at 20:17
  • Possibly [related question](https://stackoverflow.com/questions/13625388/is-it-bad-practice-to-allocate-memory-in-a-dll-and-give-a-pointer-to-it-to-a-cli). – François Andrieux Jan 30 '19 at 20:17
  • @OznOg because there isn't just one compiler on e.g. Windows. Could be the case that I use MSVC to compile the shared library and another developer uses e.g. clang. – TorbenJ Jan 30 '19 at 20:20
  • well not sure I understand, but as far as the memory layout of things is not guarantied by any standard, objects inside the dll may not be matching anything the application would expect to call, thus may crash. Moreover, allocation may not happen in the same way (maybe the dll uses a custom memory allocator) thus passing things around should not work as well (or at least, one should not expect it to work) – OznOg Jan 30 '19 at 20:25
  • If you don't compile/link all object files and libraries for your application with the *exact same* compiler/linker then all bets are off - ABI compatibility wise. The language/standard gives you *no* guarantees. – Jesper Juhl Jan 30 '19 at 21:07
  • Well yes I know that the ABI isn't standardized in C++ and this may cause problems if one doesn't use the exact same compiler, let's tick that of the list. But the ABI part only really matters in 2.) I guess and the other two points depend more on the API. – TorbenJ Jan 30 '19 at 21:19

1 Answers1

0

1.) What happens if the external application calls foo->SetBar("Hello")? Would SetBar be executed inside the DLL and thus the memory allocation of m_Bar be safe or would the memory allocation happen inside the external application and thus lead to issues?

There are many problems, not just concerning memory allocations or mixing up C runtime libraries.

For starters, Foo may not even be the same size, std::string definition may be a completely different one, etc. etc. etc.

2.) What happens if the external application copies the instance pointed to by the returned pointer? Judging by the many posts out there warning against passing std::string over DLL boundaries I assume that caused by potential different ABIs a default copy could cause problems. Is that correct?

No need to copy to get into trouble: since you don't know anything about the memory it points to, even using the Foo you were given will break everything.

3.) Would it be safe to define custom copy constructors and assignment operators that construct m_Bar by calling .c_str() on the passed instance so that those methods only rely on the API of std::string and not on the ABI?

Your general idea of trying to go to the lowest level is good. However, trying to play with m_Bar isn't.

Instead, provide a plain C interface and optionally provide wrapper classes in a header. And even then, be careful about allocating/deallocating/using system resources if you are linking with different C runtime libraries (in Windows).

Acorn
  • 24,970
  • 5
  • 40
  • 69