Es ist schon drei Monate her, seit 2018 vorbei ist. Für viele flog es fast unmerklich, aber für uns, die Entwickler von PVS-Studio, stellte sich heraus, dass es sehr gesättigt war. Wir haben hart gearbeitet, furchtlos für die Weiterentwicklung der statischen Analyse für die Massen gekämpft und nach neuen Fehlern in Open-Source-Projekten gesucht, die in C, C ++, C # und Java geschrieben wurden. Die zehn interessantesten davon haben wir in diesem Artikel für Sie gesammelt!
Mit dem statischen Code-Analysator
PVS-Studio haben wir nach interessanten Orten gesucht. Es kann Fehler und potenzielle Schwachstellen in Code erkennen, der in den oben genannten Sprachen geschrieben wurde.
Wenn Sie selbst nach Fehlern suchen möchten, können Sie unseren Analysator jederzeit herunterladen und ausprobieren. Wir bieten eine
kostenlose Version des Analysators für Studenten und begeisterte Programmierer, eine
kostenlose Lizenz für Entwickler von Open-Source-Projekten sowie eine
Testversion für All-All-All. Wer weiß, vielleicht können Sie bis zum nächsten Jahr Ihre Top 10 erreichen? :) :)
Hinweis: Ich schlage vor, dass der Leser sich selbst überprüft und vor dem Betrachten der Analysatorwarnung versucht, die Anomalien selbst zu identifizieren. Wie viele Fehler können Sie finden?
Zehnter Platz
Quelle:
Und wieder ins All: wie das Einhorn Stellarium besuchteDieser Fehler wurde beim Überprüfen des virtuellen Stellarium-Planetariums entdeckt.
Das obige Code-Snippet ist zwar klein, aber mit einem ziemlich kniffligen Fehler behaftet:
Plane::Plane(Vec3f &v1, Vec3f &v2, Vec3f &v3) : distance(0.0f), sDistance(0.0f) { Plane(v1, v2, v3, SPolygon::CCW); }
Hast du gefunden?
PVS-Studio Warnung: V603 Das Objekt wurde erstellt, wird jedoch nicht verwendet. Wenn Sie den Konstruktor aufrufen möchten, sollte 'this-> Plane :: Plane (....)' verwendet werden. Plane.cpp 29
Der Autor des Codes wollte einen Teil der Felder des Objekts mit einem anderen Konstruktor initialisieren, der im Hauptkonstruktor verschachtelt ist. Es ist ihm jedoch nur gelungen, ein temporäres Objekt zu erstellen, das beim Verlassen seines Sichtbereichs zerstört wird. Somit bleiben mehrere Felder des Objekts nicht initialisiert.
Anstelle eines verschachtelten Konstruktoraufrufs sollten Sie den in C ++ 11 eingeführten delegierenden Konstruktor verwenden. Zum Beispiel könnten Sie dies tun:
Plane::Plane(Vec3f& v1, Vec3f& v2, Vec3f& v3) : Plane(v1, v2, v3, SPolygon::CCW) { distance = 0.0f; sDistance = 0.0f; }
Dann würden alle erforderlichen Felder korrekt initialisiert. Ist es nicht wunderbar?
Neunter Platz
Quelle:
Perl 5: Wie sich Makrofehler verstecktenAuf dem neunten Platz wird ein bemerkenswertes Makro aus dem Perl 5-Quellcode zur Schau gestellt.
Als mein Kollege Svyatoslav Fehler beim Schreiben des Artikels sammelte, stieß er auf eine Warnung des Analysators zur Verwendung eines Makros. Hier ist es:
PP(pp_match) { .... MgBYTEPOS_set(mg, TARG, truebase, RXp_OFFS(prog)[0].end); .... }
Um herauszufinden, was los war, grub Svyatoslav tiefer. Er öffnete die Makrodefinition und stellte fest, dass sie mehrere weitere verschachtelte Makros enthielt, von denen einige auch verschachtelte Makros enthielten. Es war so schwer herauszufinden, dass ich eine vorverarbeitete Datei verwenden musste. Aber leider hat das nicht geholfen. Anstelle der vorherigen Codezeile entdeckte Swjatoslaw Folgendes:
(((targ)->sv_flags & 0x00000400) && (!((targ)->sv_flags & 0x00200000) || S_sv_only_taint_gmagic(targ)) ? (mg)->mg_len = ((prog->offs)[0].end), (mg)->mg_flags |= 0x40 : ((mg)->mg_len = (((targ)->sv_flags & 0x20000000) && !__builtin_expect(((((PL_curcop)->cop_hints + 0) & 0x00000008) ? (_Bool)1 :(_Bool)0),(0))) ? (ssize_t)Perl_utf8_length( (U8 *)(truebase), (U8 *)(truebase)+((prog->offs)[0].end)) : (ssize_t)((prog->offs)[0].end), (mg)->mg_flags &= ~0x40));
Warnung PVS-Studio: V502 Möglicherweise
funktioniert der Operator '?:' Anders als erwartet. Der Operator '?:' Hat eine niedrigere Priorität als der Operator '&&'. pp_hot.c 3036
Ich denke, es wird schwierig sein, einen solchen Fehler mit meinen Augen zu finden. Ehrlich gesagt haben wir lange über diesen Code meditiert und sind zu dem Schluss gekommen, dass hier tatsächlich kein Fehler vorliegt. In jedem Fall ist dies jedoch ein unterhaltsames Beispiel für unlesbaren Code.
Makros sollen böse sein. Natürlich gibt es Zeiten, in denen sie sich als unverzichtbar herausstellen, aber wenn Sie das Makro durch eine Funktion ersetzen können, sollten Sie dies auf jeden Fall tun.
Verschachtelte Makros sind besonders voll. Nicht nur, weil sie schwer zu verstehen sind, sondern auch, weil sie unvorhersehbare Ergebnisse liefern können. Wenn der Autor eines Makros versehentlich einen Fehler in einem solchen Makro macht, ist es viel schwieriger, ihn zu finden als in einer Funktion.
Achter Platz
Quelle:
Chrom: Andere FehlerDas folgende Beispiel stammt aus einer Reihe von Artikeln zur Analyse des Chromium-Projekts. Sie deckte sich in der WebRTC-Bibliothek ab.
std::vector<SdpVideoFormat> StereoDecoderFactory::GetSupportedFormats() const { std::vector<SdpVideoFormat> formats = ....; for (const auto& format : formats) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } } return formats; }
PVS-Studio Warnung: V789 CWE-672 Iteratoren für den Container 'Formate', die in der bereichsbasierten for-Schleife verwendet werden, werden beim Aufruf der Funktion 'push_back' ungültig. stereocodecfactory.cc 89
Der Fehler besteht darin, dass sich die Größe des
Formatvektors innerhalb der bereichsbasierten for-Schleife ändert. Bereichsbasierte Schleifen basieren auf Iteratoren. Daher kann die Größenänderung des Containers in solchen Schleifen zur Ungültigmachung dieser Iteratoren führen.
Dieser Fehler bleibt bestehen, wenn Sie die Schleife mit expliziten Iteratoren neu schreiben. Aus Gründen der Übersichtlichkeit können Sie diesen Code daher mitbringen:
for (auto format = begin(formats), __end = end(formats); format != __end; ++format) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } }
Wenn Sie beispielsweise die
push_back- Methode verwenden, wird möglicherweise ein Vektor freigegeben, und dann zeigen Iteratoren auf einen ungültigen Speicherbereich.
Um solche Fehler zu vermeiden, sollten Sie die Regel einhalten: Ändern Sie niemals die Größe des Containers innerhalb der Schleife, deren Bedingungen an diesen Container gebunden sind. Dies gilt für bereichsbasierte Schleifen und Schleifen mit Iteratoren. In
Diskussionen zu StackOverflow können Sie nachlesen, welche Vorgänge zur Ungültigmachung von Iteratoren führen können.
Siebter Platz
Quelle:
Godot: Regelmäßige Verwendung von Static Code AnalyzersDas erste Beispiel aus der Videospielbranche wird ein Codeausschnitt sein, den wir in der Godot-Spiele-Engine entdeckt haben. Sie müssen vielleicht schwitzen, um den Fehler mit Ihren Augen zu entdecken, aber ich bin sicher, dass unsere erfahrenen Leser damit umgehen können:
void AnimationNodeBlendSpace1D::add_blend_point( const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) { ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { for (int i = blend_points_used - 1; i > p_at_index; i++) { blend_points[i] = blend_points[i - 1]; } } .... }
PVS-Studio Warnung: V621 CWE-835 Überprüfen Sie den '
for' - Operator. Es ist möglich, dass die Schleife falsch oder gar nicht ausgeführt wird. animation_blend_space_1d.cpp 113
Betrachten wir den Zustand des Zyklus genauer. Die
Zählervariable wird mit dem Wert
blend_points_used - 1 initialisiert. Gleichzeitig wird anhand der beiden vorherigen Überprüfungen (in
ERR_FAIL_COND und in
if ) klar, dass zum Zeitpunkt der Ausführung der Schleife
blend_points_used immer größer als
p_at_index ist . Somit ist entweder die Schleifenbedingung immer wahr oder die Schleife wird überhaupt nicht ausgeführt.
Wenn
blend_points_used 1 == p_at_index ist , wird die Schleife nicht ausgeführt.
In allen anderen Fällen ist die Prüfung
i> p_at_index immer wahr, da der Zähler
i bei jeder Iteration der Schleife zunimmt.
Es mag scheinen, dass der Zyklus für immer laufen wird, aber es ist nicht so.
Erstens wird es einen ganzzahligen Überlauf der Variablen
i geben , was ein undefiniertes Verhalten ist. Verlassen Sie sich daher darauf, dass es sich nicht lohnt.
Wenn
ich vom Typ
unsigned int wäre, würde der
i ++ - Operator den Zähler in
0 umwandeln , nachdem er den maximal möglichen Wert erreicht hat. Dieses Verhalten wird vom Standard definiert und als "vorzeichenlose Umhüllung" bezeichnet. Sie sollten sich jedoch bewusst sein, dass die Verwendung eines solchen Mechanismus ebenfalls
keine gute Idee ist .
Das war erstens, aber es gibt noch zweitens! Tatsache ist, dass es nicht einmal den ganzzahligen Überlauf erreicht. Wohin geht das Array ins Ausland? Dies bedeutet, dass versucht wird, auf den Speicherbereich außerhalb des für das Array zugewiesenen Blocks zuzugreifen. Und auch dies ist ein vages Verhalten. Klassisches Beispiel :)
Um solche Fehler leichter vermeiden zu können, kann ich nur einige Empfehlungen geben:
- Schreiben Sie einfacheren, intuitiveren Code
- Führen Sie eine gründlichere Codeüberprüfung durch und schreiben Sie weitere Tests für frisch geschriebenen Code
- Verwenden Sie statische Analysegeräte;)
Sechster Platz
Quelle:
Amazon Lumberyard: Der Schrei der SeeleEin weiteres Beispiel aus der Gamedev-Branche, nämlich aus dem Quellcode der Amazon Lumberyard AAA-Engine.
void TranslateVariableNameByOperandType(....) {
PVS-Studio Warnung: V523 Die Anweisung 'then' entspricht der Anweisung 'else'. toglsloperand.c 700
Amazon Lumberyard wird als plattformübergreifende Engine entwickelt. Daher versuchen Entwickler, so viele Compiler wie möglich zu unterstützen. Der Programmierer Igor ist auf den Qualcomm-Compiler gestoßen, wie die Kommentare zeigen.
Es ist nicht bekannt, ob Igor seine Aufgabe erfüllen und die "paranoiden" Überprüfungen des Compilers bewältigen konnte, aber er hinterließ einen sehr seltsamen Code. Es ist
insofern seltsam, als sowohl die
damaligen als auch die
anderen Zweige der
if-Anweisung absolut identischen Code enthalten. Höchstwahrscheinlich wurde ein solcher Fehler durch ein schlampiges Kopieren und Einfügen verursacht.
Ich weiß nicht einmal, was hier empfohlen werden kann. Daher wünsche ich den Entwicklern von Amazon Lumberyard viel Erfolg bei der Behebung von Fehlern und viel Glück für Programmierer Igor!
Fünfter Platz
Quelle:
Der PVS-Studio-Analysator erwies sich erneut als aufmerksamer als eine PersonEine interessante Geschichte ereignete sich mit dem folgenden Beispiel. Mein Kollege Andrei Karpov bereitete einen Artikel über den nächsten Test des Qt-Frameworks vor. Während er bemerkenswerte Fehler schrieb, stieß er auf eine Analysatorwarnung, die er als falsch betrachtete. Hier ist das relevante Code-Snippet und die Warnung:
QWindowsCursor::CursorState QWindowsCursor::cursorState() { enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; CURSORINFO cursorInfo; cursorInfo.cbSize = sizeof(CURSORINFO); if (GetCursorInfo(&cursorInfo)) { if (cursorInfo.flags & CursorShowing)
PVS-Studio Warnung: V616 CWE-480 Die benannte Konstante 'CursorShowing' mit dem Wert 0 wird in der bitweisen Operation verwendet. qwindowscursor.cpp 669
Das heißt, PVS-Studio hat an einem Ort geschworen, an dem offensichtlich kein Fehler aufgetreten ist! Es kann nicht sein, dass die
CursorShowing- Konstante
0 ist , da buchstäblich ein paar Zeilen darüber auf
1 initialisiert werden.
Da zur Überprüfung eine instabile Version des Analysators verwendet wurde, bezweifelte Andrei die Richtigkeit der Warnung. Er untersuchte diesen Codeabschnitt mehrmals sorgfältig und fand immer noch keinen Fehler. Infolgedessen schrieb er dieses falsche Positiv an den Bugtracker, damit andere Kollegen die Situation korrigieren konnten.
Und erst mit einer detaillierten Analyse wurde klar, dass PVS-Studio wieder aufmerksamer war als eine Person. Der Wert
0x1 wird der benannten Konstanten
cursorShowing zugewiesen , und die
Bitkonstantenoperation "und" beinhaltet die benannte Konstante
CursorShowing . Dies sind völlig unterschiedliche Konstanten, da die erste mit einem Kleinbuchstaben und die zweite mit einem Großbuchstaben beginnt.
Der Code wird erfolgreich kompiliert, da die
QWindowsCursor- Klasse wirklich eine Konstante mit diesem Namen enthält. Hier ist ihre Definition:
class QWindowsCursor : public QPlatformCursor { public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; .... }
Wenn Sie eine benannte Enum-Konstante nicht explizit zuweisen, wird sie standardmäßig initialisiert. Da
CursorShowing das erste Element einer Aufzählung ist, wird es auf
0 gesetzt .
Um solche Fehler zu vermeiden, sollten Sie Entitäten keine zu ähnlichen Namen geben. Sie sollten diese Regel besonders sorgfältig befolgen, wenn diese Entitäten vom gleichen Typ sind oder implizit ineinander umgewandelt werden können. In solchen Fällen ist es in der Tat fast unmöglich, einen Fehler mit dem Auge zu erkennen, und der falsche Code wird erfolgreich kompiliert und lebt glücklich in Ihrem Projekt.
Vierter Platz
Quelle:
Wir schießen in den Fuß und verarbeiten die EingabedatenWir nähern uns den drei besten Finalisten, und der Fehler aus dem FreeSWITCH-Projekt ist der nächste.
static const char *basic_gets(int *cnt) { .... int c = getchar(); if (c < 0) { if (fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) { break; } command_buf[strlen(command_buf)-1] = '\0'; break; } .... }
PVS-Studio Warnung: V1010 CWE-20 Nicht aktivierte fehlerhafte Daten werden im Index 'strlen (command_buf)' verwendet.
Der Analysator warnt, dass der Ausdruck
strlen (command_buf) - 1 nicht verifizierte Daten verwendet. Und wirklich: Wenn sich herausstellt, dass
command_buf aus Sicht der C-Sprachzeichenfolge (die ein einzelnes Zeichen enthält - '\ 0')
leer ist, gibt
strlen (command_buf) 0 zurück . In diesem Fall wird
command_buf [-1] aufgerufen , was ein undefiniertes Verhalten darstellt. Ärger!
Der eigentliche Saft dieses Fehlers ist nicht einmal,
warum es passiert, sondern
wie es passiert. Dieser Fehler ist eines dieser angenehmen Beispiele, die Sie selbst "berühren" und reproduzieren können. Sie können FreeSwitch starten, einige Aktionen ausführen, die zur Ausführung des obigen Codeabschnitts führen, und dem Programm eine leere Zeile zur Eingabe übergeben.
Infolgedessen verwandelt sich ein Arbeitsprogramm mit einem Handgriff (nein, keine
eleganten Shorts ) in ein nicht funktionierendes! Details zur Reproduktion dieses Fehlers finden Sie im Quellartikel unter dem obigen Link. Im Moment werde ich jedoch ein klares Ergebnis liefern:
Denken Sie daran, dass die Eingabe alles sein kann, und Sie sollten sie immer überprüfen. Dann schwört der Analysator nicht und das Programm ist zuverlässiger.
Jetzt ist es Zeit, sich mit unseren Gewinnern zu befassen: Wir ziehen ins Finale ein!
Dritter Platz
Quelle:
NCBI Genome Workbench: Gefährdete ForschungDie drei Gewinner werden durch einen Code aus dem NCBI Genome Workbench-Projekt eröffnet - eine Reihe von Tools zum Studieren und Analysieren genetischer Daten. Obwohl es nicht notwendig ist, ein gentechnisch veränderter Übermensch zu sein, um hier einen Fehler zu finden, sind sich einige dieser Möglichkeit bewusst.
void tds_answer_challenge(....) { .... if (ntlm_v == 1) { .... memset(hash, 0, sizeof(hash)); memset(passwd_buf, 0, sizeof(passwd_buf)); ... } else { .... } }
PVS-Studio-Warnungen:- V597 Der Compiler könnte den Funktionsaufruf 'memset' löschen, mit dem der 'Hash'-Puffer geleert wird. Die Funktion memset_s () sollte verwendet werden, um die privaten Daten zu löschen. Challenge.c 365
- V597 Der Compiler könnte den Funktionsaufruf 'memset' löschen, mit dem der Puffer 'passwd_buf' geleert wird. Die Funktion memset_s () sollte verwendet werden, um die privaten Daten zu löschen. Herausforderung.c 366
Haben Sie einen Fehler gefunden? Wenn ja, dann bist du - gut gemacht! .. gut oder immer noch ein gentechnisch veränderter Übermensch.
Tatsache ist, dass moderne Optimierungs-Compiler viel dazu beitragen können, dass das zusammengestellte Programm schneller funktioniert. Insbesondere können Compiler verfolgen, dass der an
memset übergebene Puffer nirgendwo anders verwendet wird.
In diesem Fall können sie den „unnötigen“
Memset- Aufruf löschen und haben das Recht dazu. Dann kann ein Puffer, der wichtige Daten speichert, zur Freude der Angreifer im Speicher verbleiben.
Vor diesem Hintergrund sieht der literarische Kommentar „Mit Sicherheit ist es gut, pedantisch zu sein“ noch lustiger aus. Gemessen an der sehr geringen Anzahl von Warnungen, die für dieses Projekt ausgegeben wurden, bemühten sich die Entwickler sehr, vorsichtig zu sein und sicheren Code zu schreiben. Wie wir jedoch sehen können, ist das Überspringen dieser Sicherheitslücke sehr einfach. Gemäß der Common Weakness Enumeration wird ein Fehler als
CWE-14 : Compiler-Entfernung von Code zum Löschen von Puffern klassifiziert.
Verwenden Sie die Funktion
memset_s () , um die Speicherbereinigung zu löschen. Es ist nicht nur sicherer als
memset () , sondern kann vom Compiler auch nicht "ignoriert" werden.
Zweiter Platz
Quelle:
Wie sich herausstellte, dass PVS-Studio aufmerksamer war als dreieinhalb ProgrammiererDer Silbermedaillengewinner dieses Tops wurde uns von einem unserer Kunden geschickt. Er war sich sicher, dass der Analysator falsche Warnungen erzeugte.
Eugene erhielt den Brief, scannte ihn kurz und schickte ihn an Svyatoslav. Svyatoslav betrachtete nachdenklich den vom Kunden gesendeten Codeabschnitt und dachte: "Kann der Analysator so offensichtlich falsch sein?" Deshalb hat er sich mit Andrei beraten lassen. Er überprüfte auch die Site und entschied: In der Tat gibt der Analysator falsch positive Ergebnisse aus.
Was können Sie tun, müssen Sie es beheben. Und erst als Svyatoslav anfing, synthetische Beispiele zu erstellen, um die Aufgabe als Bugtracker zu formalisieren, wurde ihm klar, was los war.
Fehler waren zwar im Code vorhanden, aber keiner der Programmierer konnte sie erkennen. Ehrlich gesagt war der Autor dieses Artikels auch nicht erfolgreich.
Und das trotz der Tatsache, dass der Analysator eindeutig Warnungen für die falschen Stellen ausgegeben hat!
Kannst du so einen schlauen Fehler finden? Testen Sie sich auf Wachsamkeit und Aufmerksamkeit.
PVS-Studio Warnung:- V560 Ein Teil des bedingten Ausdrucks ist immer falsch: (ch> = 0x0FF21). decodew.cpp 525
- V560 Ein Teil des bedingten Ausdrucks ist immer wahr: (ch <= 0x0FF3A). decodew.cpp 525
- V560 Ein Teil des bedingten Ausdrucks ist immer falsch: (ch> = 0x0FF41). decodew.cpp 525
- V560 Ein Teil des bedingten Ausdrucks ist immer wahr: (ch <= 0x0FF5A). decodew.cpp 525
Wenn Sie Erfolg haben, werden Sie meinen Respekt nicht halten!
Der Fehler liegt in der Tatsache, dass der logische Negationsoperator (!) Nicht für die gesamte Bedingung gilt, sondern nur für ihren ersten Unterausdruck:
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
Wenn diese Bedingung erfüllt ist, liegt der Wert der Variablen
ch im Intervall [0x0FF10 ... 0x0FF19]. Somit machen die vier weiteren Vergleiche keinen Sinn mehr: Sie werden immer entweder wahr oder falsch sein.
Um solche Fehler zu vermeiden, sollten einige Regeln beachtet werden. Erstens ist es sehr praktisch und klar, den Code an einer Tabelle auszurichten. Zweitens überladen Sie Ausdrücke nicht mit Klammern. Dieser Code kann beispielsweise folgendermaßen umgeschrieben werden:
const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19)
Dann wird zum einen die Anzahl der Klammern viel kleiner, und zum anderen steigt die Wahrscheinlichkeit, einen von den Augen begangenen Fehler zu „fangen“.
Und jetzt - Kirsche: Wir bewegen uns an die erste Stelle!
Der erste Platz
Quelle:
System in Shock: Interessante Fehler in den Quellcodes des legendären System ShockDer Finalist unseres heutigen Top ist also ein Fehler des legendären System Shock! Dieses Spiel, das 1994 veröffentlicht wurde, wurde zum Vorläufer und Inspirator von legendären Spielen wie Dead Space, BioShock und Deus Ex.
Aber zuerst muss ich etwas zugeben. Was ich Ihnen jetzt zeigen werde, enthält keinen Fehler. Im Großen und Ganzen ist es nicht einmal ein Code-Snippet, aber ich konnte einfach nicht widerstehen, dies nicht mit Ihnen zu teilen!
Tatsache ist, dass meine Kollegin Victoria bei der Analyse des Quellcodes des Spiels viele interessante Kommentare gefunden hat. Hier und da gab es plötzlich scherzhafte und ironische Bemerkungen und sogar Verse:
Für unsere russischsprachigen Leser habe ich eine ungefähre kostenlose Übersetzung angefertigt:
Diese Kommentare wurden von den Entwicklern des Spiels in den frühen neunziger Jahren hinterlassen ... Übrigens schrieb Doug Church - der Chefdesigner von System Shock - auch Code. Wer weiß, vielleicht wurde einer dieser Kommentare von ihm persönlich geschrieben? Ich hoffe das über Männer in Handtüchern - das ist nicht seine Arbeit :)Fazit
Abschließend möchte ich meinen Kollegen dafür danken, dass sie nach neuen Fehlern gesucht und Artikel darüber geschrieben haben. Danke Jungs!
Ohne Sie wäre dieser Artikel nicht so interessant geworden.Ich möchte auch ein wenig über unsere Erfolge sprechen, denn seit einem ganzen Jahr beschäftigen wir uns nicht nur mit der Suche nach Fehlern. Wir haben auch den Analysator entwickelt und verbessert, wodurch er signifikante Änderungen erfahren hat.Beispielsweise haben wir Unterstützung für mehrere neue Compiler hinzugefügt und die Liste der Diagnoseregeln erweitert. Wir haben auch erste Unterstützung für die Standards MISRA C und MISRA C ++ bereitgestellt . Die wichtigste und zeitaufwändigste Neuerung war die Unterstützung einer neuen Sprache. Ja, jetzt können wir Java- Code analysieren ! Und wir haben das Symbol aktualisiert :)Ich möchte auch unseren Lesern danken. Vielen Dank, dass Sie unsere Artikel gelesen und uns geschrieben haben! Ihr Feedback ist sehr angenehm und wichtig für uns.Damit sind unsere Top 10 C ++ - Fehler für das Jahr 2018 zu Ende gegangen. Welche Orte haben Ihnen am besten gefallen und warum? Sind Sie 2018 auf interessante Beispiele gestoßen? Erzähl uns davon in den Kommentaren!Bis zum nächsten Mal!
Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: George Gribkov. Top 10 Fehler von C ++ - Projekten im Jahr 2018 gefunden