Die Veröffentlichung des Quellcodes durch Microsoft für seine Projekte ist ein guter Grund, diese zu überprüfen. Diesmal war dies keine Ausnahme, und heute sehen wir uns die verdächtigen Stellen im Infer.NET-Code an. Nieder mit der Anmerkung - kommen Sie auf den Punkt!
Ein bisschen über das Projekt und den Analysator
Infer.NET ist ein maschinelles Lernsystem, das von Spezialisten von Microsoft entwickelt wurde. Der Quellcode des Projekts ist seit kurzem auf
GitHub verfügbar, was der Grund für seine Überprüfung war. Weitere Details zum Projekt finden Sie beispielsweise
hier .
Das Projekt wurde mit dem statischen Analysegerät PVS-Studio Version 6.26 überprüft. Ich möchte Sie daran erinnern, dass PVS-Studio unter C, C ++ \ C # (und bald auch unter Java) unter Windows, Linux und MacOS nach Codefehlern sucht. C # -Code analysieren wir bisher nur unter Windows. Der Analysator kann
heruntergeladen und in Ihrem Projekt getestet werden.
Die Überprüfung selbst war sehr einfach und ohne Probleme. Zuvor habe ich das Projekt von GitHub entladen, die erforderlichen Pakete (Abhängigkeiten) wiederhergestellt und sichergestellt, dass das Projekt erfolgreich erstellt wurde. Dies ist erforderlich, damit der Analysator Zugriff auf alle erforderlichen Informationen für eine vollständige Analyse hat. Nach dem Zusammenbau mit wenigen Klicks startete ich die Analyse der Lösung über das PVS-Studio-Plugin für Visual Studio.
Dies ist übrigens nicht das erste Projekt von Microsoft, das mit PVS-Studio getestet wurde - es gab andere:
Roslyn ,
MSBuild ,
PowerShell ,
CoreFX und
andere .
Hinweis Wenn Sie oder Ihre Bekannten an der Analyse von Java-Code interessiert sind, können Sie uns zur
Unterstützung schreiben, indem Sie "Ich möchte einen Analysator für Java" auswählen. Es gibt keine öffentliche Beta-Version des Analysators, diese sollte jedoch bald verfügbar sein. Irgendwo in einem geheimen Labor (durch die Wand) arbeiten die Jungs aktiv daran.
Aber genug abstraktes Gerede - schauen wir uns die Probleme im Code an.
Ist das ein Fehler oder eine Funktion?
Ich schlage vor, den Fehler selbst zu finden - eine vollständig lösbare Aufgabe. Ehrlich gesagt, keine Witze im Sinne des Artikels „
Top 10 Fehler in C ++ - Projekten für 2017 “. Beeilen Sie sich also nicht, die nach dem Code-Snippet bereitgestellte Analyse-Warnung zu lesen.
private void MergeParallelTransitions() { .... if ( transition1.DestinationStateIndex == transition2.DestinationStateIndex && transition1.Group == transition2.Group) { if (transition1.IsEpsilon && transition2.IsEpsilon) { .... } else if (!transition1.IsEpsilon && !transition2.IsEpsilon) { .... if (double.IsInfinity(transition1.Weight.Value) && double.IsInfinity(transition1.Weight.Value)) { newElementDistribution.SetToSum( 1.0, transition1.ElementDistribution, 1.0, transition2.ElementDistribution); } else { newElementDistribution.SetToSum( transition1.Weight.Value, transition1.ElementDistribution, transition2.Weight.Value, transition2.ElementDistribution); } .... }
PVS-Studio Warnung :
V3001 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke 'double.IsInfinity (Transition1.Weight.Value)'. Runtime Automaton.Simplification.cs 479
Wie Sie dem Code-Snippet entnehmen können, arbeitet die Methode mit zwei Variablen -
Übergang1 und
Übergang2 . Die Verwendung ähnlicher Namen ist manchmal durchaus gerechtfertigt, aber es ist zu beachten, dass in diesem Fall die Wahrscheinlichkeit steigt, versehentlich irgendwo mit dem Namen einen Fehler zu machen.
Dies geschah, wenn Zahlen auf unendlich überprüft wurden (
double.IsInfinity ). Aufgrund eines Fehlers haben wir den Wert derselben Variablen zweimal überprüft -
Transition1.Weight.Value . Der überprüfte Wert im zweiten Unterausdruck sollte die Variable
Transition2.Weight.Value sein .
Ein weiterer ähnlicher verdächtiger Code.
internal MethodBase ToMethodInternal(IMethodReference imr) { .... bf |= BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; .... }
PVS-Studio Warnung :
V3001 Links und rechts vom '|' befinden sich identische Unterausdrücke 'BindingFlags.Public'. Betreiber. Compiler CodeBuilder.cs 194
Bei der Bildung des Werts der Variablen
bf wird das Aufzählungselement
BindingFlags.Public zweimal verwendet. Entweder enthält dieser Code eine zusätzliche Kennzeichnungsoperation, oder anstelle der zweiten Verwendung von
BindingFlags.Public sollte ein anderer Aufzählungswert vorhanden sein.
Übrigens ist dieser Code im Quellcode in einer Zeile geschrieben. Es scheint mir, dass das Problem leichter zu erkennen ist, wenn es in einem Tabellenstil (wie hier) formatiert ist.
Lass uns weitermachen. Ich bringe den ganzen Körper der Methode mit und wieder schlage ich vor, dass Sie den Fehler (oder vielleicht den Fehler) selbst finden.
private void ForEachPrefix(IExpression expr, Action<IExpression> action) {
Hast du gefunden? Wir prüfen!
PVS-Studio-Warnungen :
- V3003 Die Verwendung des Musters 'if (A) {...} else if (A) {...}' wurde erkannt. Es besteht die Wahrscheinlichkeit eines logischen Fehlers. Überprüfen Sie die Zeilen: 1719, 1727. Compiler CodeRecognizer.cs 1719
- V3003 Die Verwendung des Musters 'if (A) {...} else if (A) {...}' wurde erkannt. Es besteht die Wahrscheinlichkeit eines logischen Fehlers. Überprüfen Sie die Zeilen: 1721, 1729. Compiler CodeRecognizer.cs 1721
Vereinfachen Sie den Code ein wenig, um die Probleme offensichtlicher zu machen.
private void ForEachPrefix(IExpression expr, Action<IExpression> action) { if (....) .... else if (expr is IUnaryExpression) ForEachPrefix(((IUnaryExpression)expr).Expression, action); else if (expr is IAddressReferenceExpression) ForEachPrefix(((IAddressReferenceExpression)expr).Expression, action); .... else if (expr is IUnaryExpression) ForEachPrefix(((IUnaryExpression)expr).Expression, action); else if (expr is IAddressReferenceExpression) ForEachPrefix(((IAddressReferenceExpression)expr).Expression, action) .... }
Bedingte Ausdrücke und
dann Verzweigungen mehrerer
if-Anweisungen werden dupliziert. Möglicherweise wurde dieser Code mit der Copy-Paste-Methode geschrieben, weshalb das Problem aufgetreten ist. Nun stellt sich heraus, dass
dann Zweige der Duplikate niemals ausgeführt werden, da:
- Wenn der bedingte Ausdruck wahr ist, wird der Hauptteil der ersten if-Anweisung des entsprechenden Paares ausgeführt.
- Wenn der bedingte Ausdruck im ersten Fall falsch ist, ist er im zweiten falsch.
Da Zweige
damals dieselben Aktionen enthalten, sieht es jetzt wie redundanter Code aus, der verwirrend ist. Es ist möglich, dass dies ein anderes Problem ist - anstelle von Duplikaten sollten andere Überprüfungen durchgeführt worden sein.
Wir fahren fort.
public int Compare(Pair<int, int> x, Pair<int, int> y) { if (x.First < y.First) { if (x.Second >= y.Second) {
PVS-Studio-Warnungen :
- V3004 Die Anweisung 'then' entspricht der Anweisung 'else'. Laufzeit RegexpTreeBuilder.cs 1080
- V3004 Die Anweisung 'then' entspricht der Anweisung 'else'. Laufzeit RegexpTreeBuilder.cs 1093
Der Code sieht äußerst verdächtig aus, da er zwei bedingte Anweisungen mit identischen Körpern von
then und
else branch enthält. In beiden Fällen lohnt es sich wahrscheinlich, unterschiedliche Werte zurückzugeben. Wenn dies ein gedachtes Verhalten ist, ist es hilfreich, redundante bedingte Anweisungen zu entfernen.
Es gab interessante Zyklen. Beispiel unten:
private static Set<StochasticityPattern> IntersectPatterns(IEnumerable<StochasticityPattern> patterns) { Set<StochasticityPattern> result = new Set<StochasticityPattern>(); result.AddRange(patterns); bool changed; do { int count = result.Count; AddIntersections(result); changed = (result.Count != count); break; } while (changed); return result; }
PVS-Studio Warnung :
V3020 Eine bedingungslose Unterbrechung innerhalb einer Schleife. Compiler DefaultFactorManager.cs 474
Aufgrund der bedingungslosen
break- Anweisung wird genau eine Iteration der Schleife ausgeführt, und die
geänderte Steuervariable wird nicht einmal verwendet. Im Allgemeinen sieht der Code seltsam und verdächtig aus.
Die gleiche Methode (exakte Kopie) wurde in einer anderen Klasse gefunden. Entsprechende Analysatorwarnung:
V3020 Eine bedingungslose Unterbrechung innerhalb einer Schleife. Visualizers.Windows FactorManagerView.cs 350
Übrigens traf eine Methode auf eine bedingungslose
continue- Anweisung in einer Schleife (sie wurde vom Analysator mit derselben Diagnose gefunden), aber darüber befand sich ein Kommentar, der bestätigte, dass dies eine spezielle temporäre Lösung ist:
Ich erinnere mich, dass es in der Nähe der bedingungslosen
Unterbrechungserklärung keine derartigen Kommentare gab.
Lass uns weitermachen.
internal static DependencyInformation GetDependencyInfo(....) { .... IExpression resultIndex = null; .... if (resultIndex != null) { if (parameter.IsDefined( typeof(SkipIfMatchingIndexIsUniformAttribute), false)) { if (resultIndex == null) throw new InferCompilerException( parameter.Name + " has SkipIfMatchingIndexIsUniformAttribute but " + StringUtil.MethodNameToString(method) + " has no resultIndex parameter"); .... } .... } .... }
PVS-Studio- Warnung :
V3022 Der Ausdruck 'resultIndex == null' ist immer falsch. Compiler FactorManager.cs 382
Ich
stelle sofort fest, dass sich zwischen der Deklaration und der obigen Überprüfung der Wert der Variablen
resultIndex ändern kann. Zwischen den Überprüfungen
resultIndex! = Null und
resultIndex == null kann der Wert jedoch nicht bereits geändert werden. Daher ist das Ergebnis des Ausdrucks
resultIndex == null immer
falsch , was bedeutet, dass niemals eine Ausnahme ausgelöst wird.
Ich hoffe, dass Sie ein Interesse daran haben, ohne meine Vorschläge selbst Fehler zu finden, um ein Problem zu finden, aber für den Fall, dass ich es erneut vorschlage. Der Methodencode ist klein, ich werde ihn in seiner Gesamtheit geben.
public static Tuple<int, string> ComputeMovieGenre(int offset, string feature) { string[] genres = feature.Split('|'); if (genres.Length < 1 && genres.Length > 3) { throw new ArgumentException(string.Format( "Movies should have between 1 and 3 genres; given {0}.", genres.Length)); } double value = 1.0 / genres.Length; var result = new StringBuilder( string.Format( "{0}:{1}", offset + MovieGenreBuckets[genres[0]], value)); for (int i = 1; i < genres.Length; ++i) { result.Append( string.Format( "|{0}:{1}", offset + MovieGenreBuckets[genres[i].Trim()], value)); } return new Tuple<int, string>(MovieGenreBucketCount, result.ToString()); }
Mal sehen, was hier passiert. Die Eingabezeichenfolge wird durch das Zeichen '|' analysiert. Wenn die Länge des Arrays nicht wie erwartet ist, muss eine Ausnahme ausgelöst werden.
Warten Sie eine Sekunde ...
genres.Length <1 && genres.Length> 3 ? Da es keine Zahl gibt, die sofort in den für den Ausdruck (
[int.MinValue..1) und
(3..int.MaxValue] ) erforderlichen Wertebereich fällt, ist das Ergebnis des Ausdrucks immer
falsch . Daher schützt diese Prüfung nicht vor irgendetwas und die erwartete Ausnahme wird nicht ausgelöst.
Genau davor warnt der Analysator:
V3022 Ausdruck 'genres.Length <1 && genres.Length> 3' ist immer falsch. Wahrscheinlich das '||' Operator sollte hier verwendet werden. Evaluator Features.cs 242
Verdächtige Spaltoperation erfüllt.
public static void CreateTrueThetaAndPhi(....) { .... double expectedRepeatOfTopicInDoc = averageDocLength / numUniqueTopicsPerDoc; .... int cnt = Poisson.Sample(expectedRepeatOfTopicInDoc); .... }
PVS-Studio Warnung :
V3041 Der Ausdruck wurde implizit vom Typ 'int' in den Typ 'double' umgewandelt. Erwägen Sie die Verwendung eines expliziten Typgusses, um den Verlust eines Bruchteils zu vermeiden. Ein Beispiel: double A = (double) (X) / Y; LDA Utilities.cs 74
Dies ist hier verdächtig: Es wird eine Ganzzahldivision durchgeführt (die Variablen
averDocLength und
numUniqueTopicsPerDoc sind vom Typ
int ), und das Ergebnis wird in eine Variable vom Typ
double geschrieben . Die Frage lautet: Wird es speziell gemacht oder wurde die Aufteilung reeller Zahlen noch impliziert? Wenn die Variable
expectedRepeatOfTopicInDoc vom Typ
int wäre , würde dies mögliche Fragen klären.
An anderen Stellen wird beispielsweise die
Poisson.Sample- Methode verwendet, deren Argument die verdächtige Variable
expectedRepeatOfTopicInDoc ist.
int numUniqueWordsPerTopic = Poisson.Sample((double)averageWordsPerTopic);
averWordsPerTopic ist vom Typ
int , der am Verwendungsort bereits in
double konvertiert wurde.
Und hier ist ein weiterer Einsatzort:
double expectedRepeatOfWordInTopic = ((double)numDocs) * averageDocLength / numUniqueWordsPerTopic; .... int cnt = Poisson.Sample(expectedRepeatOfWordInTopic);
Bitte beachten Sie, dass die Variablen dieselben Namen wie im ursprünglichen Beispiel haben. Zum Initialisieren der
erwarteten Wiederholung von
WordInTopic wird nur die Division von reellen Zahlen verwendet (aufgrund der expliziten Konvertierung von
numDocs in
double ).
Im Allgemeinen lohnt es sich, den Startpunkt zu betrachten, an dem der Analysator eine Warnung ausgegeben hat.
Aber Überlegungen, ob es sich lohnt, sie zu bearbeiten und wie, lassen Sie die Autoren des Codes (sie wissen es besser), aber lassen Sie uns weiter gehen. Zur nächsten verdächtigen Abteilung.
public static NonconjugateGaussian BAverageLogarithm(....) { .... double v_opt = 2 / 3 * (Math.Log(mx * mz / Ex2 / 2) - m); if (v_opt != v) { .... } .... }
PVS-Studio Warnung :
V3041 Der Ausdruck wurde implizit vom Typ 'int' in den Typ 'double' umgewandelt. Erwägen Sie die Verwendung eines expliziten Typgusses, um den Verlust eines Bruchteils zu vermeiden. Ein Beispiel: double A = (double) (X) / Y; Laufzeit ProductExp.cs 137
Der Analysator erkannte erneut den verdächtigen Vorgang der Ganzzahldivision als
2 und
3 sind ganzzahlige numerische Literale, und das Ergebnis des Ausdrucks 2/3 ist
0 . Infolgedessen hat der gesamte Ausdruck die Form:
double v_opt = 0 * expr;
Stimmen Sie zu, ein wenig seltsam. Mehrmals kehrte ich zu dieser Warnung zurück und versuchte, einen Fang zu finden, ohne ihn dem Artikel hinzuzufügen. Die Methode ist mit Mathematik und verschiedenen Formeln gefüllt (die ich ehrlich gesagt nicht wirklich zerlegen wollte). Sie wissen nie, was Sie erwartet. Außerdem versuche ich, den Warnungen, die ich in dem Artikel schreibe, so skeptisch wie möglich gegenüber zu sein, und beschreibe sie erst, nachdem ich sie besser studiert habe.
Aber dann wurde mir klar, warum ich einen Faktor von
0 brauche, geschrieben als
2/3 ? Dieser Ort ist also trotzdem einen Blick wert.
public static void WriteAttribute(TextWriter writer, string name, object defaultValue, object value, Func<object, string> converter = null) { if ( defaultValue == null && value == null || value.Equals(defaultValue)) { return; } string stringValue = converter == null ? value.ToString() : converter(value); writer.Write($"{name}=\"{stringValue}\" "); }
PVS-Studio Warnung :
V3080 Mögliche Null-Dereferenzierung. Betrachten Sie die Überprüfung des Werts. Compiler WriteHelpers.cs 78
Ziemlich faire Aussage des Analysators basierend auf der Bedingung Die Dereferenzierung einer
Nullreferenz kann im Ausdruck
value.Equals (defaultValue) erfolgen, wenn
value == null . Da dieser Ausdruck der rechte Operand des Operators || ist, muss der linke Operand zur Berechnung
falsch sein . Dazu reicht es aus, dass mindestens eine der Variablen
defaultValue \
value nicht
null ist . Wenn
defaultValue! = Null und
value == null :
- defaultValue == null -> false ;
- defaultValue == null && value == null -> false ; (Wertprüfung nicht stattgefunden)
- value.Equals (defaultValue) -> NullReferenceException , da value null ist .
Schauen wir uns einen ähnlichen Fall an:
public FeatureParameterDistribution( GaussianMatrix traitFeatureWeightDistribution, GaussianArray biasFeatureWeightDistribution) { Debug.Assert( (traitFeatureWeightDistribution == null && biasFeatureWeightDistribution == null) || traitFeatureWeightDistribution.All( w => w != null && w.Count == biasFeatureWeightDistribution.Count), "The provided distributions should be valid and consistent in the number of features."); .... }
PVS-Studio Warnung :
V3080 Mögliche Null-Dereferenzierung. Überprüfen Sie 'traitFeatureWeightDistribution'. Recommender FeatureParameterDistribution.cs 65
Wir werfen den Überschuss weg und lassen nur die Logik für die Berechnung des Booleschen Werts übrig, damit es einfacher ist, Folgendes herauszufinden:
(traitFeatureWeightDistribution == null && biasFeatureWeightDistribution == null) || traitFeatureWeightDistribution.All( w => w != null && w.Count == biasFeatureWeightDistribution.Count)
Wieder der richtige Operand des || Es wird nur berechnet, wenn das Ergebnis der linken Berechnung
falsch ist . Der linke Operand kann
falsch sein , auch wenn
traitFeatureWeightDistribution == null und
BiasFeatureWeightDistribution! = Null sind . Dann wird der richtige Operand des Operators || berechnet und ein Aufruf von
traitFeatureWeightDistribution.All löst eine
ArgumentNullException aus .
Ein weiterer interessanter Code:
public static double GetQuantile(double probability, double[] quantiles) { .... int n = quantiles.Length; if (quantiles == null) throw new ArgumentNullException(nameof(quantiles)); if (n == 0) throw new ArgumentException("quantiles array is empty", nameof(quantiles)); .... }
PVS-Studio Warnung :
V3095 Das 'Quantiles'-Objekt wurde verwendet, bevor es gegen Null verifiziert wurde. Überprüfen Sie die Zeilen: 91, 92. Runtime OuterQuantiles.cs 91
Beachten Sie, dass zuerst auf die Eigenschaft
quantiles.Length zugegriffen wird und dann die
Quantile auf
Null überprüft werden. Wenn
Quantile == null sind ,
löst die Methode daher eine Ausnahme aus, die nur ein wenig falsch ist und ein wenig nicht dort, wo sie benötigt wurde. Anscheinend haben sie die Linien stellenweise durcheinander gebracht.
Wenn Sie sich erfolgreich mit der Erkennung früherer Fehler befasst haben, empfehle ich Ihnen, eine Tasse Kaffee zu kochen und zu versuchen, das Kunststück zu wiederholen, wobei Sie den Fehler in der folgenden Methode finden. Um es etwas interessanter zu machen, zitiere ich den gesamten Code der Methode.
(
Link zum Fullsize )

Okay, okay, das war ein Witz (oder hast du es geschafft ?!). Lassen Sie uns die Aufgabe etwas vereinfachen:
if (sample.Precision < 0) { precisionIsBetween = true; lowerBound = -1.0 / v; upperBound = -mean.Precision; } else if (sample.Precision < -mean.Precision) { precisionIsBetween = true; lowerBound = 0; upperBound = -mean.Precision; } else {
Ist es besser geworden? Der Analysator hat die folgende Warnung für diesen Code
ausgegeben :
V3008 Der Variablen 'lowerBound' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 324, 323. Runtime GaussianOp.cs 324
In der Tat wird im letzten Zweig
else der Wert der Variablen
lowerBound zweimal hintereinander zugewiesen. Anscheinend (und nach dem obigen Code zu urteilen) muss die Variable
UpperBound an einer der Zuweisungen beteiligt sein.
Wir folgen weiter.
private void WriteAucMatrix(....) { .... for (int c = 0; c < classLabelCount; c++) { int labelWidth = labels[c].Length; columnWidths[c + 1] = labelWidth > MaxLabelWidth ? MaxLabelWidth : labelWidth; for (int r = 0; r < classLabelCount; r++) { int countWidth = MaxValueWidth; if (countWidth > columnWidths[c + 1]) { columnWidths[c + 1] = countWidth; } } .... }
PVS-Studio Warnung :
V3081 Der '
r' -Zähler wird nicht in einer verschachtelten Schleife verwendet. Überprüfen Sie die Verwendung des C-Zählers. CommandLine ClassifierEvaluationModule.cs 459
Bitte beachten Sie, dass der Zähler der inneren Schleife -
r - im Körper dieser Schleife nicht verwendet wird. Aus diesem Grund stellt sich heraus, dass während aller Iterationen der inneren Schleife dieselben Operationen an denselben Elementen ausgeführt werden - da die Indizes auch den Zähler der äußeren Schleife (
c ) und nicht den inneren (
r ) verwenden.
Mal sehen, was sonst noch interessant war.
public RegexpFormattingSettings( bool putOptionalInSquareBrackets, bool showAnyElementAsQuestionMark, bool ignoreElementDistributionDetails, int truncationLength, bool escapeCharacters, bool useLazyQuantifier) { this.PutOptionalInSquareBrackets = putOptionalInSquareBrackets; this.ShowAnyElementAsQuestionMark = showAnyElementAsQuestionMark; this.IgnoreElementDistributionDetails = ignoreElementDistributionDetails; this.TruncationLength = truncationLength; this.EscapeCharacters = escapeCharacters; }
PVS-Studio Warnung : Der
V3117- Konstruktorparameter 'useLazyQuantifier' wird nicht verwendet. Runtime RegexpFormattingSettings.cs 38
Der Konstruktor verwendet keinen Parameter -
useLazyQuantifier . Dies erscheint vor dem Hintergrund besonders verdächtig, dass in der Klasse
UseLazyQuantifier eine Eigenschaft mit dem entsprechenden Namen und Typ definiert ist. Anscheinend haben sie vergessen, es über den entsprechenden Parameter zu initialisieren.
Traf mehrere potenziell gefährliche Ereignishandler. Ein Beispiel für einen von ihnen ist unten angegeben:
public class RecommenderRun { .... public event EventHandler Started; .... public void Execute() {
PVS-Studio Warnung :
V3083 Unsicherer Aufruf des Ereignisses 'Gestartet', NullReferenceException ist möglich. Überlegen Sie, ob Sie einer lokalen Variablen ein Ereignis zuweisen möchten, bevor Sie sie aufrufen. Evaluator RecommenderRun.cs 115
Tatsache ist, dass zwischen der Prüfung auf
Null- Ungleichung und dem Aufruf des Handlers ein Ereignis abgemeldet werden kann. Wenn das Ereignis im Moment zwischen der Prüfung auf
Null und dem Aufruf der Handler keine Abonnenten hat, wird eine
NullReferenceException ausgelöst . Um solche Probleme zu vermeiden, können Sie beispielsweise den Link zur Delegatenkette in einer lokalen Variablen speichern oder den Operator '?.' Verwenden Handler anrufen.
Zusätzlich zu dem obigen Code-Snippet gab es 35 solcher Stellen.
Übrigens wurden auch
785 Warnungen von
V3024 erfüllt. Warnung
V3024 wird ausgegeben, wenn reelle Zahlen mit den Operatoren '! =' Oder '==' verglichen werden. Ich werde hier nicht näher darauf eingehen, warum solche Vergleiche nicht immer korrekt sind - mehr dazu in der Dokumentation, es gibt auch einen Link zu
StackOverflow (das ist es).
In Anbetracht der Tatsache, dass Formeln und Berechnungen häufig eingehalten wurden, können diese Warnungen ebenfalls wichtig sein, obwohl sie auf Stufe 3 gebracht werden (da sie in allen Projekten nicht relevant sind).
Wenn Sie sicher sind, dass diese Warnungen irrelevant sind, können Sie sie mit
fast einem Klick entfernen, wodurch sich die Gesamtzahl der Analysatorvorgänge verringert.
Fazit
Irgendwie stellte sich heraus, dass ich lange Zeit keine Artikel über das Überprüfen von Projekten geschrieben hatte, und es war sehr angenehm, diesen Prozess noch einmal zu berühren. Ich hoffe, dass Sie aus diesem Artikel auch etwas Neues / Nützliches gelernt haben oder es zumindest mit Interesse gelesen haben.
Ich wünsche den Entwicklern eine frühzeitige Korrektur der Problembereiche und erinnere Sie daran, dass es normal ist, Fehler zu machen, aber wir sind Menschen. Dafür werden zusätzliche Tools wie statische Analysegeräte benötigt, um herauszufinden, was eine Person vermisst hat, oder? Wie auch immer - viel Glück mit dem Projekt und vielen Dank für die Arbeit!
Und denken Sie daran, dass der maximale Nutzen eines statischen Analysators durch seine
regelmäßige Verwendung erreicht wird .
Alles Gute!

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Sergey Vasiliev.
Welche Fehler lauern im Infer.NET-Code?