Selama analisis kode, PVS-Studio menganalisis aliran data dan beroperasi pada nilai-nilai variabel. Nilai diambil dari konstanta atau disimpulkan dari ekspresi kondisional. Kami menyebutnya nilai-nilai virtual. Baru-baru ini, kami meningkatkan mereka untuk bekerja dengan konstanta multi-karakter dan ini adalah alasan untuk membuat aturan diagnostik baru.
Pendahuluan
Literal multi-karakter
didefinisikan oleh implementasi , jadi kompiler yang berbeda dapat menyandikan literal ini dengan cara yang berbeda. Misalnya, GCC dan Dentang menetapkan nilai berdasarkan urutan karakter dalam literal, sedangkan MSVC memindahkannya tergantung pada jenis karakter (reguler atau melarikan diri).
Sebagai contoh, 'T \ x65s \ x74' literal akan dikodekan dengan cara yang berbeda, tergantung pada kompiler. Logika yang serupa harus ditambahkan ke penganalisa. Sebagai hasilnya, kami membuat aturan diagnostik baru V1039 untuk mengidentifikasi literal tersebut dalam kode. Literal semacam itu berbahaya dalam proyek lintas platform yang menggunakan banyak kompiler untuk perakitan.
Diagnostik V1039
Pertimbangkan sebuah contoh. Kode di bawah ini, disusun oleh berbagai kompiler, akan berperilaku berbeda:
#include <stdio.h> void foo(int c) { if (c == 'T\x65s\x74') // <= V1039 { printf("Compiled with GCC or Clang.\n"); } else { printf("It's another compiler (for example, MSVC).\n"); } } int main(int argc, char** argv) { foo('Test'); return 0; }
Program yang dikompilasi oleh kompiler yang berbeda akan mencetak pesan yang berbeda ke layar.
Untuk proyek yang menggunakan kompiler tertentu, ini tidak akan terlihat, tetapi porting dapat menyebabkan masalah, jadi Anda harus mengganti literal tersebut dengan konstanta numerik sederhana, misalnya, ubah 'Uji' menjadi 0x54657374.
Untuk menunjukkan perbedaan antara kompiler, kami menulis sebuah utilitas kecil di mana urutan 3 dan 4 karakter diambil, misalnya, 'GHIJ' dan 'GHI', dan representasi mereka dalam memori setelah kompilasi ditampilkan.
Kode Utilitas:
#include <stdio.h> typedef int char_t; void PrintBytes(const char* format, char_t lit) { printf("%20s : ", format); const unsigned char *ptr = (const unsigned char*)&lit; for (int i = sizeof(lit); i--;) { printf("%c", *ptr++); } putchar('\n'); } int main(int argc, char** argv) { printf("Hex codes are: G(%02X) H(%02X) I(%02X) J(%02X)\n",'G','H','I','J'); PrintBytes("'GHIJ'", 'GHIJ'); PrintBytes("'\\x47\\x48\\x49\\x4A'", '\x47\x48\x49\x4A'); PrintBytes("'G\\x48\\x49\\x4A'", 'G\x48\x49\x4A'); PrintBytes("'GH\\x49\\x4A'", 'GH\x49\x4A'); PrintBytes("'G\\x48I\\x4A'", 'G\x48I\x4A'); PrintBytes("'GHI\\x4A'", 'GHI\x4A'); PrintBytes("'GHI'", 'GHI'); PrintBytes("'\\x47\\x48\\x49'", '\x47\x48\x49'); PrintBytes("'GH\\x49'", 'GH\x49'); PrintBytes("'\\x47H\\x49'", '\x47H\x49'); PrintBytes("'\\x47HI'", '\x47HI'); return 0; }
Output dari utilitas yang dikompilasi oleh Visual C ++:
Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : GHIJ 'G\x48\x49\x4A' : HGIJ 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : GHI 'GH\x49' : IHG '\x47H\x49' : HGI '\x47HI' : IHG
Output dari utilitas yang disusun oleh GCC atau Dentang:
Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : JIHG 'G\x48\x49\x4A' : JIHG 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : IHG 'GH\x49' : IHG '\x47H\x49' : IHG '\x47HI' : IHG
Kesimpulan
Diagnostik V1039 ditambahkan ke analyzer PVS-Studio versi
7.03 , yang baru-baru ini dirilis. Anda dapat mengunduh versi analisa terbaru di
halaman unduhan .

Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Svyatoslav Razmyslov.
Bahaya menggunakan konstanta multi-karakter