Algoritma Copy-Paste Terbaik untuk C dan C ++. Haiku OS Cookbook

Banyak kesalahan ketik dan kode Salin-Tempel menjadi topik utama artikel tambahan tentang memeriksa kode Haiku oleh penganalisa PVS-Studio. Namun artikel ini sebagian besar menceritakan tentang kesalahan yang berkaitan dengan kesembronoan dan kegagalan refactoring, daripada kesalahan ketik. Kesalahan yang ditemukan menunjukkan seberapa kuat faktor manusia dalam pengembangan perangkat lunak.

Gambar 1

Pendahuluan


Haiku adalah sistem operasi open source gratis untuk komputer pribadi. Tim pengembangan internasional saat ini sedang mengerjakan komponen-komponen sistem. Porting Libre Office di OS dan rilis R1 Beta 1 pertama menonjol di antara peningkatan pengembangan signifikan baru-baru ini.

Tim pengembang dari PVS-Studio mengikuti pengembangan proyek ini sejak 2015 dan memposting ulasan tentang kerusakan kode. Ini adalah ulasan keempat sepanjang masa. Anda dapat membaca artikel sebelumnya dengan tautan ini:

  1. Analisis Sistem Operasi Haiku (BeOS Family), oleh PVS-Studio, Bagian 1 ;
  2. Analisis Sistem Operasi Haiku (BeOS Family) oleh PVS-Studio. Bagian 2 ;
  3. Cara menembak diri Anda di kaki di C dan C ++. Buku masak Haiku OS

Fitur dari analisis kode terakhir adalah kemampuan untuk menggunakan versi resmi PVS-Studio untuk Linux. Baik PVS-Studio untuk Linux, maupun laporan yang nyaman untuk melihat kesalahan tidak tersedia pada tahun 2015. Kali ini kami akan mengirimkan laporan lengkap dalam format yang mudah ke pengembang Haiku.

Klasik


V501 Ada sub-ekspresi identik ke kiri dan ke kanan operator '-': (addr_t) b - (addr_t) b BitmapManager.cpp 51

int compare_app_pointer(const ServerApp* a, const ServerApp* b) { return (addr_t)b - (addr_t)b; } 

Setiap pengembang harus mencampur variabel a dan b , x dan y , i dan j ... setidaknya sekali dalam hidupnya.

V501 Ada sub-ekspresi identik ke kiri dan ke kanan '||' operator: input == __null || input == __null MediaClient.cpp 182

 status_t BMediaClient::Unbind(BMediaInput* input, BMediaOutput* output) { CALLED(); if (input == NULL || input == NULL) return B_ERROR; if (input->fOwner != this || output->fOwner != this) return B_ERROR; input->fBind = NULL; output->fBind = NULL; return B_OK; } 

Input pointer yang sama diperiksa dalam kondisi dua kali. Sedangkan pointer output tetap tidak dicentang, yang dapat menyebabkan dereferensi pointer nol.

Kode tetap:

 if (input == NULL || output == NULL) return B_ERROR; 

V583 Operator '?:', Terlepas dari ekspresi kondisionalnya, selalu mengembalikan satu dan nilai yang sama: 500000. usb_modeswitch.cpp 361
 static status_t my_transfer_data(....) { .... do { bigtime_t timeout = directionIn ? 500000 : 500000; result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, timeout); .... } while (result == B_INTERRUPTED); .... } 

Operator ternary menjadi sia-sia, ketika pembuat kode melakukan kesalahan dan menulis dua nilai balik yang identik - 500000 .

V519 Variabel 'm_kindex1' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 40, 41. agg_trans_double_path.cpp 41

 trans_double_path::trans_double_path() : m_kindex1(0.0), m_kindex2(0.0), m_base_length(0.0), m_base_height(1.0), m_status1(initial), m_status2(initial), m_preserve_x_scale(true) { } void trans_double_path::reset() { m_src_vertices1.remove_all(); m_src_vertices2.remove_all(); m_kindex1 = 0.0; m_kindex1 = 0.0; m_status1 = initial; m_status2 = initial; } 

Ada kesalahan dalam fungsi reset : kesalahan ketik dalam indeks variabel m_kindex2 . Variabel ini tidak akan direset, yang mungkin akan mempengaruhi eksekusi fragmen kode lainnya.

V501 Ada sub-ekspresi identik ke kiri dan ke kanan operator '>': fg [order_type :: R]> fg [order_type :: R] agg_span_image_filter_rgba.h 898

 typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; void generate(color_type* span, int x, int y, unsigned len) { .... if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; if(fg[order_type::R] > fg[order_type::R])fg[order_type::R] = fg[order_type::R]; if(fg[order_type::G] > fg[order_type::G])fg[order_type::G] = fg[order_type::G]; if(fg[order_type::B] > fg[order_type::B])fg[order_type::B] = fg[order_type::B]; .... } 

Di baris terakhir, ada dua masalah sekaligus: perbandingan dan penugasan variabel yang sama. Saya bahkan tidak bisa menyarankan apa gagasan penulis itu. Saya hanya akan melihat cuplikan ini mencurigakan.

V570 Variabel 'wPipeIndex' ditugaskan untuk dirinya sendiri. CEchoGals_transport.cpp 244

 ECHOSTATUS CEchoGals::CloseAudio (....) { .... wPipeIndex = wPipeIndex; m_ProcessId[ wPipeIndex ] = NULL; m_Pipes[ wPipeIndex ].wInterleave = 0; .... } 

Variabel wPipeIndex diinisialisasi dengan nilainya sendiri. Kemungkinan besar, kesalahan ketik dibuat.

Kesalahan dengan pointer


V522 Dereferencing dari pointer nol 'currentInterface' mungkin terjadi. Device.cpp 258

 Device::Device(....) : .... { .... usb_interface_info* currentInterface = NULL; // <= uint32 descriptorStart = sizeof(usb_configuration_descriptor); while (descriptorStart < actualLength) { switch (configData[descriptorStart + 1]) { .... case USB_DESCRIPTOR_ENDPOINT: { .... if (currentInterface == NULL) // <= break; currentInterface->endpoint_count++; .... } .... case USB_DESCRIPTOR_ENDPOINT_COMPANION: { usb_endpoint_descriptor* desc = currentInterface // <= ->endpoint[currentInterface->endpoint_count - 1].descr; .... } .... } 

Pointer currentInterface awalnya diinisialisasi dengan nol dan kemudian diperiksa ketika masuk dalam cabang-cabang operator switch , tetapi tidak dalam semua kasus. Penganalisa memperingatkan bahwa ketika melompat ke label kasus USB_DESCRIPTOR_ENDPOINT_COMPANION , dereference pointer nol mungkin terjadi.

V522 Dereferencing 'direktori' penunjuk nol mungkin terjadi. PathMonitor.cpp 1465

 bool PathHandler::_EntryCreated(....) { .... Directory* directory = directoryNode->ToDirectory(); if (directory == NULL) { // We're out of sync with reality. if (!dryRun) { if (Entry* nodeEntry = directory->FirstNodeEntry()) { .... } } return false; } .... } 

Saya pikir, ada kesalahan dalam kondisi perbandingan pointer direktori dengan nilai nol; syaratnya harus sebaliknya. Dengan implementasi saat ini, jika variabel dryRun salah , penunjuk null direktori akan ditinjau ulang.

V522 Dereferencing dari 'input' pointer nol mungkin terjadi. MediaRecorder.cpp 343

 void GetInput(media_input* input); const media_input& BMediaRecorder::MediaInput() const { CALLED(); media_input* input = NULL; fNode->GetInput(input); return *input; } 

Input pointer diinisialisasi dengan nol dan tetap dengan nilai seperti itu, karena pointer tidak berubah dalam fungsi GetInput. Dalam metode lain dari kelas BMediaRecorder , implementasinya berbeda, misalnya:

 status_t BMediaRecorder::_Connect(....) { .... // Find our Node's free input media_input ourInput; fNode->GetInput(&ourInput); // <= .... } 

Semua sudah benar di sini, tetapi fragmen pertama harus ditulis ulang, jika tidak fungsi akan mengembalikan referensi ke objek lokal.

V522 Dereferencing dari null pointer 'mustFree' mungkin terjadi. RequestUnflattener.cpp 35

 status_t Reader::Read(int32 size, void** buffer, bool* mustFree) { if (size < 0 || !buffer || mustFree) // <= return B_BAD_VALUE; if (size == 0) { *buffer = NULL; *mustFree = false; // <= return B_OK; } .... } 

Dalam ekspresi bersyarat di mana semua data yang salah diperiksa, penulis membuat kesalahan ketik saat memeriksa pointer mustFree . Kemungkinan besar, fungsi harus keluar ketika memiliki nilai nol dari pointer ini:

 if (size < 0 || !buffer || !mustFree) // <= return B_BAD_VALUE; 

V757 Ada kemungkinan bahwa variabel yang salah dibandingkan dengan nullptr setelah konversi jenis menggunakan 'dynamic_cast'. Periksa baris: 474, 476. recover.cpp 474

 void checkStructure(Disk &disk) { .... Inode* missing = gMissing.Get(run); dir = dynamic_cast<Directory *>(missing); if (missing == NULL) { .... } .... } 

Pengembang seharusnya memeriksa pointer dir alih-alih hilang setelah konversi tipe. Omong-omong, pengembang C # juga sering membuat kesalahan serupa. Ini membuktikan sekali lagi bahwa beberapa kesalahan tidak bergantung pada bahasa yang digunakan.

Beberapa tempat lebih mirip dalam kode:

  • V757 Ada kemungkinan bahwa variabel yang salah dibandingkan dengan nullptr setelah konversi jenis menggunakan 'dynamic_cast'. Periksa baris: 355, 357. ExpandoMenuBar.cpp 355
  • V757 Ada kemungkinan bahwa variabel yang salah dibandingkan dengan nullptr setelah konversi jenis menggunakan 'dynamic_cast'. Periksa baris: 600, 601. ValControl.cpp 600

Kesalahan indeks


V557 Array overrun dimungkinkan. Indeks 'BT_SCO' menunjuk di luar batas array. h2upper.cpp 75

 struct bt_usb_dev { .... struct list nbuffersTx[(1 + 1 + 0 + 0)]; // <= [0..1] .... } typedef enum { BT_COMMAND = 0, BT_EVENT, BT_ACL, BT_SCO, // <= 3 BT_ESCO, HCI_NUM_PACKET_TYPES } bt_packet_t; void sched_tx_processing(bt_usb_dev* bdev) { .... if (!list_is_empty(&bdev->nbuffersTx[BT_SCO])) { // <= fail // TODO to be implemented } .... } 

Array bdev-> nbuffersTx hanya terdiri dari 2 elemen, tetapi itu ditangani oleh konstanta BT_SCO, yaitu 3. Di sinilah indeks array pasti keluar dari batas.

V557 Array overrun dimungkinkan. Fungsi 'ieee80211_send_setup' memproses nilai '16'. Periksa argumen keempat. Periksa baris: 842, 911. ieee80211_output.c 842

 struct ieee80211_node { .... struct ieee80211_tx_ampdu ni_tx_ampdu[16]; // <= [0..15] .... }; #define IEEE80211_NONQOS_TID 16 int ieee80211_mgmt_output(....) { .... ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, // <= 16 vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); .... } void ieee80211_send_setup( struct ieee80211_node *ni, struct mbuf *m, int type, int tid, // <= 16 ....) { .... tap = &ni->ni_tx_ampdu[tid]; // <= 16 .... } 

Indeks array lain di luar batas. Kali ini, hanya dengan satu elemen. Analisis antar prosedur membantu mengungkap kasus ketika array ni-> ni_tx_ampdu , yang terdiri dari 16 elemen ditangani oleh indeks 16. Dalam array C dan C ++ diindeks dari nol.

V781 Nilai dari variabel 'vektor' diperiksa setelah digunakan. Mungkin ada kesalahan dalam logika program. Periksa baris: 802, 805. oce_if.c 802

 #define OCE_MAX_EQ 32 typedef struct oce_softc { .... OCE_INTR_INFO intrs[OCE_MAX_EQ]; .... } OCE_SOFTC, *POCE_SOFTC; static int oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) { POCE_INTR_INFO ii = &sc->intrs[vector]; int rc = 0, rr; if (vector >= OCE_MAX_EQ) return (EINVAL); .... } 

Penganalisa telah mendeteksi bahwa elemen array sc-> intrs dialamatkan oleh indeks yang tidak valid, yang di luar batas. Alasannya adalah urutan operasi yang salah dalam kode. Pertama, elemen tersebut dialamatkan dan kemudian muncul pemeriksaan apakah nilai indeks valid.

Beberapa orang mungkin mengatakan tidak akan ada masalah. Itu tidak menghapus nilai elemen array, itu hanya mengambil alamat sel. Tapi tidak, itu bukan cara untuk melakukan sesuatu. Baca selengkapnya: " Null Pointer Dereferencing Penyebab Perilaku Tidak Terdefinisi ".

V519 Variabel ini diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 199, 200. nvme_ctrlr.c 200

 static void nvme_ctrlr_set_intel_supported_features(struct nvme_ctrlr *ctrlr) { bool *supported_feature = ctrlr->feature_supported; supported_feature[NVME_INTEL_FEAT_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_NATIVE_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_POWER_GOVERNOR_SETTING] = true; supported_feature[NVME_INTEL_FEAT_SMBUS_ADDRESS] = true; supported_feature[NVME_INTEL_FEAT_LED_PATTERN] = true; supported_feature[NVME_INTEL_FEAT_RESET_TIMED_WORKLOAD_COUNTERS] = true; supported_feature[NVME_INTEL_FEAT_LATENCY_TRACKING] = true; } 

Elemen array dengan indeks NVME_INTEL_FEAT_MAX_LBA diberi nilai yang sama. Berita baiknya adalah fungsi ini menyajikan semua konstanta yang memungkinkan yang menjadikan kode ini hanya hasil dari pemrograman Copy-Paste. Tetapi kemungkinan kesalahan akan menyelinap di sini.

V519 Variabel 'CopyPath [len]' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 92, 93. kernel_emu.cpp 93

 int UserlandFS::KernelEmu::new_path(const char *path, char **copy) { .... // append a dot, if desired if (appendDot) { copiedPath[len] = '.'; copiedPath[len] = '\0'; } .... } 

Nah, di sini programmer mendapat nasib buruk dengan menyalin. Simbol "dot" ditambahkan ke baris dan ditulis ulang dengan terminal nol. Sangat mungkin, penulis hanya menyalin garis dan lupa untuk menambah indeks.

Kondisi aneh


V517 Penggunaan pola 'jika (A) {...} else jika (A) {...}' terdeteksi. Ada kemungkinan kehadiran kesalahan logis. Periksa baris: 1407, 1410. FindPanel.cpp 1407

 void FindPanel::BuildAttrQuery(BQuery* query, bool &dynamicDate) const { .... case B_BOOL_TYPE: { uint32 value; if (strcasecmp(textControl->Text(), "true") == 0) { value = 1; } else if (strcasecmp(textControl->Text(), "true") == 0) { value = 1; } else value = (uint32)atoi(textControl->Text()); value %= 2; query->PushUInt32(value); break; } .... } 

Menyalin kode menyebabkan dua kesalahan sekaligus. Ekspresi bersyarat identik. Kemungkinan besar, perbandingan dengan string "false" dan bukan "true" harus ada di salah satunya. Lebih jauh di cabang yang menangani nilai "false", nilai yang harus diubah dari 1 ke 0 . Algoritme mensyaratkan bahwa nilai-nilai lain, berbeda dari benar atau salah dikonversi dalam angka menggunakan fungsi atoi . Tetapi karena kesalahan, teks "false" akan masuk ke fungsi.

Ekspresi V547 'error == ((int) 0)' selalu benar. Directory.cpp 688

 int32 BDirectory::CountEntries() { status_t error = Rewind(); if (error != B_OK) return error; int32 count = 0; BPrivate::Storage::LongDirEntry entry; while (error == B_OK) { if (GetNextDirents(&entry, sizeof(entry), 1) != 1) break; if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0) count++; } Rewind(); return (error == B_OK ? count : error); } 

Penganalisa mendeteksi bahwa nilai variabel kesalahan akan selalu menjadi B_OK . Paling pasti, modifikasi variabel ini tidak terjawab di loop sementara .

V564 Operator '&' diterapkan pada nilai tipe bool. Anda mungkin lupa menyertakan tanda kurung atau bermaksud menggunakan operator '&&'. strtod.c 545

 static int lo0bits(ULong *y) { int k; ULong x = *y; .... if (!(x & 1)) { k++; x >>= 1; if (!x & 1) // <= return 32; } *y = x; return k; } 

Kemungkinan besar bahwa dalam ekspresi bersyarat yang terakhir seseorang lupa menempatkan tanda kurung, seperti pada kondisi di atas. Operator pelengkap cenderung berada di luar kurung:

 if (!(x & 1)) // <= return 32; 

V590 Pertimbangkan untuk memeriksa ungkapan ini. Ekspresi berlebihan atau mengandung kesalahan cetak. PoseView.cpp 5851

 bool BPoseView::AttributeChanged(const BMessage* message) { .... result = poseModel->OpenNode(); if (result == B_OK || result != B_BUSY) break; .... } 

Ini tidak jelas, tetapi hasil dari kondisi tidak tergantung pada nilai nilai B_OK. Jadi bisa disederhanakan:

 If (result != B_BUSY) break; 

Anda dapat dengan mudah memeriksanya dengan menggambar tabel kebenaran untuk nilai-nilai variabel hasil . Jika seseorang ingin secara khusus mempertimbangkan nilai-nilai lain, berbeda dari B_OK dan B_BUSY , kode harus ditulis ulang dengan cara lain.

Dua fragmen serupa:

  • V590 Pertimbangkan untuk memeriksa ungkapan ini. Ekspresi berlebihan atau mengandung kesalahan cetak. Tracker.cpp 1714
  • V590 Pertimbangkan untuk memeriksa ungkapan ini. Ekspresi berlebihan atau mengandung kesalahan cetak. if_ipw.c 1871

V590 Pertimbangkan memeriksa 'argc == 0 || argc! = 2 ekspresi. Ekspresi berlebihan atau mengandung kesalahan cetak. cmds.c 2667

 void unsetoption(int argc, char *argv[]) { .... if (argc == 0 || argc != 2) { fprintf(ttyout, "usage: %s option\n", argv[0]); return; } .... } 

Ini mungkin contoh paling sederhana yang menunjukkan kerja diagnostik V590 . Anda perlu menampilkan deskripsi program jika tidak ada argumen yang lulus, atau tidak ada dua. Jelas, nilai apa pun selain dua, termasuk nol, tidak akan memenuhi kondisi tersebut. Oleh karena itu, kondisi dapat disederhanakan dengan aman sebagai berikut:

 if (argc != 2) { fprintf(ttyout, "usage: %s option\n", argv[0]); return; } 

V590 Pertimbangkan untuk memeriksa '* ptr =='; ' && * ptr! = '\ 0' 'ekspresi. Ekspresi berlebihan atau mengandung kesalahan cetak. pc.c 316

 ULONG parse_expression(char *str) { .... ptr = skipwhite(ptr); while (*ptr == SEMI_COLON && *ptr != '\0') { ptr++; if (*ptr == '\0') continue; val = assignment_expr(&ptr); } .... } 

Dalam contoh ini, operator logis diubah, tetapi logikanya masih sama. Di sini kondisi loop sementara hanya bergantung pada apakah karakternya sama dengan SEMI_COLON atau tidak.

V590 Pertimbangkan untuk memeriksa ungkapan ini. Ekspresi berlebihan atau mengandung kesalahan cetak. writembr.cpp 99

 int main(int argc, char** argv) { .... string choice; getline(cin, choice, '\n'); if (choice == "no" || choice == "" || choice != "yes") { cerr << "MBR was NOT written" << endl; fs.close(); return B_ERROR; } .... } 

Sudah ada tiga kondisi dalam contoh ini. Itu juga dapat disederhanakan sebelum memeriksa apakah pengguna telah memilih "ya" atau tidak:

 if (choice != "yes") { cerr << "MBR was NOT written" << endl; fs.close(); return B_ERROR; } 

Lain-lain


V530 Nilai balik fungsi 'mulai' diperlukan untuk digunakan. IMAPFolder.cpp 414

 void IMAPFolder::RegisterPendingBodies(...., const BMessenger* replyTo) { .... IMAP::MessageUIDList::const_iterator iterator = uids.begin(); for (; iterator != uids.end(); iterator++) { if (replyTo != NULL) fPendingBodies[*iterator].push_back(*replyTo); else fPendingBodies[*iterator].begin(); // <= } } 

Penganalisa menemukan panggilan tidak berguna dari iterator begin (). Saya tidak bisa membayangkan bagaimana cara memperbaiki kode. Pengembang harus memperhatikan kode ini.

V609 Bagilah dengan nol. Kisaran penyebut [0..64]. UiUtils.cpp 544

 static int32 GetSIMDFormatByteSize(uint32 format) { switch (format) { case SIMD_RENDER_FORMAT_INT8: return sizeof(char); case SIMD_RENDER_FORMAT_INT16: return sizeof(int16); case SIMD_RENDER_FORMAT_INT32: return sizeof(int32); case SIMD_RENDER_FORMAT_INT64: return sizeof(int64); case SIMD_RENDER_FORMAT_FLOAT: return sizeof(float); case SIMD_RENDER_FORMAT_DOUBLE: return sizeof(double); } return 0; } const BString& UiUtils::FormatSIMDValue(const BVariant& value, uint32 bitSize, uint32 format, BString& _output) { _output.SetTo("{"); char* data = (char*)value.ToPointer(); uint32 count = bitSize / (GetSIMDFormatByteSize(format) * 8); // <= .... } 

Fungsi GetSIMDFormatByteSize benar-benar mengembalikan 0 sebagai nilai default, yang berpotensi menyebabkan pembagian dengan nol.

V654 Kondisi 'specificSequence! = Sequence' dari loop selalu salah. pthread_key.cpp 55

 static void* get_key_value(pthread_thread* thread, uint32 key, int32 sequence) { pthread_key_data& keyData = thread->specific[key]; int32 specificSequence; void* value; do { specificSequence = keyData.sequence; if (specificSequence != sequence) return NULL; value = keyData.value; } while (specificSequence != sequence); keyData.value = NULL; return value; } 

Analisator benar bahwa kondisi operator sementara selalu salah. Karena ini, loop tidak menjalankan lebih dari satu iterasi. Dengan kata lain, tidak ada yang akan berubah jika Anda menulis while (0) . Semua ini aneh dan kode ini mengandung kesalahan logika. Pengembang harus hati-hati mempertimbangkan cuplikan ini.

V672 Mungkin tidak perlu membuat variabel 'path' baru di sini. Salah satu argumen fungsi memiliki nama yang sama dan argumen ini adalah referensi. Periksa baris: 348, 429. translate.cpp 429

 status_t Translator::FindPath(...., TypeList &path, double &pathQuality) { .... TypeList path; double quality; if (FindPath(&formats[j], stream, typesSeen, path, quality) == B_OK) { if (bestQuality < quality * formatQuality) { bestQuality = quality * formatQuality; bestPath.SetTo(path); bestPath.Add(formats[j].type); status = B_OK; } } .... } 

Variabel path diteruskan ke fungsi FindPath dengan referensi. Yang berarti, variabel ini dapat dimodifikasi dalam tubuh fungsi. Tetapi ada variabel lokal dengan nama yang sama, yang dimodifikasi. Dalam hal ini, semua perubahan hanya akan tetap dalam variabel lokal. Penulis kode mungkin ingin mengganti nama atau menghapus variabel lokal.

V705 Ada kemungkinan bahwa blok 'lain' dilupakan atau dikomentari, sehingga mengubah logika operasi program. HostnameView.cpp 109

 status_t HostnameView::_LoadHostname() { BString fHostnameString; char hostname[MAXHOSTNAMELEN]; if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { fHostnameString.SetTo(hostname, MAXHOSTNAMELEN); fHostname->SetText(fHostnameString); return B_OK; } else return B_ERROR; } 

Contoh pemformatan kode yang buruk. Kata kunci "menggantung" yang lain belum mengubah logika, tetapi begitu sebuah fragmen kode dimasukkan sebelum operator kembali , logikanya tidak akan sama.

V763 Parameter 'menu' selalu ditulis ulang di badan fungsi sebelum digunakan. video.cpp 648

 bool video_mode_hook(Menu *menu, MenuItem *item) { video_mode *mode = NULL; menu = item->Submenu(); item = menu->FindMarked(); .... } 

Saya menemukan banyak kasus ketika argumen fungsi ditulis ulang saat memasukkan fungsi. Perilaku ini menyesatkan pengembang lain yang menyebut fungsi ini.

Seluruh daftar tempat mencurigakan:

  • V763 Parameter 'force_16bit' selalu ditulis ulang di badan fungsi sebelum digunakan. ata_adapter.cpp 151
  • V763 Parameter 'force_16bit' selalu ditulis ulang di badan fungsi sebelum digunakan. ata_adapter.cpp 179
  • V763 Parameter 'menu' selalu ditulis ulang di badan fungsi sebelum digunakan. video.cpp 264
  • V763 Parameter 'panjang' selalu ditulis ulang di badan fungsi sebelum digunakan. MailMessage.cpp 677
  • V763 Parameter 'entri' selalu ditulis ulang di badan fungsi sebelum digunakan. IconCache.cpp 773
  • V763 Parameter 'entri' selalu ditulis ulang di badan fungsi sebelum digunakan. IconCache.cpp 832
  • V763 Parameter 'entri' selalu ditulis ulang di badan fungsi sebelum digunakan. IconCache.cpp 864
  • V763 Parameter 'rect' selalu ditulis ulang di badan fungsi sebelum digunakan. ErrorLogWindow.cpp 56
  • V763 Parameter 'updateRect' selalu ditulis ulang di badan fungsi sebelum digunakan. CalendarMenuWindow.cpp 49
  • V763 Parameter 'rect' selalu ditulis ulang di badan fungsi sebelum digunakan. MemoryView.cpp 165
  • V763 Parameter 'rect' selalu ditulis ulang di badan fungsi sebelum digunakan. TypeEditors.cpp 1124
  • V763 Parameter 'tinggi' selalu ditulis ulang di badan fungsi sebelum digunakan. Workspaces.cpp 857
  • V763 Parameter 'lebar' selalu ditulis ulang di badan fungsi sebelum digunakan. Workspaces.cpp 856
  • V763 Parameter 'bingkai' selalu ditulis ulang di badan fungsi sebelum digunakan. SwatchGroup.cpp 48
  • V763 Parameter 'bingkai' selalu ditulis ulang di badan fungsi sebelum digunakan. PlaylistWindow.cpp 89
  • V763 Parameter 'rect' selalu ditulis ulang di badan fungsi sebelum digunakan. ConfigView.cpp 78
  • V763 Parameter 'm' selalu ditulis ulang di badan fungsi sebelum digunakan. mkntfs.c 3917
  • V763 Parameter 'rxchainmask' selalu ditulis ulang di badan fungsi sebelum digunakan. ar5416_cal.c 463
  • V763 Parameter 'c' selalu ditulis ulang di badan fungsi sebelum digunakan. if_iwn.c 6854

Kesimpulan


Proyek Haiku adalah sumber kesalahan yang menarik dan langka. Kami telah menambahkan beberapa contoh kesalahan ke basis data kami dan memperbaiki beberapa masalah analisa yang muncul saat menganalisis kode.

Jika Anda belum memeriksa kode Anda dengan beberapa alat analisis kode untuk waktu yang lama, maka beberapa masalah yang saya jelaskan mungkin bersembunyi di kode Anda. Gunakan PVS-Studio di proyek Anda (jika ditulis dalam C, C ++, C # atau Java) untuk mengontrol kualitas kode. Unduh penganalisa di sini tanpa registrasi atau sms.

Apakah Anda ingin mencoba Haiku dan Anda memiliki pertanyaan? Pengembang Haiku mengundang Anda ke saluran telegram .

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


All Articles