Unicorn with delicious cookie
Our website uses cookies to enhance your browsing experience.
Accept
to the top
>
>
>
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++)
OWASP errors (C#)
OWASP errors (Java)
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 casting of the this pointer to the void* type followed by a cast of void* back to the class type. Casting this to void* is not an error, but in certain cases, casting void* back to the class pointer is. Such conversions may lead to an invalid pointer.

Here is an example where this is cast to void*, followed by an invalid cast back to the class type:

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();
}

One might assume that the output would be as follows:

1 2 3 1 2 3

However, the following is printed:

1 2 3 2 3 -858993460

As a result, the output for all data after conversions is incorrect. The issue is that now pointerC points to the memory block allocated for the B object rather than to the beginning of the C object.

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 vaguer. The most confusing part is that the GetAddr() function works when it's in the A class, but fails when placed in the B class.

To easily understand what caused the error, programmers need to know how class objects created using multiple inheritance are constructed and arranged in memory.

A schematic example is shown in the Figure 1.

Figure 1—The memory layout of a class object created through multiple inheritance.

The C class object, obtained as a result of multiple inheritance, consists of the A and B class objects, as well as a part of the C object.

The this pointer points to the beginning of the memory block allocated for the object. The Figure 2 shows this pointers for all the three objects.

Figure 2—The this pointers and memory blocks.

Since the C class object consists of three parts, its this pointer points to the beginning of the entire continuous memory block rather than to an additional one. That is, this pointers for the A and C classes match in this case.

The this pointer for the B class object points to the beginning of the memory block allocated for it, but its address differs from the starting address of the memory block allocated for the C class object.

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

In other words, if the GetAddr() function were stored in the A class, the program would work as expected, but when it is stored in B, a developer gets an error.

To avoid such errors, programmers should consider whether they really need to cast this to void*. If the answer is yes, they need to carefully check the inheritance hierarchy and any casts of void* back to the class pointer type.

References:

This diagnostic is classified as:

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 want to join the test
* 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