EmptyString static object's memory address comparison leads to wrong conclusion

Ill try to describe the problem I run into in here using a simplistic example.
I’m working on Juce huckleberry 5.2.1 and Visual Studio 2015.
I have built a Juce static library with the following modules.

  1. juce_core
  2. juce_cryptography
  3. juce_data_structures
  4. juce_events

I’m using this library in a Win32 dll (no MFC or anything, as simple as it gets)
My code is the following:

simpleApi.h:
#define SIMPLEAPI_API __declspec(dllexport)
#include “juceheader.h”
class SIMPLEAPI_API someApi
{
public:
String writehere;
};

simpleApi.cpp doesnt really matter, the “writehere” string is never used inside the dll.

I subsequently create a Win32 console application that uses my API. All it will do is to attempt to write something to the “writehere” string.

#include “stdafx.h”
#include
#include “simpleApi.h”
using namespace std;

int main()
{
someApi obj;
obj.writehere = “1”; <<This will crash
return 0;
}

As soon as I try to write to the “writehere” string I get a write access violation to the following line:

Juce_String.cpp line 166:

static inline void release (StringHolder* const b) noexcept
{
    if (b != (StringHolder*) &emptyString)
        if (--(b->refCount) == -1) << the crash happens here.
            delete[] reinterpret_cast<char*> (b);
}

Analyzing a bit the problem reveals that the comparison in the line right above will lead to wrong conclusion. In fact StringHolder “b” is empty, its content is equal to static object “emptyString”
But the memory addresses aren’t. This is because the dll has its own static “emptyString” object with a different memory address than the one in the console application.

Indeed, after doing some tests i confirmed that “b” 's memory address is the one of the dll’s “emptyString” static object but “emptyString” has the memory address of the static object of the console application. I assume that somewhere in the code “b” was “emptied” by pointing it to the dll’s “emptyString” static object.

The result is that the code continues inside the if block and subsequently crashes at the very next line since the memory address of “b” is invalid.

If I’m not wrong somewhere, this looks like to be a bug.

Some further insight can be found in the link below:

"Quoting from MSDN:

Variables that are declared as global in a DLL source code file are treated as global variables by the compiler and linker, but each process that loads a given DLL gets its own copy of that DLL’s global variables. The scope of static variables is limited to the block in which the static variables are declared. As a result, each process has its own instance of the DLL global and static variables by default."

"…So, the key issue here is really visibility.

In all cases, static global variables (or functions) are never visible from outside a module (dll/so or executable). The C++ standard requires that these have internal linkage, meaning that they are not visible outside the translation unit (which becomes an object file) in which they are defined. So, that settles that issue."

1 Like

I’m not sure, but I’m surprised you don’t use setter and getter ?
something like that:

class SIMPLEAPI_API someApi
{
string getStr()
{
return writehere;
}
void setStr (const String& str)
{
writehere = str;
}

public:
String writehere;
};