10 kesalahan teratas dalam proyek C ++ untuk 2018

Sudah tiga bulan sejak 2018 berakhir. Bagi banyak orang, itu terbang hampir tanpa terasa, tetapi bagi kami, pengembang PVS-Studio, ternyata sangat jenuh. Kami bekerja keras, berjuang tanpa rasa takut untuk kemajuan analisis statis kepada massa dan mencari kesalahan baru dalam proyek sumber terbuka yang ditulis dalam C, C ++, C # dan Java. Sepuluh yang paling menarik dari mereka telah kami kumpulkan untuk Anda di artikel ini!



Kami mencari tempat-tempat menarik menggunakan penganalisis kode statis PVS-Studio . Itu dapat mendeteksi kesalahan dan potensi kerentanan dalam kode yang ditulis dalam bahasa yang disebutkan di atas.

Jika Anda tertarik untuk mencari kesalahan sendiri, Anda selalu dapat mengunduh dan mencoba penganalisa kami. Kami menyediakan versi gratis alat analisis untuk siswa dan programmer yang antusias, lisensi gratis untuk pengembang proyek sumber terbuka, serta versi uji coba untuk semua-semua-semua. Siapa tahu, mungkin tahun depan Anda bisa masuk 10 besar? :)

Catatan: Saya menyarankan agar pembaca memeriksa dirinya sendiri dan, sebelum melihat peringatan penganalisa, cobalah untuk mengidentifikasi anomali itu sendiri. Berapa banyak kesalahan yang bisa Anda temukan?

Tempat kesepuluh


Sumber: Dan lagi ke luar angkasa: bagaimana unicorn Stellarium dikunjungi

Kesalahan ini ditemukan saat memeriksa planetarium virtual Stellarium.

Cuplikan kode di atas, meskipun kecil, penuh dengan kesalahan yang agak rumit:

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

Apakah kamu sudah menemukan?

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

Penulis kode ingin menginisialisasi bagian dari bidang objek menggunakan konstruktor lain yang bersarang di yang utama. Benar, sebagai gantinya, dia hanya berhasil membuat objek sementara yang akan dihancurkan ketika meninggalkan area visibilitasnya. Dengan demikian, beberapa bidang objek akan tetap tidak diinisialisasi.

Alih-alih panggilan konstruktor bersarang, Anda harus menggunakan konstruktor pendelegasian yang diperkenalkan di C ++ 11. Misalnya, Anda bisa melakukan ini:

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

Maka semua bidang yang diperlukan akan diinisialisasi dengan benar. Luar biasa bukan?

Tempat kesembilan


Sumber: Perl 5: Bagaimana Kesalahan Makro Hid

Di tempat kesembilan memamerkan makro penting dari kode sumber Perl 5.

Mengumpulkan kesalahan untuk menulis artikel, kolega saya Svyatoslav menemukan peringatan yang dikeluarkan oleh penganalisa tentang penggunaan makro. Ini dia:

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

Untuk mencari tahu apa masalahnya, 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 mengetahuinya sehingga saya harus menggunakan file preprocessed. Tapi, sayangnya, ini tidak membantu. Di tempat dari baris kode sebelumnya, Svyatoslav menemukan ini:

 (((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 menemukan kesalahan dengan mata saya. Jujur, kami sudah lama merenungkan kode ini dan sampai pada kesimpulan bahwa sebenarnya tidak ada kesalahan di sini. Tetapi bagaimanapun juga, ini adalah contoh kode yang tidak dapat dibaca yang menghibur.

Makro dikatakan jahat. Tentu saja, ada saatnya mereka menjadi sangat diperlukan, tetapi jika Anda dapat mengganti makro dengan suatu fungsi, Anda harus melakukannya.

Makro bersarang sangat penuh. Bukan hanya karena mereka sulit dipahami, tetapi juga karena mereka dapat memberikan hasil yang tidak terduga. Jika penulis makro secara tidak sengaja membuat kesalahan dalam makro seperti itu, akan jauh lebih sulit untuk menemukannya daripada dalam suatu fungsi.

Tempat kedelapan


Sumber: Chromium: Kesalahan Lainnya

Contoh berikut diambil dari serangkaian artikel tentang analisis proyek Chromium. Dia menutupi dirinya 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 perubahan format vektor di dalam rentang-berdasarkan-untuk loop. Lingkaran berbasis rentang didasarkan pada iterator, jadi mengubah ukuran wadah di dalam loop tersebut dapat menyebabkan pembatalan iterator ini.

Kesalahan ini akan tetap ada jika Anda menulis ulang loop menggunakan iterators eksplisit. Karena itu, untuk kejelasan, Anda dapat membawa kode ini:

 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 , sebuah vektor dapat dilepaskan - dan iterator akan menunjuk ke area memori yang tidak valid.

Untuk menghindari kesalahan seperti itu, Anda harus mematuhi aturan: jangan pernah mengubah ukuran kontainer di dalam loop, yang kondisinya terkait dengan wadah ini. Ini berlaku untuk loop berbasis rentang dan loop menggunakan iterator. Anda dapat membaca tentang operasi apa yang dapat menyebabkan pembatalan iterator dalam diskusi tentang StackOverflow.

Tempat ketujuh


Sumber: Godot: Penggunaan Regulator Kode Statis Biasa

Contoh pertama dari industri gim video adalah cuplikan kode yang kami temukan di mesin gim Godot. Anda mungkin harus berkeringat untuk menemukan kesalahan dengan mata Anda, tetapi saya yakin pembaca kami yang canggih dapat 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

Pertimbangkan kondisi siklus secara lebih rinci. Variabel penghitung diinisialisasi dengan nilai blend_points_used - 1 . Pada saat yang sama, berdasarkan pada dua pemeriksaan sebelumnya (dalam ERR_FAIL_COND dan jika ), menjadi jelas bahwa pada saat loop dieksekusi, blend_points_used akan selalu lebih besar daripada p_at_index . Dengan demikian, kondisi loop akan selalu benar, atau loop tidak akan dieksekusi sama sekali.

Jika blend_points_used adalah 1 == p_at_index , maka loop tidak dieksekusi.

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

Tampaknya siklus itu akan berjalan selamanya, tetapi ternyata tidak.

Pertama, akan ada integer overflow dari variabel i , yang merupakan perilaku tidak terdefinisi. Oleh karena itu, mengandalkan ini tidak layak.

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

Itu dulu, tapi masih ada yang kedua! Faktanya adalah bahwa ia bahkan tidak akan mencapai integer overflow. Di mana sebelum array pergi ke luar negeri. Ini berarti bahwa suatu upaya akan dilakukan untuk mengakses area memori di luar blok yang dialokasikan untuk array. Dan ini juga merupakan perilaku yang tidak jelas. Contoh klasik :)

Untuk membuatnya lebih mudah menghindari kesalahan seperti itu, saya hanya bisa memberikan beberapa rekomendasi:

  1. Tulis kode yang lebih sederhana, lebih intuitif
  2. Lakukan Tinjauan Kode yang lebih menyeluruh dan tulis lebih banyak tes untuk kode yang baru ditulis
  3. Gunakan analisis statis;)


Tempat keenam


Sumber: Amazon Lumberyard: The Cry of the Soul

Contoh lain dari industri gamedev, yaitu, dari kode sumber mesin Amazon Lumberyard AAA.

 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' setara dengan pernyataan 'else'. toglsloperand.c 700

Amazon Lumberyard sedang dikembangkan sebagai mesin lintas platform. Oleh karena itu, pengembang berusaha mendukung sebanyak mungkin penyusun. Programmer Igor berlari ke dalam kompiler Qualcomm, seperti yang dikatakan oleh komentar.

Tidak diketahui apakah Igor dapat menyelesaikan tugasnya dan mengatasi pemeriksaan "paranoid" dari kompiler, tetapi ia meninggalkan kode yang sangat aneh. Sungguh aneh bahwa keduanya - dan selain itu - cabang pernyataan if berisi kode yang benar-benar identik. Kemungkinan besar, kesalahan seperti itu dibuat sebagai akibat dari Copy-Paste yang ceroboh.

Saya bahkan tidak tahu apa yang bisa disarankan di sini. Oleh karena itu, saya hanya berharap pengembang Amazon Lumberyard berhasil memperbaiki bug, dan semoga sukses untuk programmer Igor!

Tempat kelima


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

Sebuah kisah menarik terjadi dengan contoh berikut ini. Rekan saya Andrei Karpov sedang mempersiapkan sebuah artikel tentang tes kerangka Qt berikutnya. Dalam proses penulisan kesalahan yang patut dicatat, dia menemui peringatan penganalisa, yang dia anggap salah. Berikut ini cuplikan dan peringatan kode yang relevan:

 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' dinamai konstan dengan nilai 0 digunakan dalam operasi bitwise. qwindowscursor.cpp 669

Yaitu, PVS-Studio bersumpah di tempat di mana, jelas, tidak ada kesalahan! Tidak mungkin konstanta CursorShowing adalah 0 , karena secara harfiah beberapa baris di atas diinisialisasi ke 1 .

Karena versi analisa yang tidak stabil digunakan untuk verifikasi, Andrei meragukan kebenaran peringatan itu. Dia dengan hati-hati memeriksa bagian kode ini beberapa kali, dan masih tidak menemukan kesalahan. Alhasil, ia menulis false positive ini ke bugtracker sehingga rekan-rekan lainnya bisa memperbaiki situasi.

Dan hanya dengan analisis terperinci menjadi jelas bahwa PVS-Studio sekali lagi lebih perhatian daripada seseorang. Nilai 0x1 ditugaskan ke cursorShowing konstanta bernama, dan operasi konstanta bit “dan” melibatkan konstanta CursorShowing bernama. Ini adalah konstanta yang sama sekali berbeda, karena yang pertama dimulai dengan huruf kecil, dan yang kedua dengan huruf kapital.

Kode berhasil dikompilasi, karena kelas QWindowsCursor benar-benar berisi konstanta dengan nama itu. Berikut adalah definisinya:

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

Jika Anda tidak secara eksplisit menetapkan enum konstan, ini akan diinisialisasi secara default. Karena CursorShowing adalah elemen pertama dari enumerasi, itu akan diatur ke 0 .

Untuk mencegah kesalahan seperti itu, Anda tidak boleh memberikan entitas nama yang terlalu mirip. Anda harus secara khusus mengikuti aturan ini jika entitas-entitas ini memiliki tipe yang sama atau dapat secara implisit saling melemparkan. Memang, dalam kasus seperti itu hampir tidak mungkin untuk mendeteksi kesalahan dengan mata, dan kode yang salah akan berhasil dikompilasi dan hidup bahagia di dalam proyek Anda.

Tempat keempat


Sumber: Kami menembak di kaki, memproses data input

Kami mendekati tiga finalis teratas, dan kesalahan dari proyek FreeSWITCH selanjutnya adalah pada gilirannya.

 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 bahwa strlen ekspresi (command_buf) - 1 menggunakan data yang tidak diverifikasi. Dan sungguh: jika command_buf ternyata kosong dari sudut pandang string bahasa C (mengandung karakter tunggal - '\ 0') maka strlen (command_buf) akan mengembalikan 0 . Dalam hal ini, command_buf [-1] akan dipanggil , yang mewakili perilaku tidak terdefinisi. Kesulitan!

Inti kesalahan ini bukanlah mengapa itu terjadi, tetapi bagaimana itu terjadi. Kesalahan ini adalah salah satu contoh menyenangkan yang dapat Anda "sentuh" ​​sendiri, buat kembali. Anda dapat memulai FreeSwitch, melakukan beberapa tindakan yang akan mengarah pada pelaksanaan bagian kode di atas, dan meneruskan program baris kosong untuk input.

Alhasil, dengan gerakan pergelangan tangan, program kerja berubah (tidak, bukan celana pendek elegan ) menjadi tidak berfungsi! Detail tentang cara mereproduksi kesalahan ini dapat ditemukan di artikel sumber di tautan di atas, tetapi untuk saat ini saya akan memberikan hasil yang jelas:



Ingat bahwa input dapat berupa apa saja, dan Anda harus selalu memeriksanya. Maka analisa tidak akan bersumpah, dan program akan lebih dapat diandalkan.

Sekarang saatnya berurusan dengan pemenang kami: kami akan pindah ke final!



Tempat ketiga


Sumber: NCBI Genome Workbench: Endangered Research

Tiga pemenang dibuka oleh sepotong kode dari proyek NCBI Genome Workbench - seperangkat alat untuk mempelajari dan menganalisis data genetik. Meskipun tidak perlu menjadi seorang superman yang dimodifikasi secara genetik untuk menemukan kesalahan di sini, beberapa orang menyadari kemungkinan ini.

 /** * 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

Berhasil menemukan kesalahan? Jika demikian, maka Anda - berhasil! .. baik, atau masih seorang superman yang dimodifikasi secara genetik.

Faktanya adalah bahwa kompiler optimisasi modern dapat melakukan banyak hal untuk membuat program yang dirakit bekerja lebih cepat. Khususnya, kompiler dapat melacak bahwa buffer yang diteruskan ke memset tidak digunakan di tempat lain.

Dalam hal ini, mereka dapat menghapus panggilan memset "tidak perlu", dan berhak untuk melakukannya. Kemudian buffer yang menyimpan data penting dapat tetap tersimpan dalam memori untuk menyenangkan penyerang.

Terhadap latar belakang ini, komentar melek “dengan keamanan bagus untuk menjadi bertele-tele” terlihat lebih lucu. Dilihat dari sedikitnya peringatan yang dikeluarkan untuk proyek ini, para pengembang berusaha sangat keras untuk berhati-hati dan menulis kode yang aman. Namun, seperti yang dapat kita lihat, melewatkan kelemahan keamanan ini sangat sederhana. Menurut Common Weakness Enumeration, cacat diklasifikasikan sebagai CWE-14 : Penghapusan Kode Kompiler ke Hapus Buffer.

Untuk menghapus pembersihan memori, gunakan fungsi memset_s () . Ini tidak hanya lebih aman daripada memset () , tetapi juga tidak dapat "diabaikan" oleh kompiler.

Tempat kedua


Sumber: Bagaimana PVS-Studio ternyata lebih penuh perhatian daripada tiga setengah programmer

Peraih medali perak top ini dikirim kepada kami oleh salah satu pelanggan kami. Dia yakin bahwa penganalisa menghasilkan peringatan palsu.

Eugene menerima surat itu, memindai sebentar, dan mengirimkannya ke Svyatoslav. Svyatoslav merenungkan bagian kode yang dikirim oleh klien, dan berpikir, "Apakah alat analisis itu bisa keliru?" Karena itu, ia berkonsultasi dengan Andrei. Dia juga memeriksa situs tersebut dan memutuskan: memang, penganalisa memberikan positif palsu.

Apa yang bisa Anda lakukan, Anda harus memperbaikinya. Dan hanya ketika Svyatoslav mulai membuat contoh-contoh sintetis untuk memformalkan tugas sebagai bugtracker, dia menyadari apa yang terjadi.

Kesalahan memang ada dalam kode, tetapi tidak satu pun programmer dapat mendeteksi mereka. Jujur saja, penulis artikel ini juga tidak berhasil.

Dan ini terlepas dari kenyataan bahwa penganalisa dengan jelas mengeluarkan peringatan untuk tempat yang salah!

Bisakah Anda menemukan kesalahan licik seperti itu? Uji diri Anda untuk 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 berhasil - Anda tidak akan menghargai saya!

Kesalahannya terletak pada kenyataan bahwa operator negasi logis (!) Tidak berlaku untuk seluruh kondisi, tetapi hanya untuk subekspresi pertamanya:

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

Jika kondisi ini terpenuhi, maka nilai variabel ch terletak pada interval [0x0FF10 ... 0x0FF19]. Jadi, empat perbandingan lebih lanjut tidak lagi masuk akal: mereka akan selalu benar atau salah.

Untuk menghindari kesalahan seperti itu, ada baiknya mengikuti beberapa aturan. Pertama, sangat mudah dan jelas untuk menyelaraskan kode dengan sebuah tabel. Kedua, jangan 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) 

Kemudian, pertama, jumlah kurung menjadi jauh lebih kecil, dan kedua, probabilitas "menangkap" kesalahan yang dibuat oleh mata meningkat.

Dan sekarang - ceri: kita pindah ke tempat pertama!

Tempat pertama


Sumber: System in shock: kesalahan menarik dalam kode sumber dari System Shock yang legendaris

Jadi, finalis top kita hari ini adalah kesalahan dari System Shock yang legendaris! Game ini, dirilis pada tahun 1994, menjadi nenek moyang dan inspirator dari 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. Pada umumnya, ini bahkan bukan cuplikan kode, tapi saya tidak bisa menahan untuk tidak membagikan ini kepada Anda!

Faktanya adalah bahwa dalam proses menganalisis kode sumber permainan, kolega saya Victoria menemukan banyak komentar menarik. Di sana-sini tiba-tiba ada komentar bercanda dan ironis, dan bahkan ayat:

 // 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 

Untuk pembaca kami yang berbahasa Rusia, saya membuat perkiraan terjemahan gratis:
 //    ,    , //    ,       //      //      //     //     ,      // - "Gepetto", Belly, _Star_ //  ,   , //    C  C++     // ================== TerrainData terrain_info; //    ... // ======================= //    ,     , //         //    ,          //      ,      ... - X //       , //         //   ,     //   ,     

Komentar-komentar ini ditinggalkan oleh para pengembang game di awal tahun sembilan puluhan ... Ngomong-ngomong, Gereja Doug - desainer kepala System Shock - juga menulis kode. Siapa tahu, mungkin salah satu dari komentar ini ditulis olehnya secara pribadi? Saya berharap bahwa tentang laki-laki di handuk - ini bukan urusannya :)

Kesimpulan


Sebagai penutup, saya ingin mengucapkan terima kasih kepada kolega saya karena mencari kesalahan baru dan menulis artikel tentang mereka. Terima kasih teman-teman! Tanpa Anda, artikel ini tidak akan begitu menarik.

Saya juga ingin berbicara sedikit tentang pencapaian kami, karena selama setahun kami telah terlibat dalam lebih dari sekedar mencari kesalahan. Kami juga mengembangkan dan meningkatkan alat analisis, yang hasilnya mengalami perubahan signifikan.

Sebagai contoh, kami menambahkan dukungan untuk beberapa kompiler baru dan memperluas daftar aturan diagnostik. Kami juga memberikan dukungan awal untuk standar MISRA C dan MISRA C ++ . Inovasi yang paling penting dan memakan waktu adalah dukungan bahasa baru. Ya, sekarang kita dapat menganalisis kode di Jawa ! Dan kami telah memperbarui ikonnya:)

Juga saya ingin mengucapkan terima kasih kepada pembaca kami. Terima kasih telah membaca artikel kami dan menulis kepada kami! Umpan balik Anda sangat menyenangkan dan penting bagi kami.

Tentang ini, 10 kesalahan C ++ teratas kami untuk tahun 2018 berakhir. Tempat mana yang paling Anda sukai dan mengapa? Apakah Anda menemukan contoh menarik di tahun 2018? Ceritakan pada kami di komentar!

Sampai waktu berikutnya!



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: George Gribkov. 10 bug teratas dari proyek C ++ ditemukan pada 2018

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


All Articles