Seit dem Ende des Jahres 2018 sind drei Monate vergangen. Für viele ist es gerade vorbei geflogen, aber für uns PVS-Studio-Entwickler war es ein ziemlich ereignisreiches Jahr. Wir haben uns ins Schwitzen gebracht, furchtlos um die Verbreitung der statischen Analyse konkurriert und nach Fehlern in Open-Source-Projekten gesucht, die in den Sprachen C, C ++, C # und Java geschrieben wurden. In diesem Artikel haben wir die 10 interessantesten für Sie zusammengestellt!
Um die faszinierendsten Orte zu finden, haben wir den statischen Code-Analysator
PVS-Studio verwendet. Es kann Fehler und potenzielle Schwachstellen im Code erkennen, der in den oben aufgeführten Sprachen geschrieben ist.
Wenn Sie begeistert sind, selbst nach Fehlern zu suchen, können Sie jederzeit unseren Analysator herunterladen und ausprobieren. Wir bieten die
kostenlose Analyseversion für Studenten und begeisterte Entwickler, die
kostenlose Lizenz für Entwickler von Open-Source-Projekten sowie die
Testversion für die ganze Welt und seinen Hund. Wer weiß, vielleicht können Sie im nächsten Jahr Ihre eigenen Top 10 erstellen? :) :)
Hinweis: Ich lade Sie ein, sich selbst zu überprüfen und, bevor Sie sich die Warnung des Analysators ansehen, selbst Fehler aufzudecken. Wie viele Fehler können Sie finden?
Zehnter Platz
Quelle:
Wieder ins All: Wie das Einhorn das Stellarium besuchteDieser Fehler wurde bei der Überprüfung eines virtuellen Planetariums namens Stellarium festgestellt.
Das obige Codefragment ist zwar klein, weist jedoch einen ziemlich kniffligen Fehler auf:
Plane::Plane(Vec3f &v1, Vec3f &v2, Vec3f &v3) : distance(0.0f), sDistance(0.0f) { Plane(v1, v2, v3, SPolygon::CCW); }
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 Code-Autor beabsichtigte, die Felder eines Objekts mithilfe eines anderen Konstruktors zu initialisieren, der im Hauptkonstruktor verschachtelt ist. Stattdessen gelang es ihm nur, ein temporäres Objekt zu erstellen, das beim Verlassen seines Bereichs zerstört wurde. Auf diese Weise bleiben die Felder mehrerer Objekte nicht initialisiert.
Der Autor sollte anstelle eines verschachtelten Konstruktoraufrufs einen in C ++ 11 eingeführten Delegatenkonstruktor verwenden. Zum Beispiel hätte er so schreiben können:
Plane::Plane(Vec3f& v1, Vec3f& v2, Vec3f& v3) : Plane(v1, v2, v3, SPolygon::CCW) { distance = 0.0f; sDistance = 0.0f; }
Auf diese Weise wären alle erforderlichen Felder korrekt initialisiert worden. Ist es nicht wunderbar?
Neunter Platz
Quelle:
Perl 5: So verbergen Sie Fehler in MakrosAuf dem neunten Platz sticht ein sehr bemerkenswertes Makro in seiner ganzen Schönheit hervor.
Beim Sammeln von Fehlern beim Schreiben eines Artikels stieß mein Kollege Svyatoslav auf eine Warnung des Analysators, die sich auf die Verwendung von Makros bezog. 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 verschachtelte Makros enthielt, von denen einige wiederum auch verschachtelte Makros enthielten. Es war so schwer, daraus einen Sinn zu machen, deshalb musste er eine vorverarbeitete Datei verwenden. Leider hat es nicht geholfen. Dies ist, was Svyatoslav in der vorherigen Codezeile gefunden hat:
(((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));
PVS-Studio-Warnung :
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 wäre schwierig, einen solchen Fehler einfach zu bemerken. Wir haben lange über diesen Code nachgedacht, aber ehrlich gesagt haben wir keinen Fehler darin gefunden. Auf jeden Fall ist es ein amüsantes Beispiel für schlecht lesbaren Code.
Sie sagen, dass Makros böse sind. Sicher, es gibt Fälle, in denen Makros unverzichtbar sind, aber wenn Sie ein Makro durch eine Funktion ersetzen können, sollten Sie dies auf jeden Fall tun.
Verschachtelte Makros sind besonders voller Fallstricke. Nicht nur, weil es schwierig ist, sie zu verstehen, sondern auch, weil sie unvorhersehbare Ergebnisse liefern können. Wenn ein Programmierer in einem solchen Makro einen Fehler macht, ist es viel schwieriger, ihn in einem Makro zu finden als in einer Funktion.
Achter Platz
Quelle:
Chrom: Andere FehlerDas nächste Beispiel stammt aus der Artikelserie zur Analyse des Chromium-Projekts. Der Fehler wurde in der WebRTC-Bibliothek ausgeblendet.
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 die Größe des Formatvektors innerhalb der bereichsbasierten for-Schleife variiert. Bereichsbasierte Schleifen basieren auf Iteratoren. Daher kann eine Änderung der Containergröße innerhalb solcher Schleifen zur Ungültigmachung dieser Iteratoren führen.
Dieser Fehler bleibt bestehen, wenn die Schleife unter expliziter Verwendung von Iteratoren neu geschrieben wird. Der Klarheit halber kann ich den folgenden Code zitieren:
for (auto format = begin(formats), __end = end(formats); format != __end; ++format) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } }
Bei Verwendung der
push_back- Methode kann beispielsweise eine
Vektorumverteilung auftreten. Auf diese Weise adressieren die Iteratoren einen ungültigen Speicherort.
Um solche Fehler zu vermeiden, befolgen Sie die Regel: Ändern Sie niemals eine Containergröße innerhalb einer Schleife mit Bedingungen, die an diesen Container gebunden sind. Es bezieht sich auch auf bereichsbasierte Schleifen und Schleifen, die Iteratoren verwenden. Sie können gerne diese
Diskussion über StackOverflow lesen, die das Thema Operationen behandelt, die zur Ungültigmachung von Iteratoren führen.
Siebter Platz
Quelle:
Godot: Zur regelmäßigen Verwendung statischer AnalysegeräteDas erste Beispiel aus der Spielebranche wird ein Code-Snippet sein, das wir in der Godot-Game-Engine gefunden haben. Wahrscheinlich wird es einige Arbeit erfordern, um den Fehler zu bemerken, aber ich bin sicher, dass unsere vertrauten Leser damit fertig werden.
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
Schauen wir uns die Schleifenbedingung genauer an. Die
Zählervariable wird mit dem Wert
blend_points_used - 1 initialisiert. Aus zwei vorherigen Überprüfungen (in
ERR_FAIL_COND und in
if ) geht außerdem hervor, dass zum Zeitpunkt der Ausführung der
Blend_points_used- 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
i- Zähler bei jeder Schleifeniteration nach oben geht.
Es scheint, dass die Schleife ewig ist, aber es ist nicht so.
Erstens tritt ein ganzzahliger Überlauf der
i- Variablen (was ein undefiniertes Verhalten ist) auf. Das heißt, wir sollten uns nicht darauf verlassen.
Wenn
ich int ohne Vorzeichen wäre, würde der Operator
i ++ den Zähler in
0 umwandeln , nachdem er den größtmöglichen Wert erreicht hat. Ein solches Verhalten wird durch den 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 .
Es war der erste Punkt, aber wir haben immer noch den zweiten! Der Fall ist, dass wir nicht einmal zu einem ganzzahligen Überlauf kommen. Der Array-Index wird viel früher außerhalb der Grenzen liegen. Dies bedeutet, dass versucht wird, auf Speicher außerhalb des für das Array zugewiesenen Blocks zuzugreifen. Welches ist auch undefiniertes Verhalten. Ein klassisches Beispiel :)
Ich kann Ihnen einige Empfehlungen geben, um ähnliche Fehler leichter zu vermeiden:
- Schreiben Sie einfachen und verständlichen Code
- Überprüfen Sie den Code gründlicher und schreiben Sie weitere Tests für neu geschriebenen Code
- Verwenden Sie statische Analysegeräte;)
Sechster Platz
Quelle:
Amazon Lumberyard: Ein Schrei der AngstHier ist ein weiteres Beispiel aus der Gamedev-Branche, nämlich aus dem Quellcode der AAA-Engine von Amazon Lumberyard.
void TranslateVariableNameByOperandType(....) {
PVS-Studio-Warnung :
V523 Die Anweisung 'then' entspricht der Anweisung 'else'. toglsloperand.c 700
Amazon Lumberyard wurde als plattformübergreifende Engine entwickelt. Aus diesem Grund versuchen Entwickler, so viele Compiler wie möglich zu unterstützen. Wie wir den Kommentaren entnehmen können, kam ein Programmierer Igor gegen den Qualcomm-Compiler.
Wir wissen nicht, ob er es geschafft hat, seine Aufgabe auszuführen und durch "paranoide" Compilerprüfungen zu waten, aber er hat sehr seltsamen Code hinterlassen. Das Seltsame daran ist, dass sowohl die
damaligen als auch die
anderen Zweige der
if- Anweisung absolut identischen Code enthalten. Ein solcher Fehler ist höchstwahrscheinlich auf die Verwendung einer schlampigen Copy-Paste-Methode zurückzuführen.
Ich weiß nicht einmal, was ich hier raten soll. Ich wünsche den Entwicklern von Amazon Lumberyard nur alles Gute bei der Behebung von Fehlern und viel Glück für den Entwickler Igor!
Fünfter Platz
Quelle:
Der PVS-Studio-Analysator hat sich erneut als aufmerksamer als eine Person erwiesenEine interessante Geschichte ereignete sich mit dem nächsten Beispiel. Mein Kollege Andrey Karpov bereitete einen Artikel über eine weitere Überprüfung des Qt-Frameworks vor. Beim Schreiben einiger bemerkenswerter Fehler stieß er auf die Warnung des Analysators, die er für falsch hielt. Hier ist das Codefragment und die Warnung dafür:
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
Was bedeutet, dass sich PVS-Studio vor Ort beschwert hat, was offensichtlich keinen Fehler hatte! Es ist unmöglich, dass die
CursorShowing- Konstante
0 ist , da nur ein paar Zeilen darüber mit
1 initialisiert werden.
Da Andrey eine instabile Analysatorversion verwendete, stellte er die Richtigkeit der Warnung in Frage. Er sah sich diesen Code sorgfältig an und fand immer noch keinen Fehler. Er gab es schließlich im Bugtracker falsch positiv, damit andere Kollegen Abhilfe schaffen konnten.
Nur eine detaillierte Analyse ergab, dass PVS-Studio wieder vorsichtiger war als eine Person. Der Wert
0x1 wird einer benannten Konstante namens
cursorShowing zugewiesen, während
CursorShowing an einer bitweisen "und"
-Operation teilnimmt. Dies sind zwei völlig unterschiedliche Konstanten, die erste beginnt mit einem Kleinbuchstaben, die zweite mit einem Großbuchstaben.
Der Code wird erfolgreich kompiliert, da die Klasse
QWindowsCursor wirklich eine Konstante mit diesem Namen enthält. Hier ist seine Definition:
class QWindowsCursor : public QPlatformCursor { public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; .... }
Wenn Sie einer Enum-Konstante keinen Wert explizit zuweisen, wird dieser standardmäßig initialisiert. Da
CursorShowing das erste Element in der Aufzählung ist, wird ihm
0 zugewiesen.
Um solche Fehler zu vermeiden, sollten Sie Entitäten keine zu ähnlichen Namen geben. Sie sollten diese Regel besonders genau befolgen, wenn Entitäten vom gleichen Typ sind oder implizit ineinander umgewandelt werden können. Wie in solchen Fällen ist es fast unmöglich, den Fehler zu bemerken, aber der falsche Code wird trotzdem kompiliert und befindet sich in einer einfachen Straße innerhalb Ihres Projekts.
Vierter Platz
Quelle:
Schießen Sie sich beim Umgang mit Eingabedaten in den FußWir nähern uns den drei besten Finalisten und der nächste in der Reihe ist der Fehler aus dem FreeSWITCH-Projekt.
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 Im Index 'strlen (command_buf)' werden nicht aktivierte fehlerhafte Daten verwendet.
Der Analysator warnt Sie, dass einige ungeprüfte Daten im Ausdruck
strlen (command_buf) - 1 verwendet werden . In der Tat: Wenn
command_buf eine leere Zeichenfolge in Bezug auf die C-Sprache ist (die das einzige Zeichen enthält - '\ 0'), gibt
strlen (command_buf) 0 zurück . In einem solchen Fall wird auf
command_buf [-1] zugegriffen, was ein undefiniertes Verhalten ist. Das ist schlecht!
Die eigentliche Lust an diesem Fehler ist nicht,
warum er auftritt, sondern
wie . Dieser Fehler ist eines der schönsten Beispiele, die Sie selbst "berühren" und reproduzieren. Sie können FreeSwitch ausführen, einige Aktionen ausführen, die zur Ausführung des oben genannten Codefragments führen, und eine leere Zeichenfolge an die Eingabe des Programms übergeben.
Infolgedessen wird ein Arbeitsprogramm mit einer subtilen Bewegung der Hand zu einem nicht funktionierenden! Einzelheiten zur Reproduktion dieses Fehlers finden Sie im Quellartikel unter dem oben angegebenen Link. Lassen Sie mich Ihnen in der Zwischenzeit ein aussagekräftiges Ergebnis liefern:
Denken Sie daran, dass Ausgabedaten alles sein können, daher sollten Sie sie immer überprüfen. Auf diese Weise beschwert sich der Analysator nicht und das Programm wird zuverlässiger.
Jetzt ist es Zeit für unseren Gewinner: Wir sind jetzt im Endspiel! Übrigens haben Bugs-Finalisten schon lange gewartet, sich dann gelangweilt und sogar angefangen, kitschig zu werden. Schauen Sie, was sie inszeniert haben, während wir weg waren!
Dritter Platz
Quelle:
NCBI Genome Workbench: Wissenschaftliche Forschung unter BedrohungEin Code-Snippet aus dem NCBI Genome Workbench-Projekt, bei dem es sich um eine Reihe von Tools zum Studieren und Analysieren genetischer Daten handelt, eröffnet die drei besten Gewinner. Auch wenn Sie kein gentechnisch veränderter Übermensch sein müssen, um diesen Fehler zu finden, wissen nur wenige, wie wichtig es ist, hier einen Fehler zu machen.
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
Hast du einen Fehler gefunden? Wenn ja, sind Sie ein Attaboy! .. oder ein genetisch veränderter Übermensch.
Tatsache ist, dass moderne Optimierungs-Compiler viel tun können, damit ein erstelltes Programm schneller funktioniert. Einschließlich der Tatsache, dass Compiler jetzt verfolgen können, dass ein an
memset übergebener Puffer nirgendwo anders verwendet wird.
In diesem Fall können sie den "unnötigen" Aufruf von
memset entfernen und haben alle Rechte dafür. Dann kann der Puffer, in dem wichtige Daten gespeichert sind, zur Freude der Angreifer im Speicher verbleiben.
Vor diesem Hintergrund klingt dieser Geek-Kommentar "Mit Sicherheit ist am besten pedantisch" noch lustiger. Nach einer kleinen Anzahl von Warnungen für dieses Projekt zu urteilen, haben die Entwickler ihr Bestes getan, um präzise zu sein und sicheren Code zu schreiben. Wie wir jedoch sehen können, kann man einen solchen Sicherheitsmangel leicht übersehen. Gemäß der Common Weakness Enumeration wird dieser Fehler als
CWE-14 : Compiler-Entfernung von Code zum Löschen von Puffern klassifiziert.
Sie sollten die Funktion
memset_s () verwenden, damit die Speicherfreigabe sicher ist. Die Funktion ist sicherer als
memset () und kann von einem Compiler nicht ignoriert werden.
Zweiter Platz
Quelle:
Wie sich PVS-Studio als aufmerksamer als dreieinhalb Programmierer erwiesEin Silbermedaillengewinner wurde uns freundlicherweise von einem unserer Kunden zugesandt. Er war sich sicher, dass der Analysator einige falsch positive Ergebnisse ausgab.
Evgeniy bekam die E-Mail, sah sie sich an und schickte sie an Svyatoslav. Svyatoslav sah sich den vom Kunden gesendeten Code genau an und dachte: "Wie ist es möglich, dass der Analysator einen solchen Fehler gemacht hat?". Also bat er Andrey um Rat. Er überprüfte auch diesen Ort und stellte fest: In der Tat erzeugte der Analysator falsch positive Ergebnisse.
So geht es, das musste repariert werden. Erst als Svyatoslav anfing, synthetische Beispiele zu erstellen, um die Aufgabe in unserem Bug-Tracker zu erstellen, bekam er, was falsch war.
Keiner der Programmierer konnte die Fehler finden, aber sie waren wirklich im Code. Ehrlich gesagt konnte der Autor dieses Artikels sie auch nicht finden, obwohl der Analysator eindeutig Warnungen für fehlerhafte Stellen ausgegeben hat!
Wirst du so einen schlauen Käfer 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 du es getan hast - ein großes Lob an dich!
Der Fehler liegt in der Tatsache, dass der logische Negationsoperator (!) Nicht auf die gesamte Bedingung angewendet wird, sondern nur auf ihren ersten Unterausdruck:
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
Wenn diese Bedingung erfüllt ist, liegt der Wert der Variablen
ch im Bereich [0x0FF10 ... 0x0FF19]. Somit sind vier weitere Vergleiche bereits bedeutungslos: Sie werden immer entweder wahr oder falsch sein.
Um solche Fehler zu vermeiden, sollten Sie sich an einige Regeln halten. Erstens ist es sehr praktisch und informativ, den Code wie eine Tabelle auszurichten. Zweitens sollten Sie die Ausdrücke nicht mit Klammern überladen. Dieser Code könnte beispielsweise folgendermaßen umgeschrieben werden:
const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19)
Auf diese Weise werden weniger Klammern angezeigt, und andererseits werden Sie mit größerer Wahrscheinlichkeit einen gelegentlichen Fehler bemerken.
Hier kommt die Kirsche an die Spitze - gehen wir zum ersten Platz!
Erster Platz
Quelle:
Schockiertes System: Interessante Fehler im Quellcode des legendären SystemschocksDer heutige Top-Finalist ist ein Fehler des legendären System Shock! Es ist ein Spiel, das vor langer Zeit im Jahr 1994 veröffentlicht wurde und Vorgänger und Inspiration für legendäre Spiele wie Dead Space, BioShock und Deus Ex wurde.
Aber zuerst muss ich etwas gestehen. Was ich Ihnen jetzt zeigen werde, enthält keine Fehler. Eigentlich ist es nicht einmal ein Stück Code, aber ich konnte einfach nicht anders, als es mit Ihnen zu teilen!
Die Sache ist, dass meine Kollegin Victoria bei der Analyse des Quellcodes des Spiels viele faszinierende Kommentare entdeckt hat. In verschiedenen Fragmenten fand sie einige witzige und ironische Bemerkungen und sogar Gedichte.
So sehen die Kommentare aus, die Entwickler in den letzten 90ern in Spielen hinterlassen haben ... Doug Church - ein Chefdesigner des Systemschocks - war übrigens auch damit beschäftigt, Code zu schreiben. Wer weiß, vielleicht wurden einige dieser Kommentare von ihm geschrieben? Hoffe, Männer in Handtüchern Zeug ist nicht seine Handarbeit :)
Fazit
Abschließend möchte ich
meinen Kollegen dafür danken, dass sie nach neuen Fehlern gesucht und in Artikeln darüber geschrieben haben. Danke Jungs! Ohne dich wäre dieser Artikel nicht so interessant.
Außerdem möchte ich ein wenig über unsere Erfolge erzählen, da wir das ganze Jahr nicht nur mit der Suche nach Fehlern beschäftigt waren. Wir haben auch den Analysator entwickelt und verbessert, was zu erheblichen Änderungen führte.
Beispielsweise haben wir die Unterstützung mehrerer neuer Compiler hinzugefügt und die Liste der Diagnoseregeln erweitert. Außerdem haben wir die erste Unterstützung der Standards
MISRA C und MISRA C ++ implementiert. Die wichtigste und zeitaufwändigste neue Funktion war die Unterstützung einer neuen Sprache. Ja, wir können jetzt Code in
Java analysieren! Und außerdem haben wir ein
neues Symbol :)
Ich möchte auch unseren Lesern danken. Vielen Dank, dass Sie unsere Artikel gelesen und uns geschrieben haben! Sie sind so reaktionsschnell und für uns so wichtig!
Unsere Top 10 C ++ - Fehler von 2018 sind zu Ende gegangen. Welche Fragmente haben dir am besten gefallen und warum? Sind Sie 2018 auf einige interessante Beispiele gestoßen?
Alles Gute, bis zum nächsten Mal!