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

Zahlreiche Tippfehler und Copy-Paste-Code wurden zum Thema eines zusätzlichen Artikels über die Überprüfung des Haiku-Codes durch den PVS-Studio-Analysator. Es wird jedoch Fehler geben, die weniger mit Tippfehlern als vielmehr mit Nachlässigkeit und erfolglosem Refactoring verbunden sind. Die Beispiele für gefundene 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. Derzeit arbeitet eine internationale Gruppe von Entwicklern aktiv an den Komponenten des Systems. Zu den letzten bedeutenden Entwicklungen in der Entwicklung gehörten die Portierung von LibreOffice auf das Betriebssystem und die Veröffentlichung der ersten Beta-Version von R1 Beta 1.

Das Entwicklerteam des statischen Code-Analysators PVS-Studio überwacht die Entwicklung des Projekts seit 2015 und veröffentlicht Überprüfungen von Codefehlern. Dies ist die vierte Überprüfung aller Zeiten. Sie können frühere Artikel unter folgenden Links kennenlernen:

  1. Überprüfen des Haiku-Betriebssystems (BeOS-Familie). Teil 1
  2. Überprüfen des Haiku-Betriebssystems (BeOS-Familie). Teil 2 ;
  3. Wie man sich in C und C ++ in den Fuß schießt. Haiku OS Rezeptsammlung

Ein Merkmal der neuesten Code-Analyse ist die Möglichkeit, die offizielle Version von PVS-Studio für Linux zu verwenden. Im Jahr 2015 war es nicht da, sowie ein praktischer Bericht zum Anzeigen von Fehlern. Jetzt senden wir den Entwicklern einen vollständigen Bericht in einem praktischen Format.

Klassiker des Genres


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 Programmierer in seinem Leben muss die Variablen a und b , x und y , i und j ... usw. 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; } 

Unter dieser Bedingung wird derselbe Eingabezeiger zweimal überprüft, und der Ausgabezeiger bleibt deaktiviert, was zur Dereferenzierung des Nullzeigers führen kann.

Korrigierter 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 verlor seine Bedeutung, als der Programmierer 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 Reset- Funktion ist ein Fehler aufgetreten : ein Tippfehler im Index der Variablen m_kindex2 . Der Wert dieser Variablen 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 werden sofort dieselben Variablen verglichen und dieselben Variablen zugewiesen. Ich kann nicht davon ausgehen, woran hier gedacht wurde. Markieren Sie das Fragment einfach als verdächtig.

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 auf 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 auf Null initialisiert und dann beim Eingeben des switch-Anweisungszweigs überprüft, jedoch nicht in allen Fällen. Der Analysator warnt davor, dass beim Wechseln zum Label USB_DESCRIPTOR_ENDPOINT_COMPANION ein Nullzeiger dereferenziert werden 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 glaube, dass es einen Fehler beim Vergleichen des Verzeichniszeigers mit einem Nullwert gab und die Bedingung das Gegenteil sein sollte. Wenn in 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 auf Null initialisiert und bleibt auf diesem Wert, weil In der GetInput-Funktion ändert sich der Zeiger nicht. Andere Methoden der BMediaRecorder- Klasse schreiben anders, zum Beispiel:

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

Hier ist alles korrekt, aber es ist unmöglich, im ersten Codefragment so zu schreiben, sonst gibt die Funktion einen Link zum lokalen Objekt zurück, aber irgendwie muss der Code repariert werden.

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 ungültigen Eingabedaten überprüft werden, wurde beim Überprüfen des mustFree- Zeigers ein Tippfehler gemacht. Höchstwahrscheinlich sollte der Ausgang der Funktion den Nullwert dieses Zeigers haben:

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

Anstelle des fehlenden Zeigers sollten Sie den Verzeichniszeiger nach der Typkonvertierung überprüfen. Übrigens machen C # -Programmierer oft einen ähnlichen Fehler. Dies zeigt einmal mehr, dass einige Fehler unabhängig von der verwendeten Sprache sind.

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 zwei Elementen, während im Code auf die Konstante BT_SCO zugegriffen wird, die den Wert 3 hat. Ein garantierter Exit über die Grenzen des Arrays hinaus erfolgt.

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 anderer Ausweg aus dem Array. In diesem Fall nur ein Artikel. Die interprozedurale Analyse half dabei, eine Situation zu identifizieren, in der auf das aus 16 Elementen bestehende Array ni-> ni_tx_ampdu am Index 16 zugegriffen wurde . In C und C ++ erfolgt die Array-Indizierung von Grund auf neu.

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 einen Aufruf des sc-> intrs-Arrays an einem ungültigen Index festgestellt (der über die Grenzen des Arrays hinausgeht). Der Grund dafür ist die falsche Codereihenfolge. Hier wird zuerst auf das Array zugegriffen, und dann wird geprüft, ob der Indexwert gültig ist.

Jemand könnte sagen, dass es keine Probleme geben wird. Hier wird schließlich nicht der Wert des Array-Elements abgerufen, sondern die Zellenadresse wird einfach genommen. Nein, das kannst du sowieso nicht. Lesen Sie mehr: "Das Dereferenzieren eines Nullzeigers führt zu undefiniertem 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. Glücklicherweise werden alle möglichen Konstanten in dieser Funktion dargestellt, und der Code ist einfach das Ergebnis der Copy-Paste-Programmierung. Die Wahrscheinlichkeit, auf diese Weise Fehler zu machen, ist jedoch sehr hoch.

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

Und hier hatte der Entwickler kein Glück mit dem Kopieren. Das Symbol "Punkt" wird zu einer bestimmten Zeile hinzugefügt und sofort durch eine Klemme Null überschrieben. Höchstwahrscheinlich hat der Autor des Codes die Zeichenfolge kopiert und vergessen, 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 sofortige Kopieren des Codes führte zu zwei Fehlern. Bedingte Ausdrücke sind identisch. Höchstwahrscheinlich sollte einer von ihnen einen Vergleich mit der Zeichenfolge "false" anstelle von "true" haben. Als nächstes sollten Sie in dem Zweig, der den Wert "false" verarbeitet, den Wert von 1 auf 0 ändern. Der Algorithmus geht davon aus, dass andere Werte als true oder false mithilfe der atoi- Funktion in eine Zahl konvertiert werden. Aufgrund eines Fehlers erhält der Text jedoch auch den Text „false“.

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 . Höchstwahrscheinlich wurde eine Änderung dieser Variablen 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; } 

Höchstwahrscheinlich haben sie im letzten bedingten Ausdruck vergessen, Klammern zu setzen, wie in den obigen Bedingungen. Wahrscheinlich sollte sich auch dort der Negationsoperator außerhalb der Klammern befinden:

 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 von B_OK ab. Somit kann es vereinfacht werden:

 If (result != B_BUSY) break; 

Dies kann leicht überprüft werden, indem eine Wahrheitstabelle für die Werte der Ergebnisvariablen erstellt wird. Wenn Sie andere Werte als B_OK und B_BUSY berücksichtigen müssen , sollte der Code anders geschrieben werden.

Zwei weitere ähnliche Bedingungen:

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

Vielleicht ist dies das einfachste Beispiel, das die Funktionsweise der V590- Diagnose demonstriert. Die Beschreibung des Programms muss angezeigt werden, wenn keine oder zwei Argumente übergeben wurden. Offensichtlich erfüllen andere Werte als zwei, einschließlich Null, die Bedingung nicht. Daher kann die Bedingung leicht auf Folgendes 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 hat sich der logische Operator geändert, die Logik ist jedoch dieselbe geblieben. 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, um zu überprüfen, ob der Benutzer "Ja" ausgewählt hat oder nicht:

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

Verschiedene Fehler


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 hat einen bedeutungslosen Aufruf des Iterators begin () festgestellt . Ich kann nicht erraten, wie der Code repariert werden soll. Der Entwickler sollte auf diesen Ort achten.

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 GetSIMDFormatByteSize- Funktion gibt tatsächlich 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 die Bedingung der while- Anweisung immer falsch ist. Aus diesem Grund wird nicht mehr als eine Iteration in einer Schleife ausgeführt. Mit anderen Worten, nichts würde sich ändern, wenn Sie während (0) schreiben. All dies ist sehr seltsam und dieser Code enthält eine Art Fehler in der Arbeitslogik. Entwickler sollten auf diesen Ort achten.

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 es möglich ist, diese Variable im Hauptteil der Funktion zu ändern. Hier gibt es jedoch eine lokale Variable mit demselben Namen, die geändert wird. In diesem Fall bleiben alle Änderungen nur in der lokalen Variablen. Vielleicht sollten Sie die lokale Variable umbenennen oder löschen.

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

Ein Beispiel für schlechtes Code-Design. Das Schlüsselwort "eingefroren" else ändert die Logik noch nicht, dies jedoch bis zum ersten Code, der vor der return-Anweisung eingefügt wird.

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

Es gab viele Fälle, in denen Funktionsargumente unmittelbar am Eingang der Funktion überschrieben wurden. Dieses Verhalten ist für andere Entwickler, die dieselben Funktionen aufrufen, irreführend.

Die ganze 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 unsere Datenbank mit Fehlerbeispielen aufgefüllt und einige Probleme im Analysator behoben, die während der Codeanalyse festgestellt wurden.

Wenn Sie Ihren Code lange Zeit nicht mit Code-Analyse-Tools überprüft haben, befindet sich wahrscheinlich auch etwas der beschriebenen in Ihrem Code. Verwenden Sie PVS-Studio in Ihrem Projekt, um die Qualität des Codes zu steuern, wenn dieser in C, C ++, C # oder Java geschrieben ist. Sie können den Analysator ohne Registrierung und SMS hier herunterladen.

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



Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Svyatoslav Razmyslov. Beste Copy-Paste-Algorithmen für C und C ++. Haiku OS Kochbuch

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


All Articles