I have a very peculiar situation here ... I have inherited some old C++ code (pre-C++11) which is long, complex and half of it is written with C and the other half with C-with-classes mentality (ie: classes with more data members, not too many class methods, direct manipulation of data member... definitely this project needs some refactoring, that's what I'm working on right now). But the code exposes some issues I find puzzling.
For the beginning let's take the following very simple (error free) situation:
#include <iostream>
static int c = 0;
struct Bar
{
Bar() : base_id(++c) { std::cout << "Bar "<< base_id << std::endl;}
int base_id;
};
struct Foo : public Bar
{
Foo() : x(c) { std::cout << "Foo "<< x << std::endl;}
int x;
};
int main()
{
Bar* b = new Foo[200];
Foo *p;
for(p = (Foo*)b; p - (Foo*)b < 200; p ++ )
{
std::cout << p->base_id << " " << ((Foo*)p)->x
<< " p-b=" << (unsigned)(p-(Foo*)b) << std::endl;
}
delete[] b;
}
or text version: we create an array of base class objects via a new Derived
. So far so good, this is what the large complex application does (there the classes are more hierarchical and the constructors does more), but the global static variable (c
) is present also in the large complex application, it uses it as unique object identifiers. Then large complex application begins to work, etc....
Then at some point in time we iterate through the array of objects, doing some work. The iteration looks exactly the same as the one I wrote here, found in a for
loop, with exhaustive pointer arithmetic. My example here just prints the object id (m
) in the large complex application more stuff is done.
But somewhere in the large complex application some magic happens ... At some time after the half of the list the objects (obtained via the p
pointer) are not valid anymore, their base_id
s are showing data which to me pretty much looks like pointers and other data members's values. However if I check the array members at the specific index, the value there is valid (ie: correctly increasing object IDs).
I also checked the followings:
- There seems to be no memory corruption issue. Valgrind and Clang's memory sanitizer show no obious things.
- All the objects are properly created and destroyed, no memory leaks.
- The only place where this craziness happens is in this loop above
So ... I came to one conclusion:
- someone somewhere modifies some array values to actually point to different type of object (all of them are derived from
Bar
(e... some differently named base class) so possibly I'll need to dig more in the code to find this. But this is a huge codebase, there are literally thousands of references for that array and before that I'd like to ask:
(And here comes the question:)
I am not aware that a C++ object can change its size during runtime (if it is possible, please share it with us), so beside of the possible issue I have identified might anyone in the community have any ideas why that pointer arithmetics behaves so strangely?
(yes, the project will be converted to proper c++11 with standard containers, etc ... but for now I am just interested in this specific issue)