Beste Copy-Paste-Algorithmen für C und C ++. Haiku OS Kochbuch

Zahlreiche Tippfehler und Copy-Paste-Code wurden zum Hauptthema des zusätzlichen Artikels über die Überprüfung des Haiku-Codes durch den PVS-Studio-Analysator. In diesem Artikel geht es jedoch hauptsächlich um Fehler im Zusammenhang mit Gedankenlosigkeit und fehlgeschlagenem Refactoring und nicht um Tippfehler. Die gefundenen Fehler zeigen, wie stark der menschliche Faktor in der Softwareentwicklung ist.

Bild 1

Einführung


Haiku ist ein kostenloses Open Source-Betriebssystem für PCs. Ein internationales Entwicklungsteam arbeitet derzeit an den Komponenten des Systems. Die Portierung von Libre Office in das Betriebssystem und die erste Version von R1 Beta 1 zeichnen sich durch die jüngsten bedeutenden Entwicklungsverbesserungen aus.

Das Entwicklerteam von PVS-Studio verfolgt diese Projektentwicklung seit 2015 und veröffentlicht Überprüfungen von Codefehlern. Dies ist die vierte Überprüfung aller Zeiten. Sie können die vorherigen Artikel über diese Links lesen:

  1. Analyse des Haiku-Betriebssystems (BeOS-Familie) durch PVS-Studio, Teil 1 ;
  2. Analyse des Haiku-Betriebssystems (BeOS-Familie) durch PVS-Studio. Teil 2 ;
  3. Wie man sich in C und C ++ in den Fuß schießt. Haiku OS Kochbuch

Das Merkmal der letzten Code-Analyse ist die Möglichkeit, die offizielle Version von PVS-Studio für Linux zu verwenden. Weder PVS-Studio für Linux noch ein praktischer Bericht zum Anzeigen von Fehlern waren 2015 verfügbar. Dieses Mal senden wir den vollständigen Bericht in einem praktischen Format an Haiku-Entwickler.

Klassisch


V501 Links und rechts vom Operator '-' befinden sich identische Unterausdrücke: (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; } 

Jeder Entwickler muss die Variablen a und b , x und y , i und j ... mindestens einmal in seinem Leben verwechseln.

V501 Links und rechts vom '||' befinden sich identische Unterausdrücke. Operator: Eingabe == __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; } 

Der gleiche Eingabezeiger wird in der Bedingung zweimal überprüft. Während der Ausgabezeiger deaktiviert blieb, kann dies zu einer Nullzeiger-Dereferenzierung führen.

Fester Code:

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

V583 Der Operator '?:' Gibt unabhängig von seinem bedingten Ausdruck immer ein und denselben Wert zurück: 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); .... } 

Der ternäre Operator wurde sinnlos, als der Code-Autor einen Fehler machte und zwei identische Rückgabewerte schrieb - 500000 .

V519 Der Variablen 'm_kindex1' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 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; } 

Bei der Rücksetzfunktion ist ein Fehler aufgetreten : ein Tippfehler im Variablenindex m_kindex2 . Diese Variable wird nicht zurückgesetzt, was sich wahrscheinlich auf die Ausführung anderer Codefragmente auswirkt.

V501 Links und rechts vom Operator '>' befinden sich identische Unterausdrücke: 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]; .... } 

In den letzten Zeilen gibt es zwei Probleme gleichzeitig: Vergleich und Zuweisung gleicher Variablen. Ich kann nicht einmal vorschlagen, was die Idee des Autors war. Ich werde diesen Ausschnitt nur als verdächtig bezeichnen.

V570 Die Variable 'wPipeIndex' wird sich selbst zugewiesen. CEchoGals_transport.cpp 244

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

Die Variable wPipeIndex wird durch ihren eigenen Wert initialisiert. Höchstwahrscheinlich wurde ein Tippfehler gemacht.

Fehler mit Zeigern


V522 Eine Dereferenzierung des Nullzeigers 'currentInterface' kann stattfinden. 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; .... } .... } 

Der currentInterface- Zeiger wird zunächst mit null initialisiert und dann beim Eingeben in die Zweige des Switch- Operators überprüft, jedoch nicht in allen Fällen. Der Analysator warnt davor, dass beim Wechseln zur Fallbezeichnung USB_DESCRIPTOR_ENDPOINT_COMPANION eine Nullzeiger-Dereferenzierung auftreten kann.

V522 Es kann zu einer Dereferenzierung des Nullzeigers 'Verzeichnis' kommen. 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; } .... } 

Ich denke, es gibt einen Fehler in der Vergleichsbedingung des Verzeichniszeigers mit dem Nullwert; Die Bedingung muss das Gegenteil sein. Wenn bei der aktuellen Implementierung die Variable dryRun false ist , wird der Verzeichnis- Nullzeiger dereferenziert.

V522 Eine Dereferenzierung des Nullzeigers 'Eingabe' kann stattfinden. MediaRecorder.cpp 343

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

Der Eingabezeiger wird mit null initialisiert und bleibt bei diesem Wert, da sich der Zeiger in der GetInput-Funktion nicht ändert. Bei anderen Methoden der BMediaRecorder- Klasse ist die Implementierung anders, zum Beispiel:

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

Hier ist alles korrekt, aber das erste Fragment muss neu geschrieben werden, sonst gibt die Funktion einen Verweis auf ein lokales Objekt zurück.

V522 Eine Dereferenzierung des Nullzeigers 'mustFree' kann stattfinden. 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; } .... } 

In dem bedingten Ausdruck, in dem alle falschen Daten überprüft werden, hat der Autor beim Überprüfen des mustFree- Zeigers einen Tippfehler gemacht . Höchstwahrscheinlich sollte die Funktion beendet werden, wenn der Nullwert dieses Zeigers vorliegt:

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

V757 Es ist möglich, dass eine falsche Variable nach der Typkonvertierung mit 'dynamic_cast' mit nullptr verglichen wird. Überprüfen Sie die Zeilen: 474, 476. recovery.cpp 474

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

Der Entwickler sollte den Verzeichniszeiger überprüft haben, anstatt nach der Typkonvertierung zu fehlen . Übrigens machen C # -Entwickler oft auch einen ähnlichen Fehler. Dies zeigt einmal mehr, dass einige Fehler nicht von der verwendeten Sprache abhängen.

Noch ein paar ähnliche Stellen im Code:

  • V757 Es ist möglich, dass eine falsche Variable nach der Typkonvertierung mit 'dynamic_cast' mit nullptr verglichen wird. Überprüfen Sie die Zeilen: 355, 357. ExpandoMenuBar.cpp 355
  • V757 Es ist möglich, dass eine falsche Variable nach der Typkonvertierung mit 'dynamic_cast' mit nullptr verglichen wird. Überprüfen Sie die Zeilen: 600, 601. ValControl.cpp 600

Indexfehler


V557 Array-Überlauf ist möglich. Der 'BT_SCO'-Index zeigt über die Array-Grenze hinaus. 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 } .... } 

Das Array bdev-> nbuffersTx besteht nur aus 2 Elementen, wird jedoch von der Konstante BT_SCO (3) adressiert. Hier kommt der todsichere Array-Index außerhalb der Grenzen.

V557 Array-Überlauf ist möglich. Die Funktion 'ieee80211_send_setup' verarbeitet den Wert '16'. Untersuchen Sie das vierte Argument. Überprüfen Sie die Zeilen: 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 .... } 

Ein weiterer Array-Index außerhalb der Grenzen. Diesmal nur um ein Element. Die interprozedurale Analyse half dabei, den Fall aufzudecken , in dem das aus 16 Elementen bestehende Array ni-> ni_tx_ampdu vom Index 16 adressiert wurde. In C und C ++ werden Arrays von Null indiziert.

V781 Der Wert der Variablen 'vector' wird nach ihrer Verwendung überprüft. Möglicherweise liegt ein Fehler in der Programmlogik vor. Überprüfen Sie die Zeilen: 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); .... } 

Der Analysator hat festgestellt, dass ein Element des sc-> intrs- Arrays durch einen ungültigen Index adressiert wurde, der außerhalb der Grenzen lag. Der Grund ist die falsche Reihenfolge der Operationen im Code. Zuerst wird das Element adressiert und dann wird geprüft, ob der Indexwert gültig ist.

Einige könnten sagen, dass es keine Probleme geben wird. Der Wert des Array-Elements wird nicht entfernt, sondern nur die Adresse der Zelle. Aber nein, das ist nicht der Weg, Dinge zu tun. Lesen Sie mehr: " Null-Zeiger-Dereferenzierung verursacht undefiniertes Verhalten ".

V519 Der Variablen werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 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; } 

Dem Array-Element mit dem Index NVME_INTEL_FEAT_MAX_LBA wird der gleiche Wert zugewiesen. Die gute Nachricht ist, dass diese Funktion alle möglichen Konstanten darstellt, wodurch dieser Code nur das Ergebnis der Copy-Paste-Programmierung ist. Aber es besteht die Möglichkeit, dass sich hier Fehler einschleichen.

V519 Der Variablen 'copiedPath [len]' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 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'; } .... } 

Nun, hier hatte der Programmierer Pech beim Kopieren. Das Symbol "Punkt" wird einer Zeile hinzugefügt und mit einem Terminal Null neu geschrieben. Es ist sehr wahrscheinlich, dass der Autor gerade die Zeile kopiert und vergessen hat, den Index zu erhöhen.

Seltsame Bedingungen


V517 Die Verwendung des Musters 'if (A) {...} else if (A) {...}' wurde erkannt. Es besteht die Wahrscheinlichkeit eines logischen Fehlers. Überprüfen Sie die Zeilen: 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; } .... } 

Das Kopieren des Codes führte zu zwei Fehlern gleichzeitig. Die bedingten Ausdrücke sind identisch. Höchstwahrscheinlich muss ein Vergleich mit der Zeichenfolge "false" anstelle von "true" in einer davon erfolgen. Weiter in dem Zweig, der den "falschen" Wert behandelt, den Wert , der von 1 auf 0 geändert werden sollte. Der Algorithmus erfordert, dass alle anderen Werte, die sich von wahr oder falsch unterscheiden , mithilfe der atoi- Funktion in eine Zahl konvertiert werden. Aufgrund eines Fehlers wird jedoch der Text "false" in die Funktion übernommen.

V547 Der Ausdruck 'error == ((int) 0)' ist immer wahr. 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); } 

Der Analysator hat festgestellt, dass der Wert der Fehlervariablen immer B_OK ist . Diese Variablenänderung wurde definitiv in der while- Schleife übersehen.

V564 Der Operator '&' wird auf den Wert des Bool- Typs angewendet. Sie haben wahrscheinlich vergessen, Klammern einzufügen, oder wollten den Operator '&&' verwenden. 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; } 

Es ist sehr wahrscheinlich, dass man im letzten bedingten Ausdruck vergessen hat, Klammern zu setzen, wie in den obigen Bedingungen. Der komplementäre Operator befindet sich wahrscheinlich außerhalb der Klammern:

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

V590 Überprüfen Sie diesen Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. PoseView.cpp 5851

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

Dies ist nicht offensichtlich, aber das Ergebnis der Bedingung hängt nicht vom Wert des B_OK-Werts ab. So kann es vereinfacht werden:

 If (result != B_BUSY) break; 

Sie können dies leicht überprüfen, indem Sie eine Wahrheitstabelle für die Werte der Ergebnisvariablen zeichnen. Wenn Sie andere Werte als B_OK und B_BUSY berücksichtigen möchten , sollte der Code auf andere Weise neu geschrieben werden.

Zwei weitere ähnliche Fragmente:

  • V590 Überprüfen Sie diesen Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. Tracker.cpp 1714
  • V590 Überprüfen Sie diesen Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. if_ipw.c 1871

V590 Überprüfen Sie die 'argc == 0 || argc! = 2 'Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. cmds.c 2667

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

Dies ist vielleicht das einfachste Beispiel, das die Arbeit der V590- Diagnose demonstriert. Sie müssen die Programmbeschreibung anzeigen, falls keine oder zwei Argumente übergeben wurden. Offensichtlich erfüllen andere Werte als zwei, einschließlich Null, die Bedingung nicht. Daher kann die Bedingung sicher vereinfacht werden:

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

V590 Überprüfen Sie die '* ptr =='; ' && * ptr! = '\ 0' 'Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. 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); } .... } 

In diesem Beispiel wurde der logische Operator geändert, aber die Logik ist immer noch dieselbe. Hier hängt die Bedingung der while-Schleife nur davon ab, ob das Zeichen SEMI_COLON entspricht oder nicht.

V590 Überprüfen Sie diesen Ausdruck. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. 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; } .... } 

In diesem Beispiel gibt es bereits drei Bedingungen. Es kann auch vereinfacht werden, bevor überprüft wird, ob der Benutzer "Ja" gewählt hat oder nicht:

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

Verschiedenes


V530 Der Rückgabewert der Funktion 'begin' muss verwendet werden. 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(); // <= } } 

Der Analysator fand einen sinnlosen Aufruf des Iterators begin (). Ich kann mir nicht vorstellen, wie ich den Code reparieren soll. Entwickler sollten diesen Code beachten.

V609 Durch Null teilen. Nennerbereich [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); // <= .... } 

Die Funktion GetSIMDFormatByteSize gibt wirklich 0 als Standardwert zurück, was möglicherweise zu einer Division durch Null führen kann.

V654 Die Bedingung 'spezifischSequenz! = Sequenz' der Schleife ist immer falsch. 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; } 

Der Analysator hat Recht, dass der Zustand des while- Operators immer falsch ist. Aus diesem Grund führt die Schleife nicht mehr als eine Iteration aus. Mit anderen Worten, nichts würde sich ändern, wenn Sie while (0) schreiben würden. All dies ist seltsam und dieser Code enthält einen logischen Fehler. Entwickler sollten dieses Snippet sorgfältig prüfen.

V672 Die neue Variable 'path' muss hier wahrscheinlich nicht erstellt werden. Eines der Argumente der Funktion hat denselben Namen und dieses Argument ist eine Referenz. Überprüfen Sie die Zeilen: 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; } } .... } 

Die Pfadvariable wird als Referenz an die FindPath- Funktion übergeben. Dies bedeutet, dass diese Variable im Hauptteil der Funktion geändert werden kann. Es gibt jedoch eine lokale Variable mit demselben Namen, die geändert wird. In diesem Fall bleiben alle Änderungen nur in der lokalen Variablen. Der Code-Autor möchte möglicherweise die lokale Variable umbenennen oder entfernen.

V705 Es ist möglich, dass der Block 'else' vergessen oder auskommentiert wurde, wodurch die Betriebslogik des Programms geändert wurde. 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; } 

Das Beispiel einer schlechten Code-Formatierung. Das Schlüsselwort "hängen" ändert die Logik noch nicht, aber sobald ein Codefragment vor dem Rückgabeoperator eingefügt wird, ist die Logik nicht mehr dieselbe.

V763 Der Parameter 'menu' wird vor der Verwendung immer im Funktionskörper neu geschrieben. video.cpp 648

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

Ich habe viele Fälle gefunden, in denen Funktionsargumente beim Eingeben der Funktion neu geschrieben werden. Dieses Verhalten führt andere Entwickler in die Irre, die genau diese Funktionen aufrufen.

Die gesamte Liste der verdächtigen Orte:

  • V763 Der Parameter 'force_16bit' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. ata_adapter.cpp 151
  • V763 Der Parameter 'force_16bit' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. ata_adapter.cpp 179
  • V763 Der Parameter 'menu' wird vor der Verwendung immer im Funktionskörper neu geschrieben. video.cpp 264
  • V763 Der Parameter 'Länge' wird vor der Verwendung immer im Funktionskörper neu geschrieben. MailMessage.cpp 677
  • V763 Der Parameter 'entry' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. IconCache.cpp 773
  • V763 Der Parameter 'entry' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. IconCache.cpp 832
  • V763 Der Parameter 'entry' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. IconCache.cpp 864
  • V763 Der Parameter 'rect' wird vor der Verwendung immer in den Funktionskörper umgeschrieben. ErrorLogWindow.cpp 56
  • V763 Der Parameter 'updateRect' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. CalendarMenuWindow.cpp 49
  • V763 Der Parameter 'rect' wird vor der Verwendung immer in den Funktionskörper umgeschrieben. MemoryView.cpp 165
  • V763 Der Parameter 'rect' wird vor der Verwendung immer in den Funktionskörper umgeschrieben. TypeEditors.cpp 1124
  • V763 Der Parameter 'height' wird vor der Verwendung immer im Funktionskörper neu geschrieben. Workspaces.cpp 857
  • V763 Der Parameter 'width' wird vor der Verwendung immer im Funktionskörper neu geschrieben. Workspaces.cpp 856
  • V763 Der Parameter 'frame' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. SwatchGroup.cpp 48
  • V763 Der Parameter 'frame' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. PlaylistWindow.cpp 89
  • V763 Der Parameter 'rect' wird vor der Verwendung immer in den Funktionskörper umgeschrieben. ConfigView.cpp 78
  • V763 Der Parameter 'm' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. mkntfs.c 3917
  • V763 Der Parameter 'rxchainmask' wird vor der Verwendung immer im Funktionskörper neu geschrieben. ar5416_cal.c 463
  • V763 Der Parameter 'c' wird vor seiner Verwendung immer im Funktionskörper neu geschrieben. if_iwn.c 6854

Fazit


Das Haiku-Projekt ist eine Quelle interessanter und seltener Fehler. Wir haben unserer Datenbank einige Fehlerbeispiele hinzugefügt und einige Probleme mit dem Analysator behoben, die bei der Analyse des Codes aufgetreten sind.

Wenn Sie Ihren Code lange Zeit nicht mit einigen Code-Analyse-Tools überprüft haben, verbergen sich einige der von mir beschriebenen Probleme wahrscheinlich in Ihrem Code. Verwenden Sie PVS-Studio in Ihrem Projekt (falls in C, C ++, C # oder Java geschrieben), um die Codequalität zu steuern. Laden Sie den Analysator hier ohne Registrierung oder SMS herunter.

Möchten Sie Haiku ausprobieren und haben Fragen? Haiku-Entwickler laden Sie zum Telegrammkanal ein .

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


All Articles