Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

One interesting bug with cast's.

4.90/5 (19 votes)
7 Oct 2012CPOL2 min read 24.9K  
I have faced with one rather interesting bug which was related to a wrong usage of casts. It is a great pleasure for me to share the results of the research.

Introduction

I have faced with one rather interesting bug which was related to a wrong usage of casts. It is a great pleasure for me to share the results of the research. So the details are below. (For more details please take a look at my other article

Bug description 

In one of the projects I was involved we had a class "C" derived from two classes "A" and "B".

C++
class  A
{ 
public:
    void funcA1();
    void funcA2();
private:
    int field1; 
};

class  B 
{  
public: 
    void funcB1();
    void funcB2();
private: 
    int field1;  
};

class  C : public A, public B 
{  
public: 
    void funcC1();
    void funcC2();
private: 
    int field1;  
};

We had a vector of pointers on C class and a function to find the index of a given pointer.

C++
B* ptr = reinterpret_cast<B*>(cPointer);
int index = FindIndex(vectorOfCPointers, ptr);  

Inside of  FindIndex function we had a following code: 

C++
... 
for (size_t i = 0; i < ptrVector.size(); ++i)
{
    if (ptr == static_cast<B*>(ptrVector.at(i)))
        return i; 
}  
return -1; 
...

The result of this function was always -1, so it was look like that there is no object even if it was there.

Fix 

I think that it's easy to understand how to fix this bug. We should just change reinterpret_cast outside the function onto static_cast. We will get a different pointer values with a different casts. For example if  cPtr is equal to 0x11223344 as a result of casts we will get a following values:  

static_cast<B*>(cPtr)  will be  0x11223348

reinterpret_cast<B*>(cPtr) will be  0x11223344

Explanation

Let's find out why did it happened. First of all we should know that object without virtual functions is represented in memory like a simple structure. It has all its fields placed in memory with the same order like they were declared in a class definition. For example if we have a class like this:

C++
class SomeClass
{
    int a;
    int b;
    int c; 
};  

And we have a pointer "ptr" on the object of that class. We can have a direct access to class fields like this.

C++
int * aPtr = (int*)ptr; 
int* bPtr = ((int*)ptr ) + 1; 
int* cPtr = ((int*)bptr) + 1;    

So what will happened in a case of multiple inheritance? For example we have our classes A, B, and C. Class C in memory will look like a sequence of classes A, B and C. And the pointer to the C class will point the sequence of fields of A class, fields of B class and finally fields of C class.

 cPtr   ->Class A members 

Class B members 

Class C members

So what should happen if we want to cast cPtr to the bPtr? Right, we should add the size of A members to cPtr, so we will get bPtr points on the B class.

Class A members 
bPtr  -> Class B members 
Class C members 
 As we can see static_cast did that transformation but reinterpret_cast did not.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)