1

Preface:

this question is closely related to these ones: ...
- C++: Avoiding Static Initialization Order Problems and Race Conditions Simultaneously
- How to detect where a block of memory was allocated?
... but they have NO positive solution and my actual target use-case is slightly different.

During construction of the object I need to know if it is initialized in static memory bock ( BSS) or is it instantiated in Heap.

The reasons are follow:

  • Object by itself is designed to be initialized to "all zeros" in constructor - therefore no initialization is needed if object is statically initialized - entire block with all objects is already set to zeros when program is loaded.

  • Static instances of the object can be used by other statically allocated objects and alter some member variables of the object

  • Order of initialization of static variables is not pre-determined - i.e. my target object can be invoked before its constructor is invoked, thus altering some of its data, and constructor can be invoked later according to some unknown order of initialization of statics thus clearing already altered data. That is why I'd like to disable code in constructor for statically allocated objects.

  • Note: in some scenarios Object is the subject for severe multi-threaded access (it has some InterlockedIncrement/Decrement logic), and it has to be completely initialized before any thread can touch it - what i can guaranteed if i explicitly allocate it in Heep, but not in static area (but i need it for static objects too).

Sample piece of code to illustrate the case:

struct MyObject
{
    long counter;

    MyObject() {
        if( !isStaticallyAllocated() ) {
            counter = 0;
        }
    }
    void startSomething() { InterlockedIncrement(&counter); }
    void endSomething() { InterlockedDecrement(&counter); }
};

At the moment I'm trying to check if 'this' pointer in some predefined range, but this does not work reliably.

LONG_PTR STATIC_START = 0x00400000;
LONG_PTR STATIC_END   = 0x02000000;
bool isStatic = (((LONG_PTR)this >= STATIC_START) && (LONG_PTR)this < STATIC_END));

Update: sample use-case where explicit new operator is not applicable. Code is 'pseudo code', just to illustrate the use-case.

struct SyncObject() {
    long counter;
    SyncObject() { 
        if( !isStaticallyAllocated() ) {
            counter = 0;
        } }
    void enter() { while( counter > 0 ) sleep(); counter++; }
    void leave() { counter--; }
}

template <class TEnum>
struct ConstWrapper {
    SyncObject syncObj;
    TEnum m_value;

    operator TEnum() const { return m_value; }
    LPCTSTR getName() {
        syncObj.enter();
        if( !initialized ) {
            loadNames();
            intialized = true;
        }
        syncObj.leave();
        return names[m_value];
    }
}

ConstWrapper<MyEnum> MyEnumValue1(MyEnum::Value1); 
Community
  • 1
  • 1
Xtra Coder
  • 3,389
  • 4
  • 40
  • 59

4 Answers4

1

You can probably achieve this by overwriting the new operator for your class. In your customized new, you can set a "magic byte" within the allocated memory, which you can later check for. This will not permit distinguishing stack from heap, but statically from dynamically allocated objects, which might be sufficient. Note, however, that in the following case

class A {
};

class B {
   A a;
};

//...

B* b = new B;

b.a will be considered statically allocated with the proposed method.

Edit: A cleaner, but more complicated solution is probably a further customization of new, where you can keep track of dynamically allocated memory blocks.

Second edit: If you just want to forbid static allocation, why don't you just make the constructor private and add a factory function to the class dynamically creating the object and delivering the pointer?

class A {
private:
    A () { ... }
public:
    static A* Create () { return new A; }
};
JohnB
  • 13,315
  • 4
  • 38
  • 65
  • +1: it was iffy until I got to the second edit, which is really the simplest way to manage this. I'd hide the copy-constructor as well unless you can think of a good reason not to. – WhozCraig Oct 26 '12 at 06:58
  • This is an awkward solution. Requiring a replacement of global new for the program logic to work is never a good idea: it will lead to conflicts in the long term. (What happens if two different libraries require different replacements? What happens if you want to use a debugging `operator new`?) – James Kanze Oct 26 '12 at 07:43
  • Well, it may be awkward, but I would consider a program logic requiring an object's knowledge about whether it lives on the stack or on the heap awkward as well. – JohnB Oct 26 '12 at 08:25
  • Unfortunately explicit creation of the objects is not always possible or, better to say, far from being usable/helpful. I have updated question with additional sample. Shortly - 'my object' is used for thread synchronization and if it is created on the fly :) i need another sync object to lock access to this pointer, implementation of what will bring me to original problem :( – Xtra Coder Oct 26 '12 at 21:22
  • I do not see the point. Why do you need to set `counter = 0` only in case the object resides on the stack? If you need two different types of objects with different behaviour, why don't you simply create two classes? Common functionality can be achieved by deriving from a base class, for example. – JohnB Oct 27 '12 at 07:54
0

I think that the best way for you to control this is to create a factory for your class. That way you have complete control of how your objects are created instead of making complicated guesses over what memory is used.

AndersK
  • 35,813
  • 6
  • 60
  • 86
0

The first answer is: not portably, and it may not be possible at all on some platforms. Under Solaris (and I think Linux as well), there is an implicitly defined global symbol end, comparison of arbitrary addresses works, and if this < &end (after the appropriate conversions), the variable is static, at least as long as no dynamic loading is involved. But this is far from general. (And it definitely fails anytime dynamic linking is involved, regardless of the platform.)

The solution I've used in the past was to make the distinction manually. Basically, I designed the class so that the normal constructor did the same thing as zero initialization, and I then provided a special no-op constructor for use with static objects:

class MayBeStatic
{
public:
    enum ForStatic { isStatic };
    MayBeStatic() { /* equivalent of zero initialization */ };
    MayBeStatic( ForStatic ) { /* do absolutely nothing! */ };
    //  ...
};

When defining an instance with static lifetime, you use the second constructor:

MayBeStatic object( MayBeStatic::isStatic );

I don't think that this is guaranteed by the standard; I think the implementation is allowed to modify the memory any way it wants before invoking the constructor, and in particular, I think it is allowed to "redo" the zero initialization immediately before invoking the constructor. None do, however, so you're probably safe in practice.

Alternatively, you can wrap all static instances in a function, so that they are local statics, and will be initialized the first time the function is called:

MayBeStatic&
getStaticInstance()
{
    static MayBeStatic theInstance;
    return theInstance;
}

Of course, you'll need a separate function for each static instance.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • This solution is actually the one i have now - the problem with it is ... (1) in case the object is created multiple times in various context (including static) it is rather possible to make a human error and miss valid parameter in constructor. In dev environment i'm rechecking it via ASSERT and it failed when i recompiled solution under VS2012 and tried it under win7 rather than WinXP. ... (2) In case object is a member variable within another sub-tree of of objects, i have to path through argument through all nested constructor (thus affecting design of other class) - which is also bad :( – Xtra Coder Oct 26 '12 at 20:19
0

It looks like after thinking for a while, I've found a workable solution to identify if block is in static area or not. Let me know, please, if there are potential pitfalls.

Designed for MS Windows, which is my target platform - by another OS I actually meant another version of MS Windows: XP -> Win7. The idea is to get address space of the loaded module (.exe or .dll) and check if block is within this address space. Code which calculates start/end of static area is put into 'lib' segment thus it should be executed before all other static objects from 'user' segment, i.e. constructor can assume that staticStart/End variables are already initialized.

#include <psapi.h>

#pragma warning(push)
#pragma warning(disable: 4073)
#pragma init_seg(compiler)
#pragma warning(pop)

HANDLE gDllHandle = (HANDLE)-1;
LONG_PTR staticStart = 0;
LONG_PTR staticEnd = 0;

struct StaticAreaLocator {
    StaticAreaLocator() {
        if( gDllHandle == (HANDLE)-1 )
            gDllHandle = GetModuleHandle(NULL);

        MODULEINFO  mi;
        GetModuleInformation(GetCurrentProcess(), (HMODULE)gDllHandle, &mi, sizeof(mi));

        staticStart = (LONG_PTR)mi.lpBaseOfDll;
        staticEnd = (LONG_PTR)mi.lpBaseOfDll + mi.SizeOfImage;

        // ASSERT will fail in DLL code if gDllHandle not initialized properly
        LONG_PTR current_address;
        #if _WIN64
            ASSERT(FALSE) // to be adopted later
        #else
            __asm {
                        call _here
                _here:  pop eax                     ; eax now holds the [EIP]
                        mov [current_address], eax
            }
        #endif
        ASSERT((staticStart <= current_address) && (current_address < staticEnd));
        atexit(cleanup);
    }

    static void cleanup();
};

StaticAreaLocator* staticAreaLocator = new StaticAreaLocator();

void StaticAreaLocator::cleanup() {
    delete staticAreaLocator;
    staticAreaLocator = NULL;
}
Xtra Coder
  • 3,389
  • 4
  • 40
  • 59