views:

84

answers:

3

I have a cross platform library that has strange problem only on iPhone and only under release.

// .h
class cColor 
{
public:
   static const cColor Red;
   static const cColor Green;
   static const cColor Blue;

   u8 r;
   u8 g;
   u8 b;
   u8 a;

   inline cColor(...) : ... { }
};

// .cpp
const cColor cColor::Red(0xFF, 0x00, 0x00);
const cColor cColor::Green(0x00, 0xFF, 0x00);
const cColor cColor::Blue(0x00, 0x00, 0xFF);

It does look like an initialization order fiasco but the problem is not in a static method but later in the program. All cColor::Red, Green, Blue are set to 0. Actually I put some printf inside the constructor's { } and it doesn't print anything but maybe it is OK since it's during globals initialization.

Now the worst part: The library was working in Release as well till recently before I added a few functions (200-300 lines) Objective-C code that doesn't even get executed. Just by cutting from the code size I can fix the issue but that is not really option for me. Also the application is not that big, memory can't be the problem.

Btw cColor is included in precompiled header in the library and later in the application that uses the library.

Help! I'm really out of ideas.


Edited: Here is more info...

I moved only the initialization code from the library to my application and now the constants are getting initialized correctly.

I really think that the linker is messing up something.

Any ideas?

+1  A: 
LumpN
I don't think my problem is initialization fiasco rather it never gets initialized. I also know that solution and it will work in my case but it is slower then a static constant because it is checked on each call if that static var is initialized.
Aleks
@Alex: Why do you think it checks each time the code is called? You don't think the compiler writers thought about that and have already added the appropriate optimization!
Martin York
@LumpN: Why dynamically create the Color!!!! Just have a static Color object. 'static cColor red(0xFF, 0x00, 0x00);' It will correctly be created on first use and unlike your code will be correctly destroyed when the application shuts down.
Martin York
I already have looked into disassembly of x86 and arm both have branch.
Aleks
@Martin York: yes this is exactly what I want to have but it doesn't work for some strange reason. The constrictor is not called on initialization. I have the same disign for my vector classes and they work just fine. I'm starting to think it's a compiler/linker bug.
Aleks
@Aleks: That means nearly nothing on modern processors. The CPU is pipe lined and starts processing the main branch whatever the condition happens to be. If it discovers that it made the wrong prediction it just throws away the predictive processing. So in reality you are loosing very little (if anything (try and measure the difference)) and gaining in code clarity and robustness.
Martin York
A: 

I'm convinced that this is a linker bug. I just found a work around which is really stupid. I moved one inlined function from the cColor class to the cColor.cpp. I had nothing else in the cColor.cpp except the static const initialization.

My guess is that because nothing else is in the translation unit in some cases the linker decides to ignore it.

I might send this to apple to see what they think about it.

P.S. Just to make it clear my initial tought was that this is memory corruption but I don't have any static memory allocations in my library/application. Also I have tested the code with multiple memory manager with different debug functions and the code is even leaks free.

Aleks
A: 

This is a common case with static inits inside a library. Code with static initialization must be linked into the main application. A library is simply a collection of .o files, and at link time, the linker selects which .o files it wants to include into the final executable. If your main application does not reference those variables, the linker determines that the object code is unused and so the .o don't get pulled in and hence, the initializers don't initialize. A quick test is to reference them in your main exe sources (not in your library) or try the -Wl,-whole-archive or -force_load flag to gcc to force all the .o objects from your library to be included.

5ound
The variables are used in both the library and the executable. The main problem is that the issue appeard after adding objective-c code that doest get executed. And I can fix It by removing any objective-c code about 200 lines. I'll defenatly test these flags if there will be any change.
Aleks