ORC adalah alat untuk menemukan pelanggaran Aturan Satu Definisi C++ di rantai alat OSX.
ORC adalah plesetan dari DWARF yang merupakan plesetan dari ELF. ORC adalah akronim; sedangkan O adalah singkatan dari ODR, ironisnya R dan C mewakili beberapa kata (yang mungkin bertentangan).
Ada banyak artikel tentang One Definition Rule (ODR), termasuk Standar C++ itu sendiri. Inti dari aturan ini adalah jika suatu simbol didefinisikan dalam suatu program, simbol tersebut hanya diperbolehkan untuk didefinisikan satu kali. Beberapa simbol diberikan pengecualian terhadap aturan ini, dan diperbolehkan untuk didefinisikan beberapa kali. Namun, simbol-simbol tersebut harus ditentukan oleh rangkaian token yang identik .
Perhatikan bahwa beberapa pengaturan kompiler juga dapat mempengaruhi urutan token - misalnya, RTTI yang diaktifkan atau dinonaktifkan dapat mengubah definisi simbol (dalam hal ini, vtable kelas.)
Simbol apa pun yang melanggar aturan di atas merupakan pelanggaran ODR (ODRV). Dalam beberapa kasus, linker mungkin menangkap definisi simbol duplikat dan mengeluarkan peringatan atau kesalahan. Namun, Standar menyatakan bahwa linker tidak diperlukan untuk melakukan hal tersebut. Andy G menjelaskannya dengan baik:
untuk alasan kinerja, Standar C++ menyatakan bahwa jika Anda melanggar Aturan Satu Definisi sehubungan dengan templat, perilaku tersebut tidak terdefinisi. Karena linker tidak peduli, pelanggaran aturan ini tidak akan terjadi. sumber
ODRV non-template dimungkinkan, dan linker mungkin juga tidak menyebutkannya.
ODRV biasanya berarti Anda memiliki simbol yang tata letak binernya berbeda-beda bergantung pada unit kompilasi yang membuatnya. Namun, karena aturannya, ketika sebuah linker menemukan beberapa definisi, ia bebas memilih salah satu dari definisi tersebut dan menggunakannya sebagai tata letak biner untuk sebuah simbol. Jika tata letak yang dipilih tidak cocok dengan tata letak biner internal simbol di unit kompilasi, perilakunya tidak terdefinisi.
Seringkali debugger tidak berguna dalam skenario ini. Itu juga akan menggunakan definisi simbol tunggal untuk keseluruhan program, dan ketika Anda mencoba men-debug ODRV, debugger mungkin memberi Anda data yang buruk, atau menunjuk ke lokasi di file yang tampaknya tidak benar. Pada akhirnya, debugger akan tampak berbohong kepada Anda, namun secara diam-diam tidak memberikan petunjuk apa pun masalahnya.
Seperti semua bug, ODRV membutuhkan waktu untuk diperbaiki, jadi mengapa Anda harus memperbaiki pelanggaran ODR dalam kode yang diuji (dan mungkin berfungsi)?
ORC adalah alat yang melakukan hal berikut:
Kecuali ada bug pada alat ini, ORC tidak menghasilkan positif palsu. Apa pun yang dilaporkannya adalah ODRV.
Saat ini, ORC tidak mendeteksi semua kemungkinan pelanggaran Aturan Satu Definisi. Kami berharap dapat memperluas dan meningkatkan apa yang dapat dicapai seiring berjalannya waktu. Sampai saat itu, ini berarti bahwa meskipun ORC merupakan pemeriksaan yang berharga, pemindaian yang bersih tidak menjamin suatu program bebas dari ODRV.
ORC dapat menemukan:
Catatan tentang vtables: ORC akan mendeteksi metode virtual yang ada di slot berbeda. (Yang merupakan program yang sangat rusak.) Pada titik ini, ia tidak akan mendeteksi kelas yang memiliki metode virtual yang merupakan "superset" dari kelas duplikat yang melanggar ODR.
Selain sumber ORC utama, kami mencoba memberikan kumpulan contoh aplikasi yang berisi ODRV yang harus ditangkap oleh alat tersebut.
ORC awalnya dibuat di macOS. Meskipun penerapannya saat ini terfokus pada hal tersebut, penerapannya tidak harus dibatasi pada rangkaian alat tersebut.
ORC dikelola oleh cmake, dan dibangun menggunakan konvensi pembangunan khas proyek yang dikelola CMake:
mkdir build
cd build
cmake -GXcode ..
Ada beberapa contoh aplikasi yang ORC diintegrasikan untuk tujuan pengujian. Itu dapat dipilih melalui popup target di Xcode.
ORC menggunakan Tracy sebagai alat pembuatan profil pilihannya, dan diaktifkan secara default. Untuk menonaktifkan Tracy, tentukan baris perintah cmake seperti ini:
cmake .. -GXcode -DTRACY_ENABLE=OFF
Ketergantungan Tracy diperlukan bahkan jika pembuatan profil dinonaktifkan (ini akan dikompilasi saat runtime.) Perhatikan bahwa opsi ini disimpan dalam cache, jadi Anda harus secara eksplisit OFF
atau ON
. Menjalankan kembali pemanggilan baris perintah dengan opsi yang hilang akan menyebabkan nilai sebelumnya digunakan.
ORC dapat dipanggil langsung dari baris perintah, atau dimasukkan ke dalam rantai alat pada langkah linker. Outputnya tidak berubah; ini hanyalah masalah kenyamanan dalam alur kerja Anda.
Mode ini berguna jika Anda memiliki perintah linker dan argumennya, dan ingin mencari ODRV yang terpisah dari build sebenarnya.
File konfigurasi (lihat di bawah)
'forward_to_linker' = false
'standalone_mode' = false
Anda memerlukan argumen baris perintah ld
dari XCode. Bangun dengan Xcode, (jika Anda tidak dapat menautkan, ORC tidak dapat membantu), salin perintah tautan, dan tempelkan setelah pemanggilan ORC. Sesuatu seperti:
/path/to/orc /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -target ... Debug/lem_mac
(Ini adalah baris perintah yang sangat besar, disingkat di sini.)
ORC akan mengeksekusi, dan mencatat pelanggaran ODR ke konsol.
Jika Anda memiliki daftar file perpustakaan untuk diproses ORC, ORC juga bisa melakukannya.
File konfigurasi (lihat di bawah)
'forward_to_linker' = false
'standalone_mode' = true
Dalam mode ini, cukup berikan daftar file perpustakaan ke ORC untuk diproses.
File konfigurasi (lihat di bawah)
'forward_to_linker' = true
'standalone_mode' = false
Untuk menggunakan ORC dalam proyek pembangunan Xcode Anda, ganti variabel berikut dengan jalur yang sepenuhnya memenuhi syarat ke skrip ORC:
"LIBTOOL": "/absolute/path/to/orc",
"LDTOOL": "/absolute/path/to/orc",
"ALTERNATE_LINKER": "/absolute/path/to/orc",
Dengan pengaturan tersebut, Xcode harus menggunakan ORC sebagai alat untuk fase libtool
dan ld
dari pembangunan proyek. Karena pengaturan forward_to_linker
, ORC akan memanggil alat tautan yang tepat untuk menghasilkan file biner. Setelah selesai, ORC akan memulai pemindaiannya.
Di antara pengaturan lainnya, ORC dapat dikonfigurasi untuk keluar atau sekadar memperingatkan ketika ODRV terdeteksi.
ORC akan menelusuri direktori saat ini, mencari file konfigurasi dengan nama:
.orc-config
, atau_orc-config
Jika ditemukan, banyak switch yang dapat mengontrol logika ORC. Silakan lihat _orc_config
di repositori untuk contohnya. ORC akan lebih memilih .orc-config
sehingga mudah untuk menyalin _orc_config
asli dan mengubah nilai secara lokal di .orc-config
.
Misalnya:
error: ODRV (structure:byte_size); conflict in `object`
compilation unit: a.o:
definition location: /Volumes/src/orc/extras/struct0/src/a.cpp:3
calling_convention: pass by value; 5 (0x5)
name: object
byte_size: 4 (0x4)
compilation unit: main.o:
definition location: /Volumes/src/orc/extras/struct0/src/main.cpp:3
calling_convention: pass by value; 5 (0x5)
name: object
byte_size: 1 (0x1)
structure:byte_size
dikenal sebagai kategori ODRV, dan merinci jenis pelanggaran apa yang diwakili oleh kesalahan ini. Kedua unit kompilasi yang mengalami konflik kemudian dikeluarkan, beserta informasi DWARF yang mengakibatkan tabrakan tersebut.
struct object { ... }
In ao:
dan In main.o
terdapat 2 file objek atau arsip yang tidak cocok. ODR kemungkinan besar disebabkan oleh kompilasi yang tidak cocok atau pengaturan #define dalam kompilasi arsip ini. byte_size
adalah nilai sebenarnya yang menyebabkan kesalahan.
definition location: /Volumes/src/orc/extras/struct0/src/a.cpp:3
Di baris dan file apa objek dideklarasikan. Jadi baris 3 dari a.cpp
dalam contoh ini.
Untuk versi ORC yang sama, dan masukan yang sama, ORC akan selalu menulis keluaran yang sama. Dimana "sama" adalah byte yang identik dan alat diff tidak akan menunjukkan perbedaan.
Mencapai (dan kemungkinan mempertahankan) keluaran yang konsisten ternyata merupakan tantangan dalam aplikasi yang sangat multi-thread.
Namun harap diingat bahwa ini TIDAK berlaku untuk versi ORC yang berbeda. Perubahan pada ORC hampir pasti akan mengakibatkan perubahan output.
Juga tidak ada jaminan bahwa perubahan “kecil” pada file masukan akan menjamin perubahan “kecil” pada keluaran ORC. Perilaku ini diinginkan dan kemungkinan besar akan menjadi area perbaikan di masa depan.
orc_test
) Aplikasi pengujian unit disediakan untuk memastikan bahwa ORC menangkap apa yang dimaksudkan untuk ditangkap. orc_test
memperkenalkan miniatur "sistem build" untuk menghasilkan file objek dari sumber yang dikenal untuk menghasilkan pelanggaran ODR yang diketahui. Kemudian memproses file objek menggunakan mesin yang sama dengan alat baris perintah ORC, dan membandingkan hasilnya dengan daftar laporan ODRV yang diharapkan.
Setiap pengujian unit pada baterai bersifat terpisah, dan berisi:
odrv_test.toml
, file TOML tingkat tinggi yang menjelaskan parameter pengujianSecara umum, satu pengujian seharusnya menghasilkan satu pelanggaran ODR, namun hal ini mungkin tidak dapat dilakukan di semua kasus.
File-file ini adalah file sumber C++ standar. Kuantitas dan ukurannya harus sangat kecil - hanya cukup besar sesuai kebutuhan untuk menimbulkan ODRV yang diinginkan.
odrv_test.toml
File pengaturan menjelaskan kepada aplikasi pengujian sumber apa yang perlu dikompilasi, flag kompilasi apa yang harus digunakan untuk pengujian, dan ODRV apa yang perlu diwaspadai sistem sebagai hasil dari menghubungkan file objek yang dihasilkan. ) bersama.
Sumber pengujian ditentukan dengan arahan [[source]]
:
[[ source ]]
path = " one.cpp "
obj = " one "
flags = [
" -Dfoo=1 "
]
Bidang path
menjelaskan jalur ke file yang berhubungan dengan odrv_test.toml
. Ini adalah satu-satunya bidang yang wajib diisi.
Bidang obj
menentukan nama file objek (sementara) yang akan dibuat. Jika nama ini dihilangkan, nama pseudo-acak akan digunakan.
Bidang flags
menentukan flag kompilasi yang akan digunakan secara khusus untuk unit kompilasi ini. Dengan menggunakan kolom ini, dimungkinkan untuk menggunakan kembali file sumber yang sama dengan flag kompilasi berbeda untuk memperoleh ODRV.
ODRV ditentukan dengan direktif [[odrv]]
:
[[ odrv ]]
category = " subprogram:vtable_elem_location "
linkage_name = " _ZNK6object3apiEv "
Bidang category
menjelaskan jenis pelanggaran ODR spesifik yang mungkin ditemukan oleh aplikasi pengujian.
Bidang linkage_name
menjelaskan simbol spesifik yang menyebabkan ODRV. Saat ini tidak digunakan, tetapi akan diterapkan saat aplikasi pengujian sudah matang.
Tanda berikut saat ini tidak digunakan atau akan mengalami perubahan besar seiring dengan semakin matangnya aplikasi pengujian unit.
[compile_flags]
: Serangkaian tanda kompilasi yang harus diterapkan ke setiap file sumber dalam pengujian unit.
[orc_test_flags]
: Serangkaian pengaturan runtime yang akan diteruskan ke aplikasi pengujian untuk pengujian ini.
[orc_flags]
: Serangkaian pengaturan runtime untuk diteruskan ke mesin ORC untuk pengujian ini.