Pertanyaan Bagaimana bisa memahami masalah portabilitas 64-bit terdeteksi?


Saya menemukan potongan mirip dengan ini dalam beberapa (C ++) kode saya sedang mempersiapkan port 64-bit.

int n;
size_t pos, npos;

/* ... initialization ... */

while((pos = find(ch, start)) != npos)
{
    /* ... advance start position ... */

    n++; // this will overflow if the loop iterates too many times
}

Sementara saya benar-benar meragukan hal ini akan benar-benar menyebabkan masalah dalam aplikasi bahkan memori-intensif, itu layak melihat dari sudut pandang teoritis karena kesalahan serupa bisa muncul yang akan menyebabkan masalah. (Perubahan n ke a short dalam contoh di atas dan bahkan file kecil bisa meluap konter.)

Alat analisis statis berguna, tetapi mereka tidak dapat mendeteksi kesalahan semacam ini secara langsung. (Belum, bagaimanapun.) Penghitung n tidak berpartisipasi dalam while ekspresi sama sekali, jadi ini tidak sesederhana loop lainnya (di mana kesalahan typecasting memberikan kesalahan jauh). Setiap alat perlu menentukan bahwa loop akan mengeksekusi lebih dari 231 kali, tetapi itu berarti itu harus dapat memperkirakan berapa kali ekspresi (pos = find(ch, start)) != npos akan dievaluasi sebagai benar — tidak ada prestasi kecil! Bahkan jika alat dapat menentukan bahwa loop bisa eksekusi lebih dari 231 kali (katakanlah, karena itu mengakui find berfungsi bekerja pada string), bagaimana bisa tahu bahwa loop biasa eksekusi lebih dari 264 kali, meluap a size_t nilai juga?

Tampak jelas bahwa untuk secara konklusif mengidentifikasi dan memperbaiki kesalahan semacam ini membutuhkan mata manusia, tetapi adakah pola yang memberikan kesalahan semacam ini sehingga dapat diperiksa secara manual? Kesalahan serupa apa yang harus saya waspadai?

EDIT 1: Sejak short, int dan long jenis-jenis ini secara inheren bermasalah, kesalahan semacam ini dapat ditemukan dengan memeriksa setiap contoh dari jenis-jenis itu. Namun, mengingat mereka di mana-mana di kode C ++ warisan, saya tidak yakin ini praktis untuk sebagian besar perangkat lunak. Apa lagi yang memberikan kesalahan ini? Apakah masing-masing while loop kemungkinan akan menunjukkan semacam kesalahan seperti ini? (for loop tentu tidak kebal terhadapnya!) Seberapa buruk kesalahan semacam ini jika kita tidak berurusan dengan jenis 16-bit seperti short?

EDIT 2: Berikut contoh lain, yang menunjukkan bagaimana kesalahan ini muncul di a for lingkaran.

int i = 0;
for (iter = c.begin(); iter != c.end(); iter++, i++)
{
    /* ... */
}

Ini pada dasarnya masalah yang sama: loop menghitung pada beberapa variabel yang tidak pernah secara langsung berinteraksi dengan tipe yang lebih luas. Variabel masih dapat melimpah, tetapi tidak ada compiler atau alat yang mendeteksi kesalahan casting. (Sebenarnya, tidak ada satu pun.)

EDIT 3: Kode yang saya kerjakan adalah sangat besar. (10-15 juta baris kode untuk C ++ saja.) Tidak mungkin untuk memeriksa semuanya, jadi saya secara khusus tertarik pada cara untuk mengidentifikasi masalah semacam ini (bahkan jika itu menghasilkan tingkat false-positive tinggi) secara otomatis.


4
2018-06-13 21:10


asal


Jawaban:


Ulasan kode. Dapatkan sekelompok orang pintar yang melihat kode.

Penggunaan short, int, atau long adalah tanda peringatan, karena rentang jenis ini tidak didefinisikan dalam standar. Sebagian besar penggunaan harus diubah ke yang baru int_fastN_t jenis dalam <stdint.h>, penggunaan berurusan dengan serialisasi ke intN_t. Yah, sebenarnya ini <stdint.h> jenis harus digunakan untuk typedef jenis aplikasi khusus yang baru.

Contoh ini benar-benar harus:

typedef int_fast32_t linecount_appt;
linecount_appt n;

Ini mengungkapkan asumsi desain bahwa linecount cocok dalam 32 bit, dan juga membuatnya mudah untuk memperbaiki kode jika perubahan persyaratan desain.


1
2018-06-13 21:14



Yang jelas apa yang Anda butuhkan adalah alat penganalisis "rentang" cerdas untuk menentukan rentang nilai yang dihitung dibandingkan dengan jenis di mana nilai-nilai tersebut disimpan. (Keberatan mendasar Anda adalah bahwa penganalisis rentang cerdas itu adalah seseorang). Anda mungkin memerlukan beberapa anotasi kode tambahan (typedef atau pernyataan yang ditempatkan secara manual dengan baik yang memberikan batasan jangkauan yang jelas) untuk memungkinkan analisis yang baik, dan untuk menangani input pengguna besar secara sewenang-wenang.

Anda akan membutuhkan pemeriksaan khusus untuk menangani tempat di mana C / C ++ mengatakan aritmatika hukum tetapi bodoh (mis., asumsi bahwa Anda tidak ingin [perpaduan dua] melengkapi luapan). Untuk n ++ example Anda, (setara dengan n_after = n_before + 1), n_before dapat menjadi 2 ^ 31-1 (karena pengamatan Anda tentang string), jadi n_before + 1 bisa menjadi 2 ^ 32 yang meluap. (Saya pikir semantik C / C ++ standar mengatakan bahwa limpahan ke -0 tanpa keluhan adalah OK).

Kami Perangkat Rekayasa Perangkat Lunak DMS sebenarnya memiliki berbagai mesin analisis yang dibangun di ... tetapi saat ini tidak terhubung ke front end CMS DMS; kita hanya bisa menjajakan begitu cepat: - {[Kami telah menggunakannya pada program COBOL untuk masalah yang berbeda yang melibatkan rentang].

Dengan tidak adanya analisis rentang tersebut, Anda mungkin bisa mendeteksi keberadaan loop dengan aliran dependen seperti itu; nilai n jelas tergantung pada jumlah loop. Saya menduga ini akan memberi Anda setiap loop dalam program yang memiliki efek samping, yang mungkin tidak banyak membantu.

Poster lain menunjukkan, entah bagaimana, redeclaring semua deklarasi int-like menggunakan jenis aplikasi tertentu (misalnya, * linecount_appt *) dan kemudian mengetik mereka untuk menilai yang berfungsi untuk aplikasi Anda. Untuk melakukan ini, saya pikir Anda harus mengklasifikasikan setiap deklarasi int-like ke dalam kategori (misalnya, "deklarasi ini semua * linecount_appt *"). Melakukan ini dengan inspeksi manual untuk 10M SLOC tampaknya cukup sulit dan sangat rawan kesalahan. Menemukan semua deklarasi yang menerima (dengan penugasan) nilai dari sumber nilai yang "sama" mungkin merupakan cara untuk mendapatkan petunjuk tentang di mana jenis aplikasi tersebut. Anda ingin dapat secara mekanis menemukan kelompok deklarasi semacam itu, dan kemudian memiliki beberapa alat secara otomatis menggantikan pernyataan sebenarnya dengan jenis aplikasi yang ditentukan (misalnya, * linecount_appt *). Ini mungkin agak lebih mudah daripada melakukan analisis rentang yang tepat.


1
2018-06-23 08:21



Ada alat yang membantu menemukan masalah tersebut. Saya tidak akan memberikan tautan apa pun di sini karena yang saya ketahui bersifat komersial tetapi seharusnya cukup mudah ditemukan.


0
2018-06-15 18:37