Kesalahan Kompilator Umum

Bagian ini mengilustrasikan kesalahan kompilator umum yang terjadi saat memigrasikan basis kode yang ada. Contoh-contoh ini kebetulan berasal dari kode HAL tingkat sistem, meskipun konsepnya langsung berlaku untuk kode tingkat pengguna.

Contoh Peringatan C4311 1

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long

Kode

pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA;

Deskripsi

PtrToUlong adalah fungsi atau makro sebaris, tergantung pada penggunaan Anda. Ini memotong pointer ke ULONG. Meskipun pointer 32-bit tidak terpengaruh, bagian atas pointer 64-bit terpotong.

CIA_PCI_CONFIG_BASE_QVA dinyatakan sebagai PVOID. Pemeran ULONG bekerja di dunia 32-bit, tetapi menghasilkan kesalahan di dunia 64-bit. Solusinya adalah mendapatkan pointer 64-bit ke ULONG, karena mengubah definisi serikat bahwa pPciAddr->u.AsULONG didefinisikan dalam perubahan terlalu banyak kode.

Menggunakan makro PtrToUlong untuk mengonversi PVOID 64-bit ke ULONG yang diperlukan diizinkan karena kami memiliki pengetahuan tentang nilai spesifik CIA_PCI_CONFIG_BASE_QVA. Dalam hal ini, pointer ini tidak akan pernah memiliki data di 32 bit atas.

Solusi

pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);

Contoh Peringatan C4311 2

'type cast' : pemotongan pointer dari 'struct _ERROR_FRAME *__ptr64 ' ke 'unsigned long

Kode

KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError );

Deskripsi

Masalahnya adalah bahwa parameter terakhir untuk fungsi ini adalah penunjuk ke struktur data. Karena PUncorrectableError adalah penunjuk, PUncorrectableError mengubah ukuran dengan model pemrograman. Prototipe untuk KeBugCheckEx diubah sehingga parameter terakhir adalah ULONG_PTR. Akibatnya, perlu untuk mentransmisikan penunjuk fungsi ke ULONG_PTR.

Anda mungkin bertanya mengapa PVOID tidak digunakan sebagai parameter terakhir. Tergantung pada konteks panggilan, parameter terakhir mungkin sesuatu selain penunjuk atau mungkin kode kesalahan.

Solusi

KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );

Contoh Peringatan C4244 1

'=' : konversi dari 'struct _CONFIGURATION_COMPONENT *__ptr64 ' ke 'struct _CONFIGURATION_COMPONENT *', kemungkinan hilangnya data

Kode

Component = &CurrentEntry->ComponentEntry;

Deskripsi

Fungsi mendeklarasikan komponen variabel sebagai PCONFIGURATION_COMPONENT. Nantinya, variabel digunakan dalam penugasan berikut yang tampak benar:

Component = &CurrentEntry->ComponentEntry;

Namun, jenis PCONFIGURATION_COMPONENT didefinisikan sebagai:

typedef struct __CONFIGURATION_COMPONENT {
...
...
} CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;

Definisi jenis untuk PCONFIGURATION_COMPONENT menyediakan pointer 32-bit dalam model 32-bit dan 64-bit karena dinyatakan POINTER_32. Perancang asli struktur ini tahu itu akan digunakan dalam konteks 32-bit dalam BIOS dan secara tegas mendefinisikannya untuk penggunaan tersebut. Kode ini berfungsi dengan baik di Windows 32-bit karena pointer kebetulan 32-bit. Di Windows 64-bit, kode tidak berfungsi karena kode dalam konteks 64-bit.

Solusi

Untuk mengatasi masalah ini, gunakan CONFIGURATION_COMPONENT * daripada PCONFIGURATION_COMPONENT 32-bit . Penting untuk memahami dengan jelas tujuan kode. Jika kode ini dimaksudkan untuk menyentuh BIOS 32-bit atau ruang Sistem, perbaikan ini tidak akan berfungsi.

POINTER_32 didefinisikan dalam Ntdef.h dan Winnt.h.

#ifdef (__AXP64__)
#define POINTER_32 _ptr32
#else
#define POINTER_32
#endif

Contoh Peringatan C4242 2

'=' : konversi dari '__int64 ' ke 'unsigned long ', kemungkinan hilangnya data

Kode

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;

Deskripsi

Peringatan ini dihasilkan karena perhitungan menggunakan nilai 64-bit, dalam hal ini pointer, dan menempatkan hasilnya dalam ULONG 32-bit.

Solusi

Ketikkan hasil penghitungan ke ULONG seperti yang ditunjukkan di sini:

ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;

Mengetikkan hasilnya memungkinkan pengkompilasi tahu bahwa Anda yakin tentang hasilnya. Yang sedang mengatakan, pastikan Anda memahami perhitungan dan benar-benar yakin itu akan cocok dalam 32-bit ULONG.

Jika hasilnya mungkin tidak cocok dalam ULONG32-bit , ubah jenis dasar variabel yang akan menyimpan hasilnya.

Peringatan C4311 - Contoh 1

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long '

Kode

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

Deskripsi

Seluruh fungsi ini berkaitan dengan alamat sebagai bilangan bulat, yang membutuhkan untuk mengetik bilangan bulat tersebut dengan cara portabel. Semua variabel lokal, nilai perantara dalam perhitungan, dan nilai pengembalian harus berupa jenis portabel.

Solusi

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 adalah pointer yang merupakan 32 bit untuk Windows 32-bit dan 64 bit untuk Windows 64-bit. Ini menunjuk ke bilangan bulat yang tidak ditandatangani, ULONG_PTR, yaitu 32 bit untuk Windows 32-bit dan 64 bit untuk Windows 64-bit.

Peringatan C4311 - Contoh 2

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long '

Kode

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

Deskripsi

Meskipun semua nilai QVA (Alamat Virtual Kuasi) benar-benar nilai 32-bit pada tahap ini dan akan cocok dalam ULONG, lebih konsisten untuk memperlakukan semua alamat sebagai nilai ULONG_PTR jika memungkinkan.

Penunjuk PciIoSpaceBase memegang QVA yang dibuat di HAL_MAKE_QVA makro. Makro ini mengembalikan nilai 64-bit dengan 32 bit teratas yang diatur ke nol sehingga matematika akan berfungsi. Kita cukup membiarkan kode untuk memotong pointer menjadi ULONG, tetapi praktik ini tidak disarankan untuk meningkatkan pemeliharaan kode dan portabilitas. Misalnya, konten QVA mungkin berubah di masa mendatang untuk menggunakan beberapa bit atas pada tingkat ini, melanggar kode.

Solusi

Aman dan gunakan ULONG_PTR untuk semua alamat dan matematika penunjuk.

HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);

Contoh Peringatan C4311 3

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long '

Kode

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

Deskripsi

Pengkompilasi memperingatkan tentang alamat operator (&) dan shift kiri (<<) jika diterapkan ke jenis pointer. Dalam kode di atas, Qva adalah nilai PVOID. Kita perlu melemparkan itu ke jenis bilangan bulat untuk melakukan matematika. Karena kode harus portabel, gunakan ULONG_PTR alih-alih ULONG.

Solusi

if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) {
  return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );

Contoh Peringatan C4311 4

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long '

Kode

TranslatedAddress->LowPart = (ULONG)HalCreateQva(
*TranslatedAddress, va);

Deskripsi

TranslatedAddress adalah gabungan yang terlihat seperti berikut ini:

typedef union
   Struct {
      ULONG LowPart;
      LONG Highpart;
   }
   LONGLONG QuadPart;
}

Solusi

Mengetahui apa sisa kode yang mungkin ditempatkan di Highpart, kita dapat memilih salah satu solusi yang ditunjukkan di sini.

TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );

Makro PtrToUlong memotong pointer yang dikembalikan oleh HalCreateQva menjadi 32 bit. Kita tahu bahwa QVA yang dikembalikan oleh HalCreateQva memiliki 32 bit atas yang diatur ke nol dan baris kode berikutnya menetapkan TranslatedAddress->Highpart ke nol.

Dengan hati-hati, kita dapat menggunakan yang berikut:

TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);

Ini berfungsi dalam contoh ini: makro HalCreateQva mengembalikan 64 bit, dengan 32 bit atas diatur ke nol. Berhati-hatilah untuk tidak membiarkan 32 bit atas tidak terdefinisi di lingkungan 32-bit, yang mungkin benar-benar dilakukan solusi kedua ini.

Contoh Peringatan C4311 5

'type cast' : pemotongan pointer dari 'void *__ptr64 ' ke 'unsigned long '

Kode

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;

Deskripsi

WindowRegisters->WindowBase adalah pointer dan sekarang 64 bit. Kode mengatakan untuk menggeser kanan nilai ini 20 bit. Pengkompilasi tidak akan membiarkan kami menggunakan operator shift kanan (>>) pada pointer; oleh karena itu, kita perlu melemparkannya ke semacam bilangan bulat.

Solusi

Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));

Casting ke ULONG_PTR adalah apa yang kita butuhkan. Masalah selanjutnya adalah Wbase. Wbase adalah ULONG dan 32 bit. Dalam hal ini, kita tahu bahwa penunjuk 64-bit WindowRegisters->WindowBase berlaku di 32 bit yang lebih rendah bahkan setelah digeser. Ini memanfaatkan makro PtrToUlong dapat diterima, karena akan memotong pointer 64-bit menjadi ULONG 32-bit. Pemeran PVOID diperlukan karena PtrToUlong mengharapkan argumen pointer. Ketika Anda melihat kode perakit yang dihasilkan, semua transmisi kode C ini menjadi hanya quad beban, geser ke kanan, dan simpan panjang.