Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette section illustre les erreurs de compilateur classiques qui se produisent lors de la migration d’une base de code existante. Ces exemples proviennent du code HAL au niveau du système, bien que les concepts soient directement applicables au code au niveau de l’utilisateur.
Avertissement C4311 - Exemple 1
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long
-
code
-
pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA; -
Description
-
PtrToUlong est une fonction ou une macro inline, en fonction de votre utilisation. Il tronque un pointeur vers un ULONG. Bien que les pointeurs 32 bits ne soient pas affectés, la moitié supérieure d’un pointeur 64 bits est tronquée.
CIA_PCI_CONFIG_BASE_QVA est déclaré en tant que PVOID. Le ULONG cast fonctionne dans le monde 32 bits, mais entraîne une erreur dans le monde 64 bits. La solution consiste à obtenir un pointeur 64 bits vers un ULONG, car la modification de la définition de l’union que pPciAddr->u.AsULONG est définie dans les modifications trop de code.
L’utilisation de la macro PtrToUlong pour convertir le PVOID 64 bits en ULONG nécessaire est autorisé, car nous avons des connaissances sur la valeur spécifique de CIA_PCI_CONFIG_BASE_QVA. Dans ce cas, ce pointeur n’aura jamais de données dans les 32 bits supérieurs.
-
solution
-
pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);
Avertissement C4311 - Exemple 2
'type cast' : troncation du pointeur de 'struct _ERROR_FRAME *__ptr64 ' vers 'unsigned long
-
code
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError ); -
Description
-
Le problème est que le dernier paramètre de cette fonction est un pointeur vers une structure de données. Étant donné que PUncorrectableError est un pointeur, il change de taille avec le modèle de programmation. Le prototype de KeBugCheckEx a été modifié afin que le dernier paramètre soit un ULONG_PTR. Par conséquent, il est nécessaire de convertir le pointeur de fonction en un ULONG_PTR.
Vous pouvez demander pourquoi PVOID n’a pas été utilisé comme dernier paramètre. Selon le contexte de l’appel, le dernier paramètre peut être autre qu’un pointeur ou peut-être un code d’erreur.
-
solution
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );
Avertissement C4244 Exemple 1
'=' : conversion de 'struct _CONFIGURATION_COMPONENT *__ptr64' en 'struct _CONFIGURATION_COMPONENT *', perte possible de données
-
code
-
Component = &CurrentEntry->ComponentEntry; -
Description
-
La fonction déclare le composant de variable en tant que PCONFIGURATION_COMPONENT. Plus tard, la variable est utilisée dans l’affectation suivante qui s’affiche correctement :
Component = &CurrentEntry->ComponentEntry;Toutefois, le type PCONFIGURATION_COMPONENT est défini comme suit :
typedef struct __CONFIGURATION_COMPONENT { ... ... } CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;La définition de type pour PCONFIGURATION_COMPONENT fournit un pointeur 32 bits dans les modèles 32 bits et 64 bits, car il est déclaré POINTER_32. Le concepteur d’origine de cette structure savait qu’il allait être utilisé dans un contexte 32 bits dans le BIOS et l’a expressément défini pour cette utilisation. Ce code fonctionne correctement dans Windows 32 bits, car les pointeurs sont 32 bits. Dans Windows 64 bits, il ne fonctionne pas, car le code est dans un contexte 64 bits.
-
solution
-
Pour contourner ce problème, utilisez CONFIGURATION_COMPONENT * plutôt que le PCONFIGURATION_COMPONENT 32 bits . Il est important de comprendre clairement l’objectif du code. Si ce code est destiné à toucher un BIOS ou un espace système 32 bits, ce correctif ne fonctionnera pas.
POINTER_32 est défini dans Ntdef.h et Winnt.h.
#ifdef (__AXP64__) #define POINTER_32 _ptr32 #else #define POINTER_32 #endif
Avertissement C4242 Exemple 2
'=' : conversion de '__int64' en 'unsigned long', perte possible de données
-
code
-
ARC_STATUS HalpCopyNVRamBuffer ( IN PCHAR NvDestPtr, IN PCHAR NvSrcPtr, IN ULONG Length ) { ULONG PageSelect1, ByteSelect1; ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; -
Description
-
Cet avertissement est généré, car le calcul utilise des valeurs 64 bits, dans ce cas des pointeurs et place le résultat dans un ULONG 32 bits.
-
solution
-
Tapez le résultat du calcul en ULONG comme indiqué ici :
ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;Le typecasting du résultat permet au compilateur de savoir que vous êtes sûr du résultat. Cela étant dit, assurez-vous que vous comprenez le calcul et êtes vraiment sûr qu’il s’ajustera dans un ULONG 32 bits.
Si le résultat peut ne pas correspondre à un ULONG32 bits, modifiez le type de base de la variable qui contiendra le résultat.
Avertissement C4311 - Exemple 1
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long'
-
code
-
ULONG HalpMapDebugPort( IN ULONG ComPort, OUT PULONG ReadQva, OUT PULONG WriteQva) { ULONG ComPortAddress; ULONG PortQva; // Compute the port address, based on the desired com port. switch( ComPort ){ case 1: ComPortAddress = COM1_ISA_PORT_ADDRESS; break; case 2: default: ComPortAddress = COM2_ISA_PORT_ADDRESS; } PortQva = (ULONG)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress; // Return the QVAs for read and write access. *ReadQva = PortQva; *WriteQva = PortQva; return ComPortAddress; } -
Description
-
Cette fonction entière traite des adresses en tant qu’entiers, nécessitant la nécessité de taper ces entiers de manière portable. Toutes les variables locales, les valeurs intermédiaires dans les calculs et les valeurs de retour doivent être des types portables.
-
solution
-
ULONG_PTR HalpMapDebugPort( IN ULONG ComPort, OUT PULONG_PTR ReadQva, OUT PULONG_PTR WriteQva) { ULONG_PTR ComPortAddress; ULONG_PTR PortQva; // Compute the port address, based on the desired com port. switch( ComPort ){ case 1: ComPortAddress = COM1_ISA_PORT_ADDRESS; break; case 2: default: ComPortAddress = COM2_ISA_PORT_ADDRESS; } PortQva = (ULONG_PTR)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress; // Return the QVAs for read and write access. *ReadQva = PortQva; *WriteQva = PortQva; return ComPortAddress; }PULONG_PTR est un pointeur qui est lui-même 32 bits pour Windows 32 bits et 64 bits pour Windows 64 bits. Il pointe vers un entier non signé, ULONG_PTR, qui est de 32 bits pour Windows 32 bits et 64 bits pour Windows 64 bits.
Avertissement C4311 - Exemple 2
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long'
-
code
-
BOOLEAN HalpMapIoSpace ( VOID ) { PVOID PciIoSpaceBase; PciIoSpaceBase = HAL_MAKE_QVA( CIA_PCI_SPARSE_IO_PHYSICAL ); //Map base addresses in QVA space. HalpCMOSRamBase = (PVOID)((ULONG)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS); -
Description
-
Même si toutes les valeurs QVA (Quasi Virtual Address) sont vraiment des valeurs 32 bits à ce stade et s’intègrent dans un ULONG, il est plus cohérent de traiter toutes les adresses comme des valeurs ULONG_PTR lorsque cela est possible.
Le pointeur PciIoSpaceBase contient l’appliance virtuelle QVA créée dans la macro HAL_MAKE_QVA. Cette macro retourne une valeur 64 bits avec les 32 premiers bits définis sur zéro afin que les mathématiques fonctionnent. Nous pourrions simplement laisser le code pour tronquer le pointeur dans un ULONG, mais cette pratique est déconseillée d’améliorer la facilité de maintenance et la portabilité du code. Par exemple, le contenu d’une appliance virtuelle QVA peut changer à l’avenir pour utiliser certains des bits supérieurs à ce niveau, en cassant le code.
-
solution
-
Soyez sûr et utilisez ULONG_PTR pour toutes les mathématiques d’adresse et de pointeur.
HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
Avertissement C4311 - Exemple 3
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long'
-
code
-
PVOID HalDereferenceQva( PVOID Qva, INTERFACE_TYPE InterfaceType, ULONG BusNumber) if ( ((ULONG) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG)Qva << IO_BIT_SHIFT ) ); } else { return (Qva); } -
Description
-
Le compilateur avertit l’adresse des opérateurs (&) et gauche (<<) s’ils sont appliqués aux types de pointeur. Dans le code ci-dessus, Qva est une valeur PVOID. Nous devons le caster en un type entier pour effectuer les calculs. Étant donné que le code doit être portable, utilisez ULONG_PTR au lieu de ULONG .
-
solution
-
if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );
Avertissement C4311 - Exemple 4
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long'
-
code
-
TranslatedAddress->LowPart = (ULONG)HalCreateQva( *TranslatedAddress, va); -
Description
-
TranslatedAddress est une union qui ressemble à ce qui suit :
typedef union Struct { ULONG LowPart; LONG Highpart; } LONGLONG QuadPart; } -
solution
-
En sachant ce que le reste du code peut placer dans Highpart, nous pouvons sélectionner l’une des solutions présentées ici.
TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );La macro PtrToUlong tronque le pointeur retourné par HalCreateQva à 32 bits. Nous savons que l’appliance virtuelle QVA retournée par HalCreateQva a les 32 bits supérieurs définis sur zéro et la ligne de code très suivante définit TranslationAddress->Highpart sur zéro.
Avec précaution, nous pourrions utiliser les éléments suivants :
TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);Cela fonctionne dans cet exemple : la macro HalCreateQva retourne 64 bits, avec les 32 bits supérieurs définis sur zéro. Veillez simplement à ne pas laisser les 32 bits supérieurs non définis dans un environnement 32 bits, que cette deuxième solution peut réellement faire.
Avertissement C4311 - Exemple 5
'type cast' : troncation du pointeur de 'void *__ptr64' vers 'unsigned long'
-
code
-
VOID HalpCiaProgramDmaWindow( PWINDOW_CONTROL_REGISTERS WindowRegisters, PVOID MapRegisterBase ) { CIA_WBASE Wbase; Wbase.all = 0; Wbase.Wen = 1; Wbase.SgEn = 1; Wbase.Wbase = (ULONG)(WindowRegisters->WindowBase) >> 20; -
Description
-
WindowRegisters ->WindowBase est un pointeur et est maintenant de 64 bits. Le code indique de déplacer à droite cette valeur 20 bits. Le compilateur ne nous permet pas d’utiliser l’opérateur de décalage droit (>>) sur un pointeur ; par conséquent, nous devons le caster en un certain nombre entier.
-
solution
-
Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));La conversion en ULONG_PTR est juste ce dont nous avons besoin. Le problème suivant est Wbase. Wbase est un ULONG et est de 32 bits. Dans ce cas, nous savons que le pointeur 64 bits WindowRegisters->WindowBase est valide dans les 32 bits inférieurs, même après avoir été décalé. Cela permet d’utiliser la macro PtrToUlong, car elle tronque le pointeur 64 bits en un ULONG32 bits. Le cast PVOID est nécessaire, car PtrToUlong attend un argument de pointeur. Lorsque vous examinez le code assembleur résultant, tout ce cast de code C devient simplement un quad de charge, passer à droite et stocker de long.