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.
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:
- Vérification du système d'exploitation Haiku (famille BeOS). Partie 1
- Vérification du système d'exploitation Haiku (famille BeOS). Partie 2 ;
- 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;
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) {
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(....) { ....
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)
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)
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)];
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];
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) { ....
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)
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))
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