10 bug teratas dari proyek C ++ ditemukan pada 2018

Sudah tiga bulan sejak 2018 berakhir. Bagi banyak orang, ini baru saja lewat, tetapi bagi kami, pengembang PVS-Studio, itu adalah tahun yang cukup penting. Kami berusaha keras, bersaing tanpa rasa takut untuk menyebarkan berita tentang analisis statis dan sedang mencari kesalahan dalam proyek sumber terbuka, ditulis dalam bahasa C, C ++, C #, dan Java. Dalam artikel ini, kami mengumpulkan 10 teratas yang paling menarik untuk Anda!


Untuk menemukan tempat paling menarik, kami menggunakan penganalisa kode statis PVS-Studio . Itu dapat mendeteksi bug dan kerentanan potensial dalam kode, ditulis dalam bahasa yang tercantum di atas.

Jika Anda senang mencari kesalahan sendiri, Anda selalu dapat mengunduh dan mencoba penganalisa kami. Kami menyediakan versi penganalisis gratis untuk siswa dan pengembang yang antusias, lisensi gratis untuk pengembang proyek sumber terbuka, dan juga versi uji coba untuk seluruh dunia dan anjingnya. Siapa tahu, mungkin pada tahun depan Anda akan dapat membuat 10 besar Anda sendiri? :)

Catatan: Saya mengundang Anda untuk memeriksa diri sendiri dan sebelum Anda melihat peringatan penganalisa, cobalah untuk mengungkapkan cacat Anda sendiri. Berapa banyak kesalahan yang dapat Anda temukan?

Tempat kesepuluh


Sumber: Into Space Again: bagaimana Unicorn Mengunjungi Stellarium

Kesalahan ini terdeteksi ketika memeriksa planetarium virtual yang disebut Stellarium.

Fragmen kode di atas, meskipun kecil, penuh dengan kesalahan yang cukup rumit:

Plane::Plane(Vec3f &v1, Vec3f &v2, Vec3f &v3) : distance(0.0f), sDistance(0.0f) { Plane(v1, v2, v3, SPolygon::CCW); } 

Menemukannya?

Peringatan PVS-Studio : V603 Objek telah dibuat tetapi tidak digunakan. Jika Anda ingin memanggil konstruktor, 'this-> Plane :: Plane (....)' harus digunakan. Plane.cpp 29

Pembuat kode bermaksud menginisialisasi bidang beberapa objek, menggunakan konstruktor lain, bersarang di yang utama. Yah, alih-alih itu, dia hanya berhasil membuat objek sementara hancur ketika meninggalkan ruang lingkupnya. Dengan demikian, beberapa bidang objek akan tetap tidak diinisialisasi.

Penulis seharusnya menggunakan konstruktor delegasi, yang diperkenalkan di C ++ 11, alih-alih panggilan konstruktor bersarang. Misalnya, dia bisa menulis seperti ini:

 Plane::Plane(Vec3f& v1, Vec3f& v2, Vec3f& v3) : Plane(v1, v2, v3, SPolygon::CCW) { distance = 0.0f; sDistance = 0.0f; } 

Dengan cara ini, semua bidang yang diperlukan akan diinisialisasi dengan benar. Luar biasa bukan?

Tempat kesembilan


Sumber: Perl 5: Cara Menyembunyikan Kesalahan di Macro

Makro yang sangat luar biasa menonjol dalam segala keindahannya di tempat kesembilan.

Ketika mengumpulkan kesalahan untuk menulis artikel, kolega saya Svyatoslav menemukan peringatan, yang dikeluarkan oleh penganalisa, yang terkait dengan penggunaan makro. Ini dia:

 PP(pp_match) { .... MgBYTEPOS_set(mg, TARG, truebase, RXp_OFFS(prog)[0].end); .... } 

Untuk mencari tahu apa yang salah, Svyatoslav menggali lebih dalam. Dia membuka definisi makro dan melihat bahwa itu berisi beberapa makro bersarang, beberapa di antaranya juga memiliki makro bersarang. Sangat sulit untuk masuk akal dari itu, jadi dia harus menggunakan file yang sudah diproses. Sayangnya, itu tidak membantu. Inilah yang ditemukan Svyatoslav di baris kode sebelumnya:

 (((targ)->sv_flags & 0x00000400) && (!((targ)->sv_flags & 0x00200000) || S_sv_only_taint_gmagic(targ)) ? (mg)->mg_len = ((prog->offs)[0].end), (mg)->mg_flags |= 0x40 : ((mg)->mg_len = (((targ)->sv_flags & 0x20000000) && !__builtin_expect(((((PL_curcop)->cop_hints + 0) & 0x00000008) ? (_Bool)1 :(_Bool)0),(0))) ? (ssize_t)Perl_utf8_length( (U8 *)(truebase), (U8 *)(truebase)+((prog->offs)[0].end)) : (ssize_t)((prog->offs)[0].end), (mg)->mg_flags &= ~0x40)); 

Peringatan PVS-Studio : V502 Mungkin operator '?:' Bekerja dengan cara yang berbeda dari yang diharapkan. Operator '?:' Memiliki prioritas lebih rendah daripada operator '&&'. pp_hot.c 3036

Saya pikir, akan sulit untuk hanya melihat kesalahan seperti itu. Kami sudah lama berkutat pada kode ini, tetapi, terus terang, kami belum menemukan kesalahan di dalamnya. Bagaimanapun, ini adalah contoh yang lucu dari kode yang sulit dibaca.

Mereka mengatakan bahwa makro itu jahat. Tentu, ada beberapa kasus, ketika makro sangat diperlukan, tetapi jika Anda dapat mengganti makro dengan fungsi - Anda harus melakukannya.

Makro bersarang sangat penuh dengan jebakan. Bukan hanya karena sulit untuk memahami mereka, tetapi juga karena mereka dapat memberikan hasil yang tidak terduga. Jika seorang programmer membuat kesalahan dalam makro seperti itu - itu akan jauh lebih sulit untuk menemukannya dalam makro, daripada dalam suatu fungsi.

Tempat kedelapan


Sumber: Chromium: Kesalahan Lainnya

Contoh berikutnya diambil dari serangkaian artikel tentang analisis proyek Chromium. Kesalahan bersembunyi di perpustakaan WebRTC.

 std::vector<SdpVideoFormat> StereoDecoderFactory::GetSupportedFormats() const { std::vector<SdpVideoFormat> formats = ....; for (const auto& format : formats) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } } return formats; } 

Peringatan PVS-Studio: V789 CWE-672 Iterators untuk wadah 'format', yang digunakan dalam rentang berbasis untuk loop, menjadi tidak valid pada panggilan fungsi 'push_back'. stereocodecfactory.cc 89

Kesalahannya adalah bahwa ukuran vektor format bervariasi dalam rentang berbasis untuk loop. Lingkaran berbasis rentang didasarkan pada iterator, itu sebabnya perubahan ukuran kontainer di dalam loop tersebut dapat mengakibatkan pembatalan iterator ini.

Kesalahan ini tetap ada, jika menulis ulang loop dengan penggunaan iterator yang eksplisit. Untuk lebih jelasnya, saya bisa mengutip kode berikut:

 for (auto format = begin(formats), __end = end(formats); format != __end; ++format) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } } 

Misalnya, ketika menggunakan metode push_back , realokasi vektor dapat terjadi - dengan cara ini, iterator akan mengatasi lokasi memori yang tidak valid.

Untuk menghindari kesalahan seperti itu, ikuti aturan: jangan pernah mengubah ukuran wadah di dalam lingkaran dengan kondisi terikat ke wadah ini. Ini juga berhubungan dengan loop berbasis rentang dan loop menggunakan iterator. Anda dapat membaca diskusi ini tentang StackOverflow yang membahas topik operasi yang menyebabkan pembatalan iterator.

Tempat ketujuh


Sumber: Godot: Tentang Penggunaan Analisis Statis Secara Reguler

Contoh pertama dari industri game adalah cuplikan kode yang kami temukan di mesin game Godot. Mungkin perlu beberapa usaha untuk menyadari kesalahannya, tetapi saya yakin bahwa pembaca yang mahir akan mengatasinya.

 void AnimationNodeBlendSpace1D::add_blend_point( const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) { ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { for (int i = blend_points_used - 1; i > p_at_index; i++) { blend_points[i] = blend_points[i - 1]; } } .... } 

Peringatan PVS-Studio: V621 CWE-835 Pertimbangkan untuk memeriksa operator 'untuk'. Ada kemungkinan bahwa loop akan dieksekusi secara tidak benar atau tidak akan dieksekusi sama sekali. animation_blend_space_1d.cpp 113

Mari kita lihat dari dekat kondisi loop. Variabel penghitung diinisialisasi oleh nilai blend_points_used - 1 . Selain itu, dilihat dari dua pemeriksaan sebelumnya (dalam ERR_FAIL_COND dan jika ), menjadi jelas, bahwa pada saat eksekusi loop blend_points_used , blend_points_used akan selalu lebih besar daripada p_at_index . Dengan demikian, kondisi loop selalu benar atau loop tidak dijalankan sama sekali.

Jika blend_points_used - 1 == p_at_index , loop tidak dieksekusi.

Dalam semua kasus lain, centang i> p_at_index akan selalu benar, karena penghitung i naik pada setiap iterasi loop.

Tampaknya loop itu abadi, tetapi tidak demikian.

Pertama, terjadi overflow integer dari variabel i (yang merupakan perilaku tidak terdefinisi). Ini berarti, kita tidak harus bergantung padanya.

Jika saya unsigned int , maka setelah penghitung mencapai nilai sebesar mungkin, operator i ++ akan mengubahnya menjadi 0 . Perilaku seperti itu didefinisikan oleh standar dan disebut "Pembungkus tidak bertanda". Namun, Anda harus sadar bahwa penggunaan mekanisme semacam itu juga bukan ide yang baik .

Itu adalah poin pertama, tetapi kita masih memiliki poin kedua! Kasusnya adalah kita bahkan tidak akan mendapatkan integer overflow. Indeks array akan keluar dari batas dengan cara sebelumnya. Ini berarti, bahwa akan ada upaya untuk mengakses memori di luar blok yang dialokasikan untuk array. Yang merupakan perilaku tidak terdefinisi juga. Contoh klasik :)

Saya dapat memberi Anda beberapa rekomendasi untuk mempermudah menghindari kesalahan serupa:

  1. Tulis kode yang sederhana dan mudah dimengerti
  2. Tinjau kode lebih menyeluruh dan tulis lebih banyak tes untuk kode yang baru ditulis
  3. Gunakan analisis statis;)



Tempat keenam


Sumber: Amazon Lumberyard: A Scream of Anguish

Berikut adalah contoh lain dari industri gamedev, yaitu dari kode sumber mesin AAA Amazon Lumberyard.

 void TranslateVariableNameByOperandType(....) { // Igor: yet another Qualcomm's special case // GLSL compiler thinks that -2147483648 is // an integer overflow which is not if (*((int*)(&psOperand->afImmediates[0])) == 2147483648) { bformata(glsl, "-2147483647-1"); } else { // Igor: this is expected to fix // paranoid compiler checks such as Qualcomm's if (*((unsigned int*)(&psOperand->afImmediates[0])) >= 2147483648) { bformata(glsl, "%d", *((int*)(&psOperand->afImmediates[0]))); } else { bformata(glsl, "%d", *((int*)(&psOperand->afImmediates[0]))); } } bcatcstr(glsl, ")"); .... } 

PVS-Studio warning : V523 Pernyataan 'then' sama dengan pernyataan 'else'. toglsloperand.c 700

Amazon Lumberyard dikembangkan sebagai mesin lintas platform. Untuk alasan ini, pengembang mencoba mendukung sebanyak mungkin penyusun. Seperti yang dapat kita lihat dari komentar, seorang programmer Igor datang melawan kompiler Qualcomm.

Kita tidak tahu apakah dia berhasil melakukan tugasnya dan memeriksa pemeriksaan kompiler "paranoid", tetapi dia meninggalkan kode yang sangat aneh. Yang aneh tentang hal itu adalah bahwa kedua- duanya - dan cabang lain dari pernyataan if berisi kode yang benar-benar identik. Kemungkinan besar, kesalahan seperti itu dihasilkan dari penggunaan metode Copy-Paste yang ceroboh.

Saya bahkan tidak tahu harus memberi saran apa di sini. Jadi saya hanya berharap semua pengembang Amazon Lumberyard memperbaiki kesalahan dan semoga sukses untuk pengembang Igor!

Tempat kelima


Sumber: Sekali lagi, penganalisa PVS-Studio terbukti lebih perhatian daripada seseorang

Sebuah kisah menarik terjadi dengan contoh berikut ini. Rekan saya Andrey Karpov sedang mempersiapkan sebuah artikel tentang pemeriksaan lain dari kerangka kerja Qt. Ketika menulis beberapa kesalahan penting, dia menemukan peringatan penganalisa, yang dia anggap salah. Ini adalah fragmen kode dan peringatan untuk itu:

 QWindowsCursor::CursorState QWindowsCursor::cursorState() { enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; CURSORINFO cursorInfo; cursorInfo.cbSize = sizeof(CURSORINFO); if (GetCursorInfo(&cursorInfo)) { if (cursorInfo.flags & CursorShowing) // <= V616 .... } 

Peringatan PVS-Studio: V616 CWE-480 'CursorShowing' bernama konstan dengan nilai 0 digunakan dalam operasi bitwise. qwindowscursor.cpp 669

Yang berarti, bahwa PVS-Studio mengeluh di tempat itu, yang jelas tidak memiliki kesalahan! Tidak mungkin untuk konstanta CursorShowing menjadi 0 , karena hanya beberapa baris di atas yang diinisialisasi oleh 1 .

Karena Andrey menggunakan versi penganalisis yang tidak stabil, ia mempertanyakan kebenaran peringatan itu. Dia dengan hati-hati memeriksa potongan kode itu dan masih tidak menemukan bug. Dia akhirnya memberikannya positif palsu di bugtracker sehingga kolega lain bisa memperbaiki situasi.

Hanya analisis terperinci yang menunjukkan bahwa PVS-Studio ternyata lebih berhati-hati daripada seseorang lagi. Nilai 0x1 ditetapkan ke konstanta bernama bernama cursorShowing sementara CursorShowing mengambil bagian dalam operasi bitwise "dan". Ini adalah dua konstanta yang sama sekali berbeda, yang pertama dimulai dengan huruf kecil, yang kedua - dengan modal.

Kode berhasil dikompilasi, karena kelas QWindowsCursor benar-benar berisi konstanta dengan nama ini. Inilah definisinya:

 class QWindowsCursor : public QPlatformCursor { public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; .... } 

Jika Anda tidak menetapkan nilai ke konstanta enum secara eksplisit, itu akan diinisialisasi secara default. Karena CursorShowing adalah elemen pertama dalam enumerasi, maka akan diberikan 0 .

Untuk menghindari kesalahan seperti itu, Anda tidak harus memberikan entitas nama yang terlalu mirip. Anda harus mengikuti aturan ini dengan seksama jika entitas memiliki tipe yang sama atau dapat secara implisit dilemparkan satu sama lain. Seperti dalam kasus-kasus seperti itu hampir tidak mungkin untuk melihat kesalahan, tetapi kode yang salah masih akan dikompilasi dan tinggal di jalan yang mudah di dalam proyek Anda.

Tempat keempat


Sumber: Tembak kaki Anda saat memegang data input

Kami semakin dekat dengan tiga finalis teratas dan baris berikutnya adalah kesalahan dari proyek FreeSWITCH.

 static const char *basic_gets(int *cnt) { .... int c = getchar(); if (c < 0) { if (fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) { break; } command_buf[strlen(command_buf)-1] = '\0'; /* remove endline */ break; } .... } 

Peringatan PVS-Studio: V1010 CWE-20 Data tercemar yang tidak dicentang digunakan dalam indeks: 'strlen (command_buf)'.

Penganalisis memperingatkan Anda bahwa beberapa data yang tidak dicentang digunakan dalam strlen ekspresi (command_buf) - 1 . Memang: jika command_buf adalah string kosong dalam hal bahasa C (berisi satu-satunya karakter - '\ 0'), strlen (command_buf) akan mengembalikan 0 . Dalam kasus seperti itu, command_buf [-1] akan diakses, yang merupakan perilaku tidak terdefinisi. Itu buruk!

Semangat sebenarnya dari kesalahan ini bukan mengapa itu terjadi, tetapi bagaimana . Kesalahan ini adalah salah satu contoh terbaik, yang Anda "sentuh" ​​sendiri, buat kembali. Anda dapat menjalankan FreeSwitch, melakukan beberapa tindakan yang akan mengarah pada pelaksanaan fragmen kode yang disebutkan di atas dan meneruskan string kosong ke input program.

Akibatnya, dengan gerakan tangan yang halus, sebuah program kerja berubah menjadi tidak bekerja! Anda dapat menemukan detail tentang cara mereproduksi kesalahan ini di artikel sumber melalui tautan yang diberikan di atas. Sementara itu, izinkan saya memberi Anda hasil yang memberi tahu:



Perlu diingat, bahwa data keluaran bisa berupa apa saja, jadi Anda harus selalu memeriksanya. Dengan cara ini, penganalisa tidak akan mengeluh dan program akan menjadi lebih andal.

Sekarang saatnya pergi untuk pemenang kami: kami berada di endgame sekarang! Ngomong-ngomong, finalis bug sudah menunggu lama, kemudian bosan dan bahkan mulai canggung. Lihat saja apa yang dipentaskan saat kami pergi!



Tempat ketiga


Sumber: NCBI Genome Workbench: Riset Ilmiah di Bawah Ancaman

Cuplikan kode dari proyek NCBI Genome Workbench, yang merupakan seperangkat alat untuk mempelajari dan menganalisis data genetik, membuka 3 pemenang teratas. Meskipun Anda tidak harus menjadi manusia super yang dimodifikasi secara genetik untuk menemukan bug ini, hanya sedikit orang yang tahu tentang kemungkinan untuk membuat kesalahan di sini.

 /** * Crypt a given password using schema required for NTLMv1 authentication * @param passwd clear text domain password * @param challenge challenge data given by server * @param flags NTLM flags from server side * @param answer buffer where to store crypted password */ void tds_answer_challenge(....) { .... if (ntlm_v == 1) { .... /* with security is best be pedantic */ memset(hash, 0, sizeof(hash)); memset(passwd_buf, 0, sizeof(passwd_buf)); ... } else { .... } } 

Peringatan PVS-Studio:

  • V597 Kompiler dapat menghapus pemanggilan fungsi 'memset', yang digunakan untuk membersihkan buffer 'hash'. Fungsi memset_s () harus digunakan untuk menghapus data pribadi. challenge.c 365
  • V597 Kompiler dapat menghapus pemanggilan fungsi 'memset', yang digunakan untuk membersihkan buffer 'passwd_buf'. Fungsi memset_s () harus digunakan untuk menghapus data pribadi. challenge.c 366

Apakah Anda menemukan bug? Jika ya, Anda seorang attaboy! .. atau manusia super yang dimodifikasi secara genetis.

Faktanya adalah bahwa kompiler pengoptimasi modern mampu melakukan banyak hal untuk memungkinkan program yang dibangun bekerja lebih cepat. Termasuk fakta bahwa kompiler sekarang dapat melacak bahwa buffer, diteruskan ke memset , tidak digunakan di tempat lain.

Dalam hal ini, mereka dapat menghapus panggilan memset yang "tidak perlu", memiliki semua hak untuk itu. Kemudian buffer yang menyimpan data penting dapat tetap tersimpan dalam memori untuk menyenangkan para penyerang.

Terhadap latar belakang ini, komentar geek ini "dengan keamanan adalah yang terbaik untuknya" terdengar lebih lucu. Dilihat oleh sejumlah kecil peringatan, diberikan untuk proyek ini, pengembangnya melakukan yang terbaik untuk menjadi tepat dan menulis kode aman. Namun, seperti yang bisa kita lihat, seseorang dapat dengan mudah mengabaikan cacat keamanan tersebut. Menurut Pencacahan Common Weakness, cacat ini diklasifikasikan sebagai CWE-14 : Penghapusan Kompiler Kode ke Hapus Buffer.

Anda harus menggunakan fungsi memset_s () agar deallokasi memori aman. Fungsi ini lebih aman daripada memset () dan tidak dapat diabaikan oleh kompiler.

Tempat kedua


Sumber: Bagaimana PVS-Studio Terbukti Lebih Penuh Perhatian Daripada Tiga Setengah Programer

Seorang peraih medali perak dengan ramah dikirim kepada kami oleh salah satu klien kami. Dia yakin bahwa penganalisa mengeluarkan beberapa positif palsu.

Evgeniy mendapat email, melihat melalui itu dan mengirim ke Svyatoslav. Svyatoslav melihat dari dekat potongan kode, yang dikirim oleh klien dan berpikir: "bagaimana mungkin analisa telah membuat kesalahan besar?". Jadi dia meminta nasihat pada Andrey. Dia juga memeriksa tempat itu dan memutuskan: memang, penganalisa menghasilkan positif palsu.

Begitulah, itu perlu diperbaiki. Hanya setelah Svyatoslav mulai membuat contoh-contoh sintetis untuk membuat tugas di pelacak bug kami, dia mendapatkan apa yang salah.

Tidak ada programmer yang dapat menemukan kesalahan, tetapi mereka benar-benar ada dalam kode. Terus terang, penulis artikel ini juga gagal menemukan mereka meskipun faktanya, penganalisa dengan jelas mengeluarkan peringatan untuk tempat yang salah!

Apakah Anda akan menemukan bug yang licik? Uji diri Anda pada kewaspadaan dan perhatian.


Peringatan PVS-Studio:
  • V560 Bagian dari ekspresi kondisional selalu salah: (ch> = 0x0FF21). decodew.cpp 525
  • V560 Bagian dari ekspresi kondisional selalu benar: (ch <= 0x0FF3A). decodew.cpp 525
  • V560 Bagian dari ekspresi kondisional selalu salah: (ch> = 0x0FF41). decodew.cpp 525
  • V560 Bagian dari ekspresi kondisional selalu benar: (ch <= 0x0FF5A). decodew.cpp 525

Jika Anda melakukannya - pujian untuk Anda!

Kesalahannya terletak pada kenyataan bahwa operator negasi logis (!) Tidak diterapkan pada seluruh kondisi, tetapi hanya sub-ekspresi pertama:

 !((ch >= 0x0FF10) && (ch <= 0x0FF19)) 

Jika kondisi ini benar, nilai variabel ch terletak di kisaran [0x0FF10 ... 0x0FF19]. Dengan demikian, empat perbandingan lebih lanjut sudah tidak ada artinya: mereka akan selalu benar atau salah.

Untuk menghindari kesalahan seperti itu, ada baiknya tetap berpegang pada beberapa aturan. Pertama, sangat mudah dan informatif untuk meluruskan kode seperti tabel. Kedua, Anda tidak harus membebani ekspresi dengan tanda kurung. Misalnya, kode ini dapat ditulis ulang seperti ini:

 const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19) // 0..9 || (ch >= 0x0FF21 && ch <= 0x0FF3A) // A..Z || (ch >= 0x0FF41 && ch <= 0x0FF5A); // a..z if (!isLetterOrDigit) 

Dengan cara ini, akan ada lebih sedikit tanda kurung dan di sisi lain - Anda akan lebih sering melihat kesalahan sesekali.

Di sinilah ceri di atas - mari kita beralih ke tempat pertama!

Tempat pertama


Sumber: Sistem Terkejut: Kesalahan Menarik di Kode Sumber Shock Sistem Legendaris

Finalis top hari ini adalah kesalahan dari System Shock yang legendaris! Ini adalah game yang dirilis cukup lama pada tahun 1994, yang menjadi pendahulu dan inspirasi untuk game ikonik seperti Dead Space, BioShock dan Deus Ex.

Tetapi pertama-tama saya harus mengakui sesuatu. Apa yang akan saya tunjukkan kepada Anda sekarang, tidak mengandung kesalahan. Sebenarnya, itu bahkan bukan sepotong kode, tapi aku tidak bisa membaginya denganmu!

Masalahnya adalah ketika menganalisis kode sumber permainan, kolega saya Victoria menemukan banyak komentar menarik. Dalam fragmen-fragmen yang berbeda, dia menemukan beberapa komentar cerdas dan ironis, dan bahkan puisi.

 // I'll give you fish, I'll give you candy, // I'll give you, everything I have in my hand // that kid from the wrong side came over my house again, // decapitated all my dolls // and if you bore me, you lose your soul to me // - "Gepetto", Belly, _Star_ // And here, ladies and gentlemen, // is a celebration of C and C++ and their untamed passion... // ================== TerrainData terrain_info; // Now the actual stuff... // ======================= // this is all outrageously horrible, as we dont know what // we really need to deal with here // And if you thought the hack for papers was bad, // wait until you see the one for datas... - X // Returns whether or not in the humble opinion of the // sound system, the sample should be politely obliterated // out of existence // it's a wonderful world, with a lot of strange men // who are standing around, and they all wearing towels 

Beginilah komentar-komentar yang ditinggalkan dalam gim oleh pengembang di akhir tahun 90-an seperti ... Ngomong-ngomong, Doug Church - Kepala Perancang System Shock, juga sibuk menulis kode. Siapa tahu, mungkin beberapa komentar ini ditulis olehnya? Berharap, barang-barang pria di-handuk bukanlah hasil karyanya :)

Kesimpulan


Sebagai penutup, saya ingin mengucapkan terima kasih kepada kolega saya karena mencari bug baru dan menulisnya di artikel. Terima kasih kawan! Tanpa Anda, artikel ini tidak akan semenarik itu.

Saya juga ingin menceritakan sedikit tentang pencapaian kami, karena sepanjang tahun kami tidak sibuk dengan hanya mencari kesalahan. Kami juga telah mengembangkan dan meningkatkan alat analisis, yang menghasilkan perubahan signifikan.

Sebagai contoh, kami telah menambahkan dukungan dari beberapa kompiler baru dan memperluas daftar aturan diagnostik. Kami juga telah mengimplementasikan dukungan awal standar MISRA C dan MISRA C ++ . Fitur baru yang paling penting dan memakan waktu adalah dukungan bahasa baru. Ya, kami sekarang dapat menganalisis kode di Jawa ! Dan terlebih lagi, kami memiliki ikon yang diperbarui :)

Saya juga ingin mengucapkan terima kasih kepada pembaca kami. Terima kasih telah membaca artikel kami dan menulis kepada kami! Anda sangat responsif dan Anda sangat penting bagi kami!

10 kesalahan C ++ teratas kami di tahun 2018 telah berakhir. Fragmen apa yang paling Anda sukai dan mengapa? Apakah Anda menemukan beberapa contoh menarik di tahun 2018?

Semua yang terbaik, sampai jumpa lagi!

Source: https://habr.com/ru/post/id444568/


All Articles