Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / C++

One interesting bug with cast's.

Rate me:
Please Sign up or sign in to vote.
4.90/5 (19 votes)
7 Oct 2012CPOL2 min read 23.2K   8   16
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)


Written By
Software Developer (Senior) Oracle
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 2 Pin
Wolfgang_Baron8-Oct-12 9:09
professionalWolfgang_Baron8-Oct-12 9:09 
Questionstatic_cast and reinterpret_cast Pin
ftai7-Oct-12 21:31
ftai7-Oct-12 21:31 
QuestionMaybe a good tip Pin
Paulo Zemek7-Oct-12 3:37
mvaPaulo Zemek7-Oct-12 3:37 
GeneralMy vote of 3 Pin
Stefan_Lang2-Oct-12 5:52
Stefan_Lang2-Oct-12 5:52 
GeneralRe: My vote of 3 Pin
ykachanov3-Oct-12 16:24
ykachanov3-Oct-12 16:24 
GeneralRe: My vote of 3 Pin
Stefan_Lang3-Oct-12 22:35
Stefan_Lang3-Oct-12 22:35 
QuestionMy vote of 5 Pin
Guyverthree2-Oct-12 3:34
Guyverthree2-Oct-12 3:34 
AnswerRe: My vote of 5 Pin
Sergey Vystoropskiy2-Oct-12 4:44
Sergey Vystoropskiy2-Oct-12 4:44 
GeneralMy vote of 3 Pin
User 32413791-Oct-12 9:48
User 32413791-Oct-12 9:48 
GeneralRe: My vote of 3 Pin
Sergey Vystoropskiy1-Oct-12 10:06
Sergey Vystoropskiy1-Oct-12 10:06 
GeneralMy vote of 5 Pin
kanalbrummer1-Oct-12 4:17
kanalbrummer1-Oct-12 4:17 
GeneralRe: My vote of 5 Pin
Sergey Vystoropskiy1-Oct-12 4:41
Sergey Vystoropskiy1-Oct-12 4:41 
SuggestionThis is by design Pin
Johann Anhofer30-Sep-12 23:45
Johann Anhofer30-Sep-12 23:45 
GeneralRe: This is by design Pin
Sergey Vystoropskiy1-Oct-12 0:32
Sergey Vystoropskiy1-Oct-12 0:32 
GeneralRe: This is by design Pin
Dmitriy Iassenev3-Oct-12 7:03
Dmitriy Iassenev3-Oct-12 7:03 
Casts are very interesting topic and I'd like to add that C-style cast is even more evil than reinterpret_cast, because it behaves differently!

For example, if you use C-style cast to cast from B* to C* using your class hierarchy and you include header of C class, then static_cast will be used, but if you remove C class header include and forward declare class C, compiler will silently perform reinterpret_cast!

And I don't mention that C-style cast silently performs const_cast if needed.
GeneralMy vote of 5 Pin
StNickolay30-Sep-12 8:06
StNickolay30-Sep-12 8:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.