Meilleurs algorithmes de copier-coller pour C et C ++. Haiku OS Cookbook

De nombreuses fautes de frappe et du code copier-coller sont devenus le sujet principal de l'article supplémentaire sur la vérification du code Haiku par l'analyseur PVS-Studio. Pourtant, cet article parle principalement d'erreurs liées à l'insouciance et à l'échec de la refactorisation, plutôt qu'aux fautes de frappe. Les erreurs trouvées démontrent la force du facteur humain dans le développement de logiciels.

Image 1

Présentation


Haiku est un système d'exploitation open source gratuit pour les ordinateurs personnels. Une équipe de développement international travaille actuellement sur les composants du système. Le portage de Libre Office dans le système d'exploitation et la première version R1 Beta 1 se distinguent parmi les améliorations de développement importantes récentes.

L'équipe de développeurs de PVS-Studio suit ce développement de projet depuis 2015 et publie des revues de défauts de code. Il s'agit du quatrième examen de tous les temps. Vous pouvez lire les articles précédents par ces liens:

  1. Analyse du système d'exploitation Haiku (famille BeOS), par PVS-Studio, partie 1 ;
  2. Analyse du système d'exploitation Haiku (famille BeOS) par PVS-Studio. Partie 2 ;
  3. Comment se tirer une balle dans le pied en C et C ++. Livre de cuisine Haiku OS

La caractéristique de la dernière analyse de code est la possibilité d'utiliser la version officielle de PVS-Studio pour Linux. Ni PVS-Studio pour Linux, ni un rapport pratique pour afficher les erreurs n'était disponible en 2015. Cette fois, nous enverrons le rapport complet dans un format pratique aux développeurs de Haiku.

Classique


V501 Il existe des sous-expressions identiques à gauche et à droite de l'opérateur '-': (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; } 

Chaque développeur doit mélanger les variables a et b , x et y , i et j ... au moins une fois dans sa vie.

V501 Il existe des sous-expressions identiques à gauche et à droite de '||' opérateur: entrée == __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; } 

Le même pointeur d' entrée est vérifié deux fois dans la condition. Alors que le pointeur de sortie est resté non contrôlé, ce qui peut entraîner la déréférence du pointeur nul.

Code fixe:

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

V583 L' opérateur '?:', Quelle que soit son expression conditionnelle, renvoie toujours une seule et même valeur: 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); .... } 

L'opérateur ternaire est devenu inutile, lorsque l'auteur du code a fait une erreur et a écrit deux valeurs de retour identiques - 500000 .

V519 La variable 'm_kindex1' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 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; } 

Il y a une erreur dans la fonction de réinitialisation : une faute de frappe dans l' index des variables m_kindex2 . Cette variable ne sera pas réinitialisée, ce qui affectera probablement l'exécution d'autres fragments de code.

V501 Il existe des sous-expressions identiques à gauche et à droite de l'opérateur '>': 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]; .... } 

Dans les dernières lignes, il y a deux problèmes à la fois: la comparaison et l'affectation de variables égales. Je ne peux même pas suggérer l'idée originale de l'auteur. Je vais juste noter cet extrait comme suspect.

V570 La variable 'wPipeIndex' est assignée à elle-même. CEchoGals_transport.cpp 244

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

La variable wPipeIndex est initialisée par sa propre valeur. Très probablement, une faute de frappe a été faite.

Erreurs avec des pointeurs


V522 Le déréférencement du pointeur nul 'currentInterface' peut avoir lieu. 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; .... } .... } 

Le pointeur currentInterface est initialement initialisé par null puis vérifié lors de la saisie dans les branches de l'opérateur switch , mais pas dans tous les cas. L'analyseur avertit que lors du passage à l' étiquette de cas USB_DESCRIPTOR_ENDPOINT_COMPANION , une déréférence de pointeur nul peut se produire.

V522 Le déréférencement du pointeur nul 'répertoire' peut avoir lieu. 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; } .... } 

Je pense qu'il y a une erreur dans la condition de comparaison du pointeur de répertoire avec la valeur nulle; la condition doit être le contraire. Avec l'implémentation actuelle, si la variable dryRun est fausse , le pointeur null du répertoire sera déréférencé.

V522 Le déréférencement du pointeur nul «entrée» peut avoir lieu. MediaRecorder.cpp 343

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

Le pointeur d' entrée est initialisé par null et reste avec une telle valeur, car le pointeur ne change pas dans la fonction GetInput. Dans d'autres méthodes de la classe BMediaRecorder , l'implémentation est différente, par exemple:

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

Tout est correct ici, mais le premier fragment doit être réécrit, sinon la fonction renverra une référence à un objet local.

V522 Le déréférencement du pointeur nul «mustFree» peut avoir lieu. 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; } .... } 

Dans l'expression conditionnelle où toutes les données incorrectes sont vérifiées, l'auteur a fait une faute de frappe lors de la vérification du pointeur mustFree . Très probablement, la fonction devrait se terminer lorsqu'elle a la valeur nulle de ce pointeur:

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

V757 Il est possible qu'une variable incorrecte soit comparée à nullptr après la conversion de type en utilisant 'dynamic_cast'. Vérifiez les lignes: 474, 476. Recover.cpp 474

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

Le développeur aurait dû vérifier le pointeur dir au lieu de manquer après la conversion de type. Soit dit en passant, les développeurs C # font également souvent une erreur similaire. Cela prouve une fois de plus que certaines erreurs ne dépendent pas de la langue utilisée.

Quelques endroits similaires dans le code:

  • V757 Il est possible qu'une variable incorrecte soit comparée à nullptr après la conversion de type en utilisant 'dynamic_cast'. Vérifiez les lignes: 355, 357. ExpandoMenuBar.cpp 355
  • V757 Il est possible qu'une variable incorrecte soit comparée à nullptr après la conversion de type en utilisant 'dynamic_cast'. Vérifiez les lignes: 600, 601. ValControl.cpp 600

Erreurs d'index


V557 Le dépassement de matrice est possible. L'index 'BT_SCO' pointe au-delà de la limite du tableau. 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 } .... } 

Le tableau bdev-> nbuffersTx se compose uniquement de 2 éléments, mais il est adressé par la constante BT_SCO, qui est 3. Voici l'index du tableau infaillible hors limites.

V557 Le dépassement de matrice est possible. La fonction 'ieee80211_send_setup' traite la valeur '16'. Inspectez le quatrième argument. Vérifiez les lignes: 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 .... } 

Un autre index de tableau hors limites. Cette fois, juste par un élément. L'analyse interprocédurale a permis de révéler le cas où le tableau ni-> ni_tx_ampdu , composé de 16 éléments, était traité par l'index 16. En C et C ++, les tableaux sont indexés à partir de zéro.

V781 La valeur de la variable "vecteur" est vérifiée après son utilisation. Il y a peut-être une erreur dans la logique du programme. Vérifiez les lignes: 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); .... } 

L'analyseur a détecté qu'un élément du tableau sc-> intrs était adressé par un index non valide, qui était hors limites. La raison en est l'ordre incorrect des opérations dans le code. Tout d'abord, l'élément est adressé, puis vient la vérification si la valeur d'index est valide.

Certains pourraient dire qu'il n'y aura aucun problème. Il ne supprime pas la valeur de l'élément de tableau, il prend simplement l'adresse de la cellule. Mais non, ce n'est pas la façon de faire les choses. En savoir plus: "Le déréférencement de pointeur nul provoque un comportement indéfini ".

V519 La variable se voit attribuer des valeurs deux fois de suite. C'est peut-être une erreur. Vérifiez les lignes: 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; } 

L'élément de tableau avec l'index NVME_INTEL_FEAT_MAX_LBA reçoit la même valeur. La bonne nouvelle est que cette fonction présente toutes les constantes possibles, ce qui fait que ce code n'est que le résultat de la programmation du copier-coller. Mais il y a des chances que des erreurs se faufilent ici.

V519 La variable 'copiedPath [len]' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 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'; } .... } 

Eh bien, ici, le programmeur n'a pas eu de chance avec la copie. Le symbole "point" est ajouté à une ligne et est réécrit avec un terminal nul. Il est fort probable que l'auteur ait simplement copié la ligne et oublié d'incrémenter l'index.

Des conditions étranges


V517 L'utilisation du modèle 'if (A) {...} else if (A) {...}' a été détectée. Il y a une probabilité de présence d'erreur logique. Vérifiez les lignes: 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; } .... } 

La copie du code a conduit à deux erreurs à la fois. Les expressions conditionnelles sont identiques. Très probablement, une comparaison avec la chaîne "false" au lieu de "true" doit être dans l'un d'eux. Plus loin dans la branche qui gère la "fausse" valeur, la valeur qui doit être changée de 1 à 0 . L'algorithme requiert que toute autre valeur, différente de true ou false, soit convertie en un nombre à l'aide de la fonction atoi . Mais en raison d'une erreur, le texte "false" entrera dans la fonction.

V547 L' expression 'error == ((int) 0)' est toujours vraie. 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); } 

L'analyseur a détecté que la valeur de la variable d' erreur sera toujours B_OK . Très certainement, cette modification de variable a été manquée dans la boucle while.

V564 L'opérateur '&' est appliqué à la valeur de type bool. Vous avez probablement oublié d'inclure des parenthèses ou avez l'intention d'utiliser l'opérateur '&&'. 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; } 

Il est fort probable que dans la dernière expression conditionnelle, on ait oublié de placer des crochets, comme dans les conditions ci-dessus. L'opérateur complémentaire est susceptible d'être en dehors des parenthèses:

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

V590 Envisagez d'inspecter cette expression. L'expression est excessive ou contient une erreur d'impression. PoseView.cpp 5851

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

Ce n'est pas évident, mais le résultat de la condition ne dépend pas de la valeur de la valeur B_OK. Cela peut donc être simplifié:

 If (result != B_BUSY) break; 

Vous pouvez facilement le vérifier en dessinant une table de vérité pour les valeurs de la variable de résultat . Si l'on voulait considérer spécifiquement d'autres valeurs, différentes de B_OK et B_BUSY , le code devrait être réécrit d'une autre manière.

Deux autres fragments similaires:

  • V590 Envisagez d'inspecter cette expression. L'expression est excessive ou contient une erreur d'impression. Tracker.cpp 1714
  • V590 Envisagez d'inspecter cette expression. L'expression est excessive ou contient une erreur d'impression. if_ipw.c 1871

V590 Envisagez d'inspecter le 'argc == 0 || argc! = expression 2 '. L'expression est excessive ou contient une erreur d'impression. cmds.c 2667

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

C'est peut-être l'exemple le plus simple qui démontre le travail du diagnostic V590 . Vous devez afficher la description du programme au cas où aucun argument n'est passé ou s'il n'y en a pas deux. De toute évidence, toute valeur autre que deux, y compris zéro, ne satisfera pas la condition. Par conséquent, la condition peut être simplifiée en toute sécurité à ceci:

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

V590 Pensez à inspecter le '* ptr =='; ' && * ptr! = expression '\ 0' '. L'expression est excessive ou contient une erreur d'impression. 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); } .... } 

Dans cet exemple, l'opérateur logique a été modifié, mais la logique est toujours la même. Ici, la condition de la boucle while dépend uniquement de si le caractère est égal à SEMI_COLON ou non.

V590 Envisagez d'inspecter cette expression. L'expression est excessive ou contient une erreur d'impression. 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; } .... } 

Il y a déjà trois conditions dans cet exemple. Il peut également être simplifié avant de vérifier si l'utilisateur a choisi "oui" ou non:

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

Divers


V530 La valeur de retour de la fonction 'begin' doit être utilisée. 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(); // <= } } 

L'analyseur a trouvé un appel inutile de l'itérateur begin (). Je ne peux pas imaginer comment réparer le code. Les développeurs doivent faire attention à ce code.

V609 Divisez par zéro. Plage de dénominateurs [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); // <= .... } 

La fonction GetSIMDFormatByteSize renvoie vraiment 0 comme valeur par défaut, ce qui pourrait potentiellement conduire à une division par zéro.

V654 La condition 'specificSequence! = Sequence' de la boucle est toujours fausse. 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; } 

L'analyseur a raison de dire que la condition de l'opérateur while est toujours fausse. Pour cette raison, la boucle n'exécute pas plus d'une itération. En d'autres termes, rien ne changerait si vous écriviez while (0) . Tout cela est bizarre et ce code contient une erreur logique. Les développeurs doivent examiner attentivement cet extrait.

V672 Il n'est probablement pas nécessaire de créer ici la nouvelle variable 'path'. Un des arguments de la fonction possède le même nom et cet argument est une référence. Vérifier les lignes: 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; } } .... } 

La variable path est transmise à la fonction FindPath par référence. Ce qui signifie que cette variable peut être modifiée dans le corps de la fonction. Mais il existe une variable locale du même nom, qui est modifiée. Dans ce cas, toutes les modifications resteront uniquement dans la variable locale. L'auteur du code peut vouloir renommer ou supprimer la variable locale.

V705 Il est possible que le bloc "else" ait été oublié ou commenté, altérant ainsi la logique de fonctionnement du programme. 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; } 

L'exemple d'une mauvaise mise en forme du code. Le mot-clé "suspendu" else ne change pas encore la logique, mais une fois qu'un fragment de code est inséré avant l'opérateur de retour , la logique ne sera plus la même.

V763 Le «menu» des paramètres est toujours réécrit dans le corps de la fonction avant d'être utilisé. video.cpp 648

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

J'ai trouvé de nombreux cas où les arguments de fonction sont réécrits en entrant dans la fonction. Ce comportement induit en erreur les autres développeurs qui appellent ces mêmes fonctions.

La liste complète des endroits suspects:

  • V763 Le paramètre 'force_16bit' est toujours réécrit dans le corps de la fonction avant d'être utilisé. ata_adapter.cpp 151
  • V763 Le paramètre 'force_16bit' est toujours réécrit dans le corps de la fonction avant d'être utilisé. ata_adapter.cpp 179
  • V763 Le «menu» des paramètres est toujours réécrit dans le corps de la fonction avant d'être utilisé. video.cpp 264
  • V763 La «longueur» du paramètre est toujours réécrite dans le corps de la fonction avant d'être utilisée. MailMessage.cpp 677
  • V763 L'entrée de paramètre est toujours réécrite dans le corps de la fonction avant d'être utilisée. IconCache.cpp 773
  • V763 L'entrée de paramètre est toujours réécrite dans le corps de la fonction avant d'être utilisée. IconCache.cpp 832
  • V763 L'entrée de paramètre est toujours réécrite dans le corps de la fonction avant d'être utilisée. IconCache.cpp 864
  • V763 Le paramètre 'rect' est toujours réécrit dans le corps de la fonction avant d'être utilisé. ErrorLogWindow.cpp 56
  • V763 Le paramètre 'updateRect' est toujours réécrit dans le corps de la fonction avant d'être utilisé. CalendarMenuWindow.cpp 49
  • V763 Le paramètre 'rect' est toujours réécrit dans le corps de la fonction avant d'être utilisé. MemoryView.cpp 165
  • V763 Le paramètre 'rect' est toujours réécrit dans le corps de la fonction avant d'être utilisé. TypeEditors.cpp 1124
  • V763 Le paramètre 'hauteur' est toujours réécrit dans le corps de la fonction avant d'être utilisé. Workspaces.cpp 857
  • V763 Le paramètre 'largeur' est toujours réécrit dans le corps de la fonction avant d'être utilisé. Workspaces.cpp 856
  • V763 Le «cadre» du paramètre est toujours réécrit dans le corps de la fonction avant d'être utilisé. SwatchGroup.cpp 48
  • V763 Le «cadre» du paramètre est toujours réécrit dans le corps de la fonction avant d'être utilisé. PlaylistWindow.cpp 89
  • V763 Le paramètre 'rect' est toujours réécrit dans le corps de la fonction avant d'être utilisé. ConfigView.cpp 78
  • V763 Le paramètre 'm' est toujours réécrit dans le corps de la fonction avant d'être utilisé. mkntfs.c 3917
  • V763 Le paramètre 'rxchainmask' est toujours réécrit dans le corps de la fonction avant d'être utilisé. ar5416_cal.c 463
  • V763 Le paramètre 'c' est toujours réécrit dans le corps de la fonction avant d'être utilisé. if_iwn.c 6854

Conclusion


Le projet Haiku est une source d'erreurs intéressantes et rares. Nous avons ajouté à notre base de données quelques exemples d'erreur et corrigé quelques problèmes d'analyseur qui se présentaient lors de l'analyse du code.

Si vous n'avez pas vérifié votre code avec des outils d'analyse de code depuis longtemps, certains des problèmes que j'ai décrits se cachent probablement dans votre code. Utilisez PVS-Studio dans votre projet (s'il est écrit en C, C ++, C # ou Java) pour contrôler la qualité du code. Téléchargez l'analyseur ici sans inscription ni sms.

Voulez-vous essayer Haiku et vous avez des questions? Les développeurs de Haiku vous invitent sur le canal télégramme .

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


All Articles