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

De nombreuses fautes de frappe et du code copier-coller sont devenus le sujet d'un article supplémentaire sur la vérification du code Haiku par l'analyseur PVS-Studio. Cependant, il y aura des erreurs associées non pas tant aux fautes de frappe, mais plutôt à la négligence et au refactoring infructueux. Les exemples d'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 gratuit et open source pour les ordinateurs personnels. Actuellement, un groupe international de développeurs travaille activement sur les composants du système. Parmi les derniers développements importants dans le développement, le portage de LibreOffice sur le système d'exploitation et la sortie de la première version bêta de R1 Beta 1.

L'équipe de développeurs de l'analyseur de code statique PVS-Studio suit le développement du projet depuis 2015, publiant des revues de défauts de code. Il s'agit du quatrième examen de tous les temps. Vous pouvez vous familiariser avec les articles précédents à ces liens:

  1. Vérification du système d'exploitation Haiku (famille BeOS). Partie 1
  2. Vérification du système d'exploitation Haiku (famille BeOS). Partie 2 ;
  3. Comment se tirer une balle dans le pied en C et C ++. Collection de recettes Haiku OS

Une caractéristique de la dernière analyse de code est la possibilité d'utiliser la version officielle de PVS-Studio pour Linux. En 2015, il n'était pas là, ainsi qu'un rapport pratique pour visualiser les erreurs. Nous allons maintenant envoyer aux développeurs un rapport complet dans un format pratique.

Classiques du genre


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 programmeur de sa vie doit mélanger les variables a et b , x et y , i et j ... etc.

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; } 

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

Code corrigé:

 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 a perdu sa signification lorsque le programmeur 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; } 

Une erreur a été commise dans la fonction reset : une faute de frappe dans l'index de la variable m_kindex2 . La valeur de cette variable ne sera pas réinitialisée, ce qui est susceptible d'affecter 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 immédiatement une comparaison de variables identiques et l'affectation de variables identiques. Je ne peux pas supposer ce à quoi on a pensé ici. Marquez simplement le fragment 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 à 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é à zéro puis vérifié lors de l'entrée dans la branche de l' instruction switch , mais pas dans tous les cas. L'analyseur avertit que lors du passage à l'étiquette USB_DESCRIPTOR_ENDPOINT_COMPANION , il est possible de déréférencer un pointeur nul.

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 crois qu'il y a eu une erreur en comparant le pointeur de répertoire avec une valeur nulle et la condition devrait être l'inverse. Dans 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é à zéro et reste à cette valeur, car dans la fonction GetInput, le pointeur ne change pas. D'autres méthodes de la classe BMediaRecorder écrivent différemment, par exemple:

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

Tout est correct ici, mais il est impossible d'écrire comme ceci dans le premier fragment de code, sinon la fonction renverra un lien vers l'objet local, mais le code doit en quelque sorte être corrigé.

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 d'entrée non valides sont vérifiées, une faute de frappe a été effectuée lors de la vérification du pointeur mustFree . Très probablement, la sortie de la fonction doit être à la valeur zéro 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) { .... } .... } 

Au lieu du pointeur manquant , vous devez vérifier le pointeur dir après la conversion de type. Soit dit en passant, les programmeurs C # font souvent une erreur similaire. Cela prouve une fois de plus que certaines erreurs sont indépendantes du langage utilisé.

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 de seulement deux éléments, tandis que dans le code il est accessible par la constante BT_SCO, qui a une valeur de 3. Une sortie garantie au-delà des limites du tableau se produit.

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 .... } 

Une autre façon de sortir du tableau. Dans ce cas, un seul élément. L'analyse interprocédurale a permis d'identifier une situation où le tableau ni-> ni_tx_ampdu , composé de 16 éléments, était accessible à l'index 16 . En C et C ++, l'indexation des tableaux se fait à 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é un appel au tableau sc-> intrs à un index non valide (dépassant les limites du tableau). La raison en est un mauvais ordre de code. Ici, le tableau est d'abord accessible, puis une vérification est effectuée pour voir si la valeur d'index est valide.

Quelqu'un peut dire qu'il n'y aura aucun problème. Ici, après tout, la valeur de l'élément de tableau n'est pas récupérée, mais l'adresse de cellule est simplement prise. Non, vous ne pouvez pas le faire de toute façon. En savoir plus: " Déréférencer un pointeur nul conduit à 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. Heureusement, toutes les constantes possibles sont représentées dans cette fonction, et le code est simplement le résultat de la programmation de copier-coller. Mais la probabilité de commettre des erreurs de cette manière est très élevée.

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'; } .... } 

Et ici, le développeur n'a pas eu la chance de copier. Le symbole "point" est ajouté à une certaine ligne et est immédiatement remplacé par un zéro terminal. Très probablement, l'auteur du code a copié la chaîne 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 immédiatement conduit à deux erreurs. Les expressions conditionnelles sont identiques. Très probablement, l'un d'eux devrait avoir une comparaison avec la chaîne "false", au lieu de "true". Ensuite, dans la branche qui traite la valeur "false", vous devez changer la valeur de la valeur de 1 à 0 . L'algorithme suppose que toute autre valeur autre que true ou false sera convertie en un nombre à l'aide de la fonction atoi , mais en raison d'une erreur, le texte obtiendra également le texte "false".

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 probablement, une modification de cette 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; } 

Très probablement, dans la dernière expression conditionnelle, ils ont oublié de placer des crochets, comme dans les conditions ci-dessus. Probablement, là aussi, l'opérateur de négation devrait être en dehors des crochets:

 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 B_OK. Ainsi, il peut être simplifié:

 If (result != B_BUSY) break; 

Cela peut être facilement vérifié en construisant une table de vérité pour les valeurs de la variable de résultat . Si vous devez considérer spécifiquement d'autres valeurs autres que B_OK et B_BUSY , le code doit être réécrit différemment.

Deux autres conditions 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; } .... } 

Il s'agit peut-être de l'exemple le plus simple qui illustre le fonctionnement du diagnostic V590 . Il est nécessaire d'afficher la description du programme s'il n'y a pas d'arguments passés, 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 facilement simplifiée à 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 changé, mais la logique est restée la même. Ici, la condition de la boucle while ne dépend que de savoir 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é pour vérifier si l'utilisateur a sélectionné «oui» ou non:

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

Erreurs diverses


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 détecté un appel vide de sens à l'itérateur begin (). Je ne peux pas deviner comment corriger le code. Le développeur doit faire attention à cet endroit.

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 en fait 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'instruction while est toujours fausse. Pour cette raison, pas plus d'une itération n'est effectuée dans une boucle. En d'autres termes, rien ne changerait si vous écrivez while (0) . Tout cela est très étrange et ce code contient une sorte d'erreur dans la logique du travail. Les développeurs doivent faire attention à cet endroit.

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. Cela signifie qu'il est possible de modifier cette variable dans le corps de la fonction. Mais ici, il y a une variable locale du même nom qui est en cours de modification. Dans ce cas, toutes les modifications resteront uniquement dans la variable locale. Vous devriez peut-être 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; } 

Un exemple de mauvaise conception de code. Le mot-clé else "gelé" ne change pas encore la logique, mais c'est jusqu'à ce que le premier morceau de code soit inséré avant l' instruction return .

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(); .... } 

Dans de nombreux cas, les arguments de fonction sont remplacés immédiatement à l'entrée de la fonction. Ce comportement est trompeur pour les autres développeurs qui invoquent 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 de bugs intéressants et rares. Nous avons reconstitué notre base de données d'exemples d'erreur et corrigé plusieurs problèmes dans l'analyseur identifié lors de l'analyse de code.

Si vous n'avez pas vérifié votre code avec des outils d'analyse de code depuis longtemps, alors quelque chose de ce qui est décrit se trouve probablement dans votre code également. Utilisez PVS-Studio dans votre projet pour contrôler la qualité du code s'il est écrit en C, C ++, C # ou Java. Vous pouvez télécharger l'analyseur sans inscription et SMS ici .

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



Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Svyatoslav Razmyslov. Meilleurs algorithmes de copier-coller pour C et C ++. Haiku OS Cookbook

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


All Articles