Our website uses cookies to enhance your browsing experience.
Accept
to the top
close form

Fill out the form in 2 simple steps below:

Your contact information:

Step 1
Congratulations! This is your promo code!

Desired license type:

Step 2
Team license
Enterprise license
** By clicking this button you agree to our Privacy Policy statement
close form
Request our prices
New License
License Renewal
--Select currency--
USD
EUR
* By clicking this button you agree to our Privacy Policy statement

close form
Free PVS‑Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

close form
To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

close form
I am interested to try it on the platforms:
* By clicking this button you agree to our Privacy Policy statement

close form
check circle
Message submitted.

Your message has been sent. We will email you at


If you do not see the email in your inbox, please check if it is filtered to one of the following folders:

  • Promotion
  • Updates
  • Spam

>
>
>
V725. Dangerous cast of 'this' to 'void…
menu mobile close menu
Analyzer diagnostics
General Analysis (C++)
General Analysis (C#)
General Analysis (Java)
Micro-Optimizations (C++)
Diagnosis of 64-bit errors (Viva64, C++)
Customer specific requests (C++)
MISRA errors
AUTOSAR errors
OWASP errors (C#)
Problems related to code analyzer
Additional information
toggle menu Contents

V725. Dangerous cast of 'this' to 'void*' type in the 'Base' class, as it is followed by a subsequent cast to 'Class' type.

Jun 30 2015

The analyzer has detected a dangerous conversion of the "this" pointer to the "void*" type followed by a conversion of "void*" back to the class type. Casting "this" to "void*" is not in itself an error, but in certain cases the reverse conversion (from "void*" to the class pointer) is, which may be dangerous as the resulting pointer may appear incorrect.

The diagnostic description is pretty large and complex, but unfortunately I cannot help it. So please read it carefully to the end.

Let's discuss an example where "this" is cast to "void*" and after that the reverse conversion to the class type takes place:

class A
{
public:
  A() : firstPart(1){}
  void printFirstPart() { std::cout << firstPart << " "; }
private:
  int firstPart;
};

class B
{
public:
  B() : secondPart(2){}
  void* GetAddr() const { return (void*)this;  }
  void printSecondPart() { std::cout << secondPart << " "; }
private:
  int secondPart;
};

class C: public A, public B
{
public:
  C() : A(), B(), thirdPart(3){}
  void printThirdPart() { std::cout << thirdPart << " "; }
private:
  int thirdPart;
};
void func()
{
  C someObject;

  someObject.printFirstPart();
  someObject.printSecondPart();
  someObject.printThirdPart();

  void *pointerToObject = someObject.GetAddr();
  ....
  auto pointerC = static_cast<C*>(pointerToObject);

  pointerC->printFirstPart();
  pointerC->printSecondPart();
  pointerC->printThirdPart();
}

We would expect to get the following output:

1 2 3 1 2 3

But what will be actually printed is something like this:

1 2 3 2 3 -858993460

So, we get an incorrect output for all the data after the mentioned conversion sequence. The trouble is that the "pointerC" pointer is now pointing to the memory block allocated for object B, instead of the beginning of the C object as it did before.

This error may seem farfetched and unreal. But it is only obvious because the example above is short and simple. In real-life programs with complex class hierarchies, it may be far more confusing and vague. What makes this issue especially tricky is that when the "GetAddr()" function is stored in class A, everything works right, but if you store it in class B, then it doesn't. That may be quite embarrassing. So let's figure it all out.

To make it easier for you to understand the reason behind the error, we need to find out how objects of classes created through multiple inheritance are constructed and arranged in memory.

A schematic example is shown in Figure 1.

V725/image1.png

Figure 1 - Arrangement of an object of a class created through multiple inheritance in memory

As you can see from this figure, the object of class C (which is the one created through multiple inheritance) consists of the objects of classes A and B plus a part of object C.

Each of the "this" pointers contains the address of the beginning of the memory block allocated for the corresponding object. Figure 2 shows where "this" pointers point to for all the three objects.

V725/image2.png

Figure 2 - "this" pointers and memory blocks

Since the C-class object consists of three parts, its "this" pointer will be pointing not to the memory block added to the base classes, but to the beginning of the entire continuous memory block. That is, "this" pointers for classes A and C will coincide in this case.

The "this" pointer for the B-class object points to where the memory block allocated for it starts, but at the same time, the address of the beginning of this memory block is different from that of the memory block allocated for the C-class object.

So, when calling the "GetAddr()" method, we will get the address of object B and then, after casting the resulting pointer back to type "C*", we will get an incorrect pointer.

In other words, if the "GetAddr()" function were stored in class A, the program would work as expected. But when it is stored in B, we get an error.

To avoid errors like this, the programmer should carefully consider if they really need to cast "this" to "void*", and if the answer is certainly yes, then they must carefully check the inheritance hierarchy as well as any further reverse conversions from "void*" to the class pointer type.

References:

This diagnostic is classified as: