Nous utilisons des cookies pour améliorer votre expérience de navigation. En savoir plus
Accepter
to the top
close form

Remplissez le formulaire ci‑dessous en 2 étapes simples :

Vos coordonnées :

Étape 1
Félicitations ! Voici votre code promo !

Type de licence souhaité :

Étape 2
Team license
Enterprise licence
** En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité
close form
Demandez des tarifs
Nouvelle licence
Renouvellement de licence
--Sélectionnez la devise--
USD
EUR
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
La licence PVS‑Studio gratuit pour les spécialistes Microsoft MVP
close form
Pour obtenir la licence de votre projet open source, s’il vous plait rempliez ce formulaire
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
I am interested to try it on the platforms:
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
check circle
Votre message a été envoyé.

Nous vous répondrons à


Si vous n'avez toujours pas reçu de réponse, vérifiez votre dossier
Spam/Junk et cliquez sur le bouton "Not Spam".
De cette façon, vous ne manquerez la réponse de notre équipe.

>
>
>
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.

30 Jui 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: