Aufgrund des dunklen Themas musste Thunderbird einen Code-Analysator ausführen

Bild 3
Das „Abenteuer“ mit dem Mozilla Thunderbird-E-Mail-Client begann mit einem automatischen Upgrade auf Version 68.0. Bemerkenswerte Merkmale dieser Version waren: Popup-Benachrichtigungen und einem dunklen Thema werden standardmäßig mehr Text hinzugefügt. Es gab einen Fehler, den ich mithilfe einer statischen Analyse erkennen wollte. Dies war eine Gelegenheit, den Quellcode des Projekts erneut mit PVS-Studio zu überprüfen. Es stellte sich heraus, dass der Fehler zum Zeitpunkt der Analyse bereits behoben war. Da wir jedoch auf dieses Projekt aufmerksam gemacht haben, können wir über andere darin festgestellte Mängel schreiben.

Einführung


Das dunkle Thema der neuen Version von Thunderbird sieht ziemlich hübsch aus. Ich liebe dunkle Themen. Bereits in Instant Messenger, Windows, MacOS auf sie umgestellt. In Kürze wird das iPhone auf iOS 13 aktualisiert, wo ein dunkles Thema angezeigt wurde. Dafür musste ich sogar mein iPhone 5S auf ein neueres Modell umstellen. In der Praxis stellte sich heraus, dass das dunkle Thema für Entwickler mehr Aufwand erfordert, um die Farben der Benutzeroberfläche auszuwählen. Nicht jeder kommt beim ersten Mal damit klar. Meine Standard-Tags in Thunderbird sahen also so aus:

Bild 1


Ich benutze sechs Tags (5 Standard + 1 benutzerdefinierte), um E-Mails zu markieren. Es wurde unmöglich, die Hälfte von ihnen nach dem Update zu sehen, und ich beschloss, die Farbe in den Einstellungen heller zu ändern. Aber hier bin ich auf einen Fehler gestoßen:

Bild 2


Sie können die Farbe des Tags nicht ändern !!! Genauer gesagt ist es möglich, aber der Editor lässt nicht zu, dass es unter Bezugnahme auf einen vorhandenen Namen (WTF ???) gespeichert wird.

Eine weitere Manifestation des Fehlers ist die Untätigkeit der Schaltfläche "OK", wenn Sie versuchen, den Namen zu ändern, da Sie nicht mit diesem Namen speichern können. Sie können auch nicht umbenennen.

Schließlich können Sie feststellen, dass das dunkle Thema die Einstellungen nicht berührt hat, was auch nicht sehr schön ist.

Nach einem langen Kampf mit dem Build-System in Windows war es immer noch möglich, Thunderbird aus dem Quellcode zusammenzusetzen. Die neueste Version des Mail-Clients erwies sich als viel besser als die neueste Version. Darin kam ein dunkles Thema zu den Einstellungen, und dieser Fehler mit dem Tag-Editor verschwand ebenfalls. Damit die Montagearbeiten des Projekts nicht verschwendet werden, wurde der statische Code-Analysator PVS-Studio gestartet.

Hinweis Der Thunderbird-Quellcode überschneidet sich irgendwie mit der Firefox-Codebasis. Daher umfasste die Analyse Fehler von verschiedenen Komponenten, die einen genauen Blick auf die Entwickler verschiedener Teams wert sind.

Anmerkung 2 Während der Artikel geschrieben wurde, wurde im Thunderbird 68.1-Update ein Fehler behoben:

Bild 5


comm


comm-central ist ein Mercurial-Repository des Thunderbird-, SeaMonkey- und Lightning-Erweiterungscodes.

V501 Links und rechts vom '||' befinden sich identische Unterausdrücke '(! Strcmp (Header, "Reply-To"))'. Betreiber. nsEmitterUtils.cpp 28

extern "C" bool EmitThisHeaderForPrefSetting(int32_t dispType, const char *header) { .... if (nsMimeHeaderDisplayTypes::NormalHeaders == dispType) { if ((!strcmp(header, HEADER_DATE)) || (!strcmp(header, HEADER_TO)) || (!strcmp(header, HEADER_SUBJECT)) || (!strcmp(header, HEADER_SENDER)) || (!strcmp(header, HEADER_RESENT_TO)) || (!strcmp(header, HEADER_RESENT_SENDER)) || (!strcmp(header, HEADER_RESENT_FROM)) || (!strcmp(header, HEADER_RESENT_CC)) || (!strcmp(header, HEADER_REPLY_TO)) || (!strcmp(header, HEADER_REFERENCES)) || (!strcmp(header, HEADER_NEWSGROUPS)) || (!strcmp(header, HEADER_MESSAGE_ID)) || (!strcmp(header, HEADER_FROM)) || (!strcmp(header, HEADER_FOLLOWUP_TO)) || (!strcmp(header, HEADER_CC)) || (!strcmp(header, HEADER_ORGANIZATION)) || (!strcmp(header, HEADER_REPLY_TO)) || (!strcmp(header, HEADER_BCC))) return true; else return false; .... } 

Die Kopfzeile wurde zweimal mit der Konstanten HEADER_REPLY_TO verglichen. Vielleicht hätte es an seiner Stelle eine andere Konstante geben sollen.

V501 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke 'obj-> options-> headers! = MimeHeadersCitation'. mimemsig.cpp 536

 static int MimeMultipartSigned_emit_child(MimeObject *obj) { .... if (obj->options && obj->options->headers != MimeHeadersCitation && obj->options->write_html_p && obj->options->output_fn && obj->options->headers != MimeHeadersCitation && sig->crypto_closure) { .... } .... } 

Ein weiterer seltsamer Vergleich einer Variablen mit einem ähnlichen Namen sind Header . Wie immer gibt es zwei mögliche Erklärungen: einen zusätzlichen Scheck oder einen Tippfehler.

V517 Die Verwendung des Musters 'if (A) {...} else if (A) {...}' wurde erkannt. Es besteht die Wahrscheinlichkeit eines logischen Fehlers. Überprüfen Sie die Zeilen: 1306, 1308. MapiApi.cpp 1306

 void CMapiApi::ReportLongProp(const char *pTag, LPSPropValue pVal) { if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_LONG)) { nsCString num; nsCString num2; num.AppendInt((int32_t)pVal->Value.l); num2.AppendInt((int32_t)pVal->Value.l, 16); MAPI_TRACE3("%s %s, 0x%s\n", pTag, num, num2); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) { MAPI_TRACE1("%s {NULL}\n", pTag); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) { // <= MAPI_TRACE1("%s {Error retrieving property}\n", pTag); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) { // <= MAPI_TRACE1("%s {Error retrieving property}\n", pTag); } else { MAPI_TRACE1("%s invalid value, expecting long\n", pTag); } if (pVal) MAPIFreeBuffer(pVal); } 

Die Kaskade der bedingten Ausdrücke wurde durch Drücken von Strg + C und Strg + V deutlich beschleunigt. Infolgedessen wird einer der Zweige niemals ausgeführt.

V517 Die Verwendung des Musters 'if (A) {...} else if (A) {...}' wurde erkannt. Es besteht die Wahrscheinlichkeit eines logischen Fehlers. Überprüfen Sie die Zeilen: 777, 816. nsRDFContentSink.cpp 777

 nsresult RDFContentSinkImpl::GetIdAboutAttribute(const char16_t** aAttributes, nsIRDFResource** aResource, bool* aIsAnonymous) { .... if (localName == nsGkAtoms::about) { .... } else if (localName == nsGkAtoms::ID) { .... } else if (localName == nsGkAtoms::nodeID) { nodeID.Assign(aAttributes[1]); } else if (localName == nsGkAtoms::about) { // XXX we don't deal with aboutEach... //MOZ_LOG(gLog, LogLevel::Warning, // ("rdfxml: ignoring aboutEach at line %d", // aNode.GetSourceLineNumber())); } .... } 

Die erste und letzte Bedingung sind gleich. Der Code zeigt an, dass der Code gerade geschrieben wird. Man kann mit Sicherheit sagen, dass sich der Fehler mit hoher Wahrscheinlichkeit nach Abschluss des Codes manifestiert. Ein Programmierer kann den kommentierten Code ändern, erhält jedoch niemals die Kontrolle. Seien Sie vorsichtig und vorsichtig mit diesem Code.

V522 Es kann zu einer Dereferenzierung der Nullzeigerzeile kommen. morkRowCellCursor.cpp 175

 NS_IMETHODIMP morkRowCellCursor::MakeCell( // get cell at current pos in the row nsIMdbEnv* mev, // context mdb_column* outColumn, // column for this particular cell mdb_pos* outPos, // position of cell in row sequence nsIMdbCell** acqCell) { nsresult outErr = NS_OK; nsIMdbCell* outCell = 0; mdb_pos pos = 0; mdb_column col = 0; morkRow* row = 0; morkEnv* ev = morkEnv::FromMdbEnv(mev); if (ev) { pos = mCursor_Pos; morkCell* cell = row->CellAt(ev, pos); if (cell) { col = cell->GetColumn(); outCell = row->AcquireCellHandle(ev, cell, col, pos); } outErr = ev->AsErr(); } if (acqCell) *acqCell = outCell; if (outPos) *outPos = pos; if (outColumn) *outColumn = col; return outErr; } 

Die Dereferenzierung des Zeilennullzeigers ist in der folgenden Zeile möglich:

 morkCell* cell = row->CellAt(ev, pos); 

Höchstwahrscheinlich wurde die Zeigerinitialisierung vor dieser Zeile übersprungen, z. B. mithilfe der GetRow- Methode usw.

V543 Es ist merkwürdig, dass der Variablen 'm_lastError' vom Typ HRESULT der Wert '-1' zugewiesen wird. MapiApi.cpp 1050

 class CMapiApi { .... private: static HRESULT m_lastError; .... }; CMsgStore *CMapiApi::FindMessageStore(ULONG cbEid, LPENTRYID lpEid) { if (!m_lpSession) { MAPI_TRACE0("FindMessageStore called before session is open\n"); m_lastError = -1; return NULL; } .... } 

Der HRESULT- Typ ist ein komplexer Datentyp. Unterschiedliche Bits einer Variablen dieses Typs repräsentieren unterschiedliche Fehlerbeschreibungsfelder. Der Fehlercode muss mithilfe spezieller Konstanten aus den Systemheaderdateien festgelegt werden.

Noch ein paar dieser Orte:

  • V543 Es ist merkwürdig, dass der Variablen 'm_lastError' vom Typ HRESULT der Wert '-1' zugewiesen wird. MapiApi.cpp 817
  • V543 Es ist merkwürdig, dass der Variablen 'm_lastError' vom Typ HRESULT der Wert '-1' zugewiesen wird. MapiApi.cpp 1749

V579 Die Memset-Funktion empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das dritte Argument. icalmime.c 195

 icalcomponent* icalmime_parse(....) { struct sspm_part *parts; int i, last_level=0; icalcomponent *root=0, *parent=0, *comp=0, *last = 0; if ( (parts = (struct sspm_part *) malloc(NUM_PARTS*sizeof(struct sspm_part)))==0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } memset(parts,0,sizeof(parts)); sspm_parse_mime(parts, NUM_PARTS, /* Max parts */ icalmime_local_action_map, /* Actions */ get_string, data, /* data for get_string*/ 0 /* First header */); .... } 

Die Teilevariable ist ein Zeiger auf ein Array von Strukturen. Um die Werte von Strukturen zurückzusetzen, verwendeten sie die Memset- Funktion, übertrugen jedoch die Größe des Zeigers als Größe eines Speicherstücks darauf.

Andere verdächtige Orte:

  • V579 Die Memset-Funktion empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das dritte Argument. icalmime.c 385
  • V579 Die Memset-Funktion empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das dritte Argument. icalparameter.c 114
  • V579 Die Funktion snprintf empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das zweite Argument. icaltimezone.c 1908
  • V579 Die Funktion snprintf empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das zweite Argument. icaltimezone.c 1910
  • V579 Die Funktion strncmp empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das dritte Argument. sspm.c 707
  • V579 Die Funktion strncmp empfängt den Zeiger und seine Größe als Argumente. Es ist möglicherweise ein Fehler. Untersuchen Sie das dritte Argument. sspm.c 813

V595 Der Zeiger 'aValues' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 553, 555. nsLDAPMessage.cpp 553

 NS_IMETHODIMP nsLDAPMessage::GetBinaryValues(const char *aAttr, uint32_t *aCount, nsILDAPBERValue ***aValues) { .... *aValues = static_cast<nsILDAPBERValue **>( moz_xmalloc(numVals * sizeof(nsILDAPBERValue))); if (!aValues) { ldap_value_free_len(values); return NS_ERROR_OUT_OF_MEMORY; } .... } 

Diagnose V595 findet normalerweise typische Nullzeiger-Dereferenzierungsfehler. Es wurde jedoch ein sehr interessanter Fall gefunden, der besondere Aufmerksamkeit verdient.

Technisch gesehen hat der Analysator Recht, dass der aValues- Zeiger zuerst dereferenziert und dann überprüft wird, aber der Fehler ist anders. Dies ist ein Doppelzeiger, daher sollte der richtige Code folgendermaßen aussehen:

 *aValues = static_cast<nsILDAPBERValue **>( moz_xmalloc(numVals * sizeof(nsILDAPBERValue))); if (!*aValues) { ldap_value_free_len(values); return NS_ERROR_OUT_OF_MEMORY; } 

Ein weiterer sehr ähnlicher Ort:

  • V595 Der Zeiger '_retval' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 357, 358. nsLDAPSyncQuery.cpp 357

V1044 Schleifenunterbrechungsbedingungen hängen nicht von der Anzahl der Iterationen ab. mimemoz2.cpp 1795

 void ResetChannelCharset(MimeObject *obj) { .... if (cSet) { char *ptr2 = cSet; while ((*cSet) && (*cSet != ' ') && (*cSet != ';') && (*cSet != '\r') && (*cSet != '\n') && (*cSet != '"')) ptr2++; if (*cSet) { PR_FREEIF(obj->options->default_charset); obj->options->default_charset = strdup(cSet); obj->options->override_charset = true; } PR_FREEIF(cSet); } .... } 

Dieser Fehler wurde mithilfe der neuen Diagnose festgestellt, die in der nächsten Version des Analysators verfügbar sein wird. Alle Variablen, die in der Bedingung zum Stoppen der while-Schleife verwendet werden, werden nicht geändert, da die Variablen ptr2 und cSet im Funktionskörper verwechselt werden.

netwerk


netwerk enthält C-Schnittstellen und Code für den Zugriff auf das Netzwerk auf niedriger Ebene (mithilfe von Sockets und Datei- und Speichercaches) sowie auf Zugriff auf höherer Ebene (mithilfe verschiedener Protokolle wie http, ftp, gopher, castanet). Dieser Code ist auch unter den Namen "netlib" und "Necko" bekannt.

V501 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke 'connectStarted'. nsSocketTransport2.cpp 1693

 nsresult nsSocketTransport::InitiateSocket() { .... if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() && connectStarted && connectCalled) { // <= good, line 1630 SendPRBlockingTelemetry( connectStarted, Telemetry::PRCONNECT_BLOCKING_TIME_NORMAL, Telemetry::PRCONNECT_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCONNECT_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCONNECT_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCONNECT_BLOCKING_TIME_OFFLINE); } .... if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() && connectStarted && connectStarted) { // <= fail, line 1694 SendPRBlockingTelemetry( connectStarted, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_NORMAL, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_OFFLINE); } .... } 

Zuerst dachte ich, dass das Duplizieren der Variablen connectStarted nur überflüssiger Code ist, bis ich die gesamte ausreichend lange Funktion durchgesehen und ein ähnliches Fragment gefunden habe. Anstelle einer einzelnen Variablen connectStarted sollte hier höchstwahrscheinlich auch eine Variable connectCalled verwendet werden .

V611 Der Speicher wurde mit dem Operator 'new T []' zugewiesen, aber mit dem Operator 'delete' freigegeben. Überprüfen Sie diesen Code. Es ist wahrscheinlich besser, 'delete [] mData;' zu verwenden. Überprüfen Sie die Zeilen: 233, 222. DataChannel.cpp 233

 BufferedOutgoingMsg::BufferedOutgoingMsg(OutgoingMsg& msg) { size_t length = msg.GetLeft(); auto* tmp = new uint8_t[length]; // infallible malloc! memcpy(tmp, msg.GetData(), length); mLength = length; mData = tmp; mInfo = new sctp_sendv_spa; *mInfo = msg.GetInfo(); mPos = 0; } BufferedOutgoingMsg::~BufferedOutgoingMsg() { delete mInfo; delete mData; } 

Der mData- Zeiger zeigt auf ein Array, nicht auf ein einzelnes Objekt. Sie haben einen Fehler im Klassendestruktor gemacht und vergessen, Klammern für den Löschoperator hinzuzufügen.

V1044 Schleifenunterbrechungsbedingungen hängen nicht von der Anzahl der Iterationen ab. ParseFTPList.cpp 691

 int ParseFTPList(....) { .... pos = toklen[2]; while (pos > (sizeof(result->fe_size) - 1)) pos = (sizeof(result->fe_size) - 1); memcpy(result->fe_size, tokens[2], pos); result->fe_size[pos] = '\0'; .... } 

Der Wert von pos wird in der Schleife um den gleichen Betrag überschrieben. Es scheint, dass die neue Diagnose einen weiteren Fehler gefunden hat.

gfx


gfx enthält C-Schnittstellen und Code für plattformunabhängiges Zeichnen und Imaging. Es kann verwendet werden, um Rechtecke, Linien, Bilder usw. zu zeichnen. Im Wesentlichen handelt es sich um eine Reihe von Schnittstellen für einen plattformunabhängigen Gerätekontext (Zeichnungskontext). Widgets oder bestimmte Zeichenroutinen werden nicht verarbeitet. Es werden nur die primitiven Operationen zum Zeichnen bereitgestellt.

V501 Links und rechts vom '||' befinden sich identische Unterausdrücke. Operator: mVRSystem || mVRCompositor || mVRSystem OpenVRSession.cpp 876

 void OpenVRSession::Shutdown() { StopHapticTimer(); StopHapticThread(); if (mVRSystem || mVRCompositor || mVRSystem) { ::vr::VR_Shutdown(); mVRCompositor = nullptr; mVRChaperone = nullptr; mVRSystem = nullptr; } } 

In der Bedingung ist die Variable mVRSystem zweimal vorhanden. Offensichtlich sollte einer von ihnen durch mVRChaperon ersetzt werden .

dom


dom enthält C-Schnittstellen und Code zum Implementieren und Verfolgen von DOM-Objekten (Document Object Model) in Javascript. Es bildet die C-Unterstruktur, die integrierte und benutzerdefinierte Objekte gemäß dem Javascript-Skript erstellt, zerstört und bearbeitet.

V570 Die Variable 'clonedDoc-> mPreloadReferrerInfo' wird sich selbst zugewiesen. Document.cpp 12049

 already_AddRefed<Document> Document::CreateStaticClone( nsIDocShell* aCloneContainer) { .... clonedDoc->mReferrerInfo = static_cast<dom::ReferrerInfo*>(mReferrerInfo.get())->Clone(); clonedDoc->mPreloadReferrerInfo = clonedDoc->mPreloadReferrerInfo; .... } 

Der Analysator hat die Zuordnung einer Variablen zu sich selbst erkannt.

xpcom


xpcom enthält die C-Schnittstellen auf niedriger Ebene, C-Code, C-Code, ein bisschen Assembly-Code und Befehlszeilen-Tools zum Implementieren der grundlegenden Maschinerie von XPCOM-Komponenten (was für "Platform Component Component Object Model" steht). XPCOM ist der Mechanismus, mit dem Mozilla Schnittstellen exportieren und automatisch für JavaScript-Skripte, Microsoft COM und regulären Mozilla C-Code verfügbar machen kann.

V611 Der Speicher wurde mit der Funktion 'malloc / realloc' zugewiesen, aber mit dem Operator 'delete' freigegeben. Überprüfen Sie die Betriebslogik hinter der Variablen 'key'. Überprüfen Sie die Zeilen: 143, 140. nsINIParser.h 143

 struct INIValue { INIValue(const char* aKey, const char* aValue) : key(strdup(aKey)), value(strdup(aValue)) {} ~INIValue() { delete key; delete value; } void SetValue(const char* aValue) { delete value; value = strdup(aValue); } const char* key; const char* value; mozilla::UniquePtr<INIValue> next; }; 

Nach dem Aufrufen der Funktion strdup müssen Sie Speicher mit der Funktion free freigeben , nicht mit dem Operator delete .

V716 Verdächtige Typkonvertierung bei der Initialisierung: 'HRESULT var = BOOL'. SpecialSystemDirectory.cpp 73

 BOOL SHGetSpecialFolderPathW( HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate ); static nsresult GetWindowsFolder(int aFolder, nsIFile** aFile) { WCHAR path_orig[MAX_PATH + 3]; WCHAR* path = path_orig + 1; HRESULT result = SHGetSpecialFolderPathW(nullptr, path, aFolder, true); if (!SUCCEEDED(result)) { return NS_ERROR_FAILURE; } .... } 

Die WinGI SHGetSpecialFolderPathW- Funktion gibt einen Wert vom Typ BOOL zurück , nicht HRESULT . Überprüfen Sie, ob das Ergebnis der Funktion auf das richtige umgeschrieben werden muss.

nsprpub


nsprpub enthält C-Code für die plattformübergreifende Laufzeitbibliothek "C". Die C-Laufzeitbibliothek enthält grundlegende nicht visuelle C-Funktionen zum Zuweisen und Freigeben von Speicher, Abrufen von Uhrzeit und Datum, Lesen und Schreiben von Dateien, Behandeln von Threads sowie Behandeln und Vergleichen von Zeichenfolgen auf allen Plattformen

V647 Der Wert vom Typ 'int' wird dem Zeiger vom Typ 'short' zugewiesen. Überprüfen Sie die Zuordnung: 'out_flags = 0x2'. prsocket.c 1220

 #define PR_POLL_WRITE 0x2 static PRInt16 PR_CALLBACK SocketPoll( PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) { *out_flags = 0; #if defined(_WIN64) if (in_flags & PR_POLL_WRITE) { if (fd->secret->alreadyConnected) { out_flags = PR_POLL_WRITE; return PR_POLL_WRITE; } } #endif return in_flags; } /* SocketPoll */ 

Der Analysator hat die Zuordnung einer numerischen Konstante zum Zeiger out_flags festgestellt . Höchstwahrscheinlich haben sie einfach vergessen, ihn zu dereferenzieren:

 if (fd->secret->alreadyConnected) { *out_flags = PR_POLL_WRITE; return PR_POLL_WRITE; } 

Fazit


Dies ist nicht das Ende. Seien Sie neue Code-Bewertungen. Der Thunderbird- und Firefox-Code enthält zwei Hauptbibliotheken: Network Security Services (NSS) und WebRTC (Web Real Time Communications). Es gab einige sehr interessante Fehler. In dieser Rezension werde ich eine nach der anderen zeigen.

Nss

V597 Der Compiler könnte den Funktionsaufruf 'memset' löschen, mit dem der 'newdeskey'-Puffer geleert wird. Die Funktion RtlSecureZeroMemory () sollte verwendet werden, um die privaten Daten zu löschen. pkcs11c.c 1033

 static CK_RV sftk_CryptInit(....) { .... unsigned char newdeskey[24]; .... context->cipherInfo = DES_CreateContext( useNewKey ? newdeskey : (unsigned char *)att->attrib.pValue, (unsigned char *)pMechanism->pParameter, t, isEncrypt); if (useNewKey) memset(newdeskey, 0, sizeof newdeskey); sftk_FreeAttribute(att); .... } 

NSS ist eine Bibliothek zum Entwickeln sicherer Client- und Serveranwendungen, und hier wird DES Key nicht bereinigt. Der Compiler entfernt den Memset- Aufruf aus dem Code als Das newdeskey- Array wird in Code außerhalb dieses Speicherorts nicht mehr verwendet.

WebRTC

V519 Der Variablen 'state [state_length - x_length + i]' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 83, 84. filter_ar.c 84

 size_t WebRtcSpl_FilterAR(....) { .... for (i = 0; i < state_length - x_length; i++) { state[i] = state[i + x_length]; state_low[i] = state_low[i + x_length]; } for (i = 0; i < x_length; i++) { state[state_length - x_length + i] = filtered[i]; state[state_length - x_length + i] = filtered_low[i]; // <= } .... } 

Im zweiten Zyklus werden Daten in das falsche Array geschrieben, da der Autor den Code kopiert und vergessen hat, den Namen des Arrays von state in state_low zu ändern .

Es gibt wahrscheinlich interessantere Fehler in diesen Projekten, die es wert sind, erwähnt zu werden. Und wir werden es in naher Zukunft tun. Probieren Sie in der Zwischenzeit PVS-Studio für Ihr Projekt aus.



Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Svyatoslav Razmyslov. Dunkles Thema von Thunderbird als Grund, einen Code-Analysator auszuführen .

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


All Articles