Warten auf die Linux-Version:Überprüfen des Codes des Inkscape-Grafikeditors

Warten auf die Linux-Version:Überprüfen des Codes des Inkscape-Grafikeditors

In diesem Artikel spreche ich über die Analyseergebnisse für ein weiteres beliebtes Open-Source-Projekt, den Vektorgrafik-Editor Inkscape 0.92. Das Projekt entwickelt sich seit über 12 Jahren und bietet eine große Anzahl von Funktionen, um mit verschiedenen Vektorbildformaten zu arbeiten. Im Laufe dieser Zeit ist die Codebasis auf 600.000 Codezeilen angewachsen, und jetzt ist der richtige Zeitpunkt, sie mit dem statischen Analysator von PVS-Studio zu überprüfen.

Einführung

Inkscape ist ein plattformübergreifender Open-Source-Vektorgrafikeditor. Es wird sowohl von Amateur- als auch von professionellen Designern auf der ganzen Welt verwendet, um Bilder, Symbole, Logos, Diagramme, Karten und Webgrafiken zu erstellen. Inkscape hat sich zu einem der beliebtesten Tools in diesem Bereich entwickelt. Das Projekt wurde 2003 als Fork des Sodipodi-Projekts gegründet und befindet sich noch in der Entwicklung. Weitere Informationen zu Inkscape finden Sie auf der offiziellen Website.

Für diese Analyse haben wir die neueste Version von Inkscape, 0.92, verwendet, deren Quellcodes aus dem GitHub-Repository heruntergeladen werden können, und den statischen Analysator PVS-Studio 6.07, der hier heruntergeladen werden kann. Beachten Sie, dass zum Zeitpunkt der Erstellung dieses Artikels nur die Windows-Version von PVS-Studio verfügbar ist. Die Situation wird sich jedoch bald verbessern, und Sie können sich bereits für einen Beta-Test der Linux-Version bewerben. Details finden Sie im Artikel "PVS-Studio bekennt sich zu Linux".

Kommen wir zurück zu den Fehlern. Beachten Sie, dass ich nur die interessantesten Warnungen ausgewählt habe, um sie in diesem Artikel zu diskutieren. Um eine gründlichere Analyse selbst durchzuführen, sollten sich die Projektautoren mit uns in Verbindung setzen, damit wir ihnen einen temporären PVS-Studio-Schlüssel und den Analysebericht zusenden können. Da es noch keine öffentliche Version von PVS-Studio gibt, können sie das Tool PVS-Studio Standalone verwenden, das unter Windows läuft, um den Bericht anzuzeigen. Stimmt, es ist unbequem, aber bitte haben Sie etwas Geduld:Der große Tag der Veröffentlichung der Linux-Version steht kurz bevor.

Analyseergebnisse

Testen eines Zeigers auf null nach new

Diagnosemeldung von PVS-Studio :V668 Es hat keinen Sinn, den 'outputBuf'-Zeiger gegen null zu testen, da der Speicher mit dem 'new'-Operator allokiert wurde. Die Ausnahme wird im Fall eines Speicherzuweisungsfehlers generiert. gzipstream.cpp 180

bool GzipInputStream::load()
{
  ....
  outputBuf = new unsigned char [OUT_SIZE];
  if ( !outputBuf ) {  // <=
    delete[] srcBuf;
    srcBuf = NULL;
    return false;
  }
  ....
}

Wie vom modernen C++-Standard angegeben, wird new, wenn kein Speicher zugewiesen werden kann Operator wirft ein std::bad_alloc() Ausnahme, anstatt nullptr zurückzugeben . Wenn das System keinen Speicher zuordnen kann, wird eine Ausnahme ausgelöst und die Funktion wird nicht mehr ausgeführt. Das Programm wird daher niemals in den Codeblock nach der Bedingung eintreten.

In diesem speziellen Fall kann der Fehler zu einem Speicherverlust führen. Die offensichtlichste Lösung ist die Verwendung von try {....} catch(const std::bad_alloc &) {....} blockieren, aber ein viel besserer Weg ist es, intelligente Zeiger zu verwenden, anstatt den Speicher explizit freizugeben.

Andere ähnliche Zeigerprüfungen:

  • V668 Es macht keinen Sinn, den 'destbuf'-Zeiger gegen null zu testen, da der Speicher mit dem 'new'-Operator allokiert wurde. Die Ausnahme wird im Fall eines Speicherzuweisungsfehlers generiert. gzipstream.cpp 397
  • V668 Es macht keinen Sinn, den 'srcBuf'-Zeiger gegen null zu testen, da der Speicher mit dem 'new'-Operator allokiert wurde. Die Ausnahme wird im Fall eines Speicherzuweisungsfehlers generiert. gzipstream.cpp 175
  • V668 Es macht keinen Sinn, den 'oldcurve'-Zeiger gegen null zu testen, da der Speicher mit dem 'new'-Operator allokiert wurde. Die Ausnahme wird im Fall eines Speicherzuweisungsfehlers generiert. sp-lpe-item.cpp 719

Vergleiche dies mit Null

Diagnosemeldung von PVS-Studio :V704 '!this'-Ausdruck in bedingten Anweisungen sollte vermieden werden - dieser Ausdruck ist auf neueren Compilern immer falsch, da 'this'-Zeiger niemals NULL sein kann. sp-lpe-item.cpp 213

bool SPLPEItem::performPathEffect(....) {
  if (!this) {
    return false;
  }
  ....
}

Wie vom modernen C++-Standard angegeben, ist die Datei this Zeiger kann niemals null sein. Vergleich dies mit Null führt oft zu unerwarteten Fehlern. Details siehe Beschreibung der Diagnose V704.

Ein weiterer Testfall dies für nullptr :

  • V704 'this'-Ausdruck in bedingten Anweisungen sollte vermieden werden - dieser Ausdruck ist auf neueren Compilern immer wahr, weil 'this'-Zeiger niemals NULL sein kann. sp-paint-server.cpp 42

Gefährliche Parameterneudefinition

Diagnosemeldung von PVS-Studio :V581 Die Bedingungsausdrücke der nebeneinander stehenden 'if'-Operatoren sind identisch. Überprüfen Sie die Zeilen:1046, 1051. sp-mesh-array.cpp 1051

void SPMeshNodeArray::create( ...., Geom::OptRect bbox ) // <=
{
  ....
  if( !bbox ) {
    std::cout << "SPMeshNodeArray::create(): bbox empty" 
              << std::endl;
    Geom::OptRect bbox = item->geometricBounds();        // <=
  }
  if( !bbox ) {                                          // <=
    std::cout << "ERROR: No bounding box!" 
              << std::endl;
    return;
  }
  ....
}

Der Programmierer möchte ein neues Objekt vom Typ Geom::OptRect für die bbox erstellt werden Parameter, wenn dieser Parameter gleich nullptr ist; wenn das Objekt nicht erstellt werden kann, sollte die Ausführung der Methode mit einer Fehlermeldung enden.

Dieser Code verhält sich jedoch ganz anders als vom Autor erwartet. Wenn die bbox Parameter ist gleich nullptr , eine komplett neue bbox -Objekt wird innerhalb des ersten if erstellt blockiert und beim Verlassen dieses Blocks sofort zerstört. Als Ergebnis wird die zweite Bedingung jedes Mal ausgeführt, wenn die erste ausgeführt wird, also jedes Mal, wenn die bbox ausgeführt wird Parameter ist gleich nullptr , wird die Methode beendet und eine Fehlermeldung ausgegeben.

Dieses Codefragment sollte wie folgt umgeschrieben werden:

void SPMeshNodeArray::create( ...., Geom::OptRect bbox )
{
  ....
  if( !bbox ) {
    std::cout << "SPMeshNodeArray::create(): bbox empty" 
              << std::endl;
    bbox = item->geometricBounds();
    if( !bbox ) {
      std::cout << "ERROR: No bounding box!" 
                << std::endl;
      return;
    }
  }
  ....
}

Falsch auskommentierte Zeile

Diagnosemeldung von PVS-Studio :V628 Es ist möglich, dass die Zeile falsch auskommentiert wurde, wodurch die Betriebslogik des Programms geändert wurde. FontFactory.cpp 705

font_instance *font_factory::Face(....)
{
  ....
  if( features[0] != 0 ) // <=
    // std::cout << "          features: " << std::endl;

  for( unsigned k = 0; features[k] != 0; ++k ) {
  // dump_tag( &features[k], "            feature: ");
  ++(res->openTypeTables[ extract_tag(&features[k])]);
  }
  ....
}

Der Programmierer hat vergessen, die Zeile mit der Bedingung auszukommentieren, die zum Debuggen verwendet wurde. Der Fehler ist glücklicherweise harmlos. Es ist nur die Bedingung im if -Anweisung repliziert einfach die Bedingung der for-Schleife bei der ersten Iteration, aber es ist sicherlich ein Fehler, der später gefährlich werden kann.

"Einmalige" Schleife

Diagnosemeldung von PVS-Studio :V612 Ein unbedingter 'Break' innerhalb einer Schleife. text_reassemble.c 417

int TR_kern_gap(....)
{ 
  ....
  while(ptsp && tsp){
    ....
    if(!text32){
      ....
      if(!text32)break;
    }
    ....
    if(!ptxt32){
      ....
      if(!ptxt32)break;
    }
    ....
    break; // <=
  }
  ....
  return(kern);
}

Diese Schleife bricht in jedem Fall nach der ersten Iteration ab, da vor dem break keine Bedingung steht Aussage. Ich bin mir nicht sicher, was der Autor wirklich mit diesem Code wollte. Wenn hier kein Fehler auftritt, ist es immer noch besser, den Code neu zu schreiben und while zu ersetzen mit wenn .

Sehr seltsame Methode

Diagnosemeldung von PVS-Studio :V571 Wiederkehrende Prüfung. Die Bedingung 'back ==false' wurde bereits in Zeile 388 verifiziert. Path.cpp 389

void
Path::SetBackData (bool nVal)
{
  if (back == false) {
    if (nVal == true && back == false) {
      back = true;
      ResetPoints();
    } else if (nVal == false && back == true) {
      back = false;
      ResetPoints();
    }
  } else {
    if (nVal == true && back == false) {
      back = true;
      ResetPoints();
    } else if (nVal == false && back == true) {
      back = false;
      ResetPoints();
    }
  }
}

Es ist schwer zu sagen, warum diese Methode so seltsam geschrieben ist:das if und sonst Blöcke sind identisch und es gibt viele unnötige Überprüfungen. Auch wenn hier kein logischer Fehler vorliegt, sollte diese Methode unbedingt umgeschrieben werden:

void
Path::SetBackData (bool nVal)

{

  back = nVal;
  ResetPoints();

}

Komma verloren

Diagnosemeldung von PVS-Studio :V737 Es ist möglich, dass das Komma ',' am Ende der Zeichenfolge fehlt. Zeichnungstext.cpp 272

void DrawingText::decorateStyle(....)
{
  ....
  int dashes[16]={
     8,  7,   6,   5,
     4,  3,   2,   1,
    -8, -7,  -6,  -5  // <=
    -4, -3,  -2,  -1
  };
  ....
}

Ein Komma fehlt, was zur Initialisierung der Bindestriche führt Array auf falsche Werte.

Erwartete Werte:

{ 8,  7,  6,  5,
  4,  3,  2,  1,
 -8, -7, -6, -5,
 -4, -3, -2, -1 }

Aktuelle Werte:

{ 8,  7,  6,  5, 
  4,  3,  2,  1,
 -8, -7, -6, -9,
 -3, -2, -1,  0 }

Das 12. Element wird auf den Wert -5 - 4 ==-9 initialisiert , während das letzte Element (das keinen zugeordneten Wert in der Array-Initialisierungsliste hat) mit Null initialisiert wird, wie vom C++-Standard angegeben.

Falsche Länge in strncmp

Diagnosemeldung von PVS-Studio :V666 Prüfen Sie das dritte Argument der Funktion 'strncmp'. Es ist möglich, dass der Wert nicht der Länge eines Strings entspricht, der mit dem zweiten Argument übergeben wurde. blend.cpp 85

static Inkscape::Filters::FilterBlendMode
 sp_feBlend_readmode(....) {
  ....
  switch (value[0]) {
    case 'n':
      if (strncmp(value, "normal", 6) == 0)
        return Inkscape::Filters::BLEND_NORMAL;
      break;
    case 'm':
      ....
    case 's':
      if (strncmp(value, "screen", 6) == 0)
          return Inkscape::Filters::BLEND_SCREEN;
      if (strncmp(value, "saturation", 6) == 0) // <=
          return Inkscape::Filters::BLEND_SATURATION;
      break;
    case 'd':
      ....
    case 'o':
      if (strncmp(value, "overlay", 7) == 0)
          return Inkscape::Filters::BLEND_OVERLAY;
      break;
    case 'c':
      ....
    case 'h':
      if (strncmp(value, "hard-light", 7) == 0) // <=
          return Inkscape::Filters::BLEND_HARDLIGHT;
      ....
      break;
    ....
  }
}

Der strncmp Funktion empfängt falsche Längen von Strings "saturation" und "hartes Licht" . Als Ergebnis werden nur die ersten 6 bzw. 7 Zeichen verglichen. Dieser Fehler muss aus der Verwendung der sogenannten Copy-Paste-Programmierung resultieren und führt zu Fehlalarmen, wenn neue Elemente zu switch-case hinzugefügt werden . Der Code muss repariert werden:

....
if (strncmp(value, "saturation", 10) == 0)
....
if (strncmp(value, "hard-light", 10) == 0)
....

Potentialdivision durch Null

Diagnosemeldung von PVS-Studio :V609 Teile durch Null. Nennerbereich [0..999]. lpe-fillet-chamfer.cpp 607

Geom::PathVector
LPEFilletChamfer::doEffect_path(....)
{
  ....
  if(....){
    ....
  } else if (type >= 3000 && type < 4000) {
      unsigned int chamferSubs = type-3000;
      ....
      double chamfer_stepsTime = 1.0/chamferSubs;
      ....
  }
  ...
}

Wenn der Typ Variable gleich 3000 , der Wert von chamferSubs Variable wird 0 sein. Daher ist der Wert von chamfer_stepsTime wird 1.0/0 ==inf sein , was der Programmierer offensichtlich nicht erwartet hat. Um dies zu beheben, muss die Bedingung in if Block geändert werden soll:

...
else if (type > 3000 && type < 4000)
...

Eine andere Möglichkeit besteht darin, die Situation separat zu behandeln, wenn chamferSubs ==0 .

Ein weiteres ähnliches Problem:

  • V609 Teile durch Null. Nennerbereich [0..999]. lpe-fillet-chamfer.cpp 623

Fehlt noch was?

Diagnosemeldung von PVS-Studio :V646 Erwägen Sie die Überprüfung der Anwendungslogik. Es ist möglich, dass das Schlüsselwort „else“ fehlt. sp-item.cpp 204

void SPItem::resetEvaluated() 
{
  if ( StatusCalculated == _evaluated_status ) {
    ....
  } if ( StatusSet == _evaluated_status ) { // <=
      ....
  }
}

Als Codeformatierung (die zweite if -Anweisung belegt dieselbe Zeile wie die schließende geschweifte Klammer des vorherigen if Aussage) und die Logik suggeriert, das else Schlüsselwort fehlt:

....
if ( StatusCalculated == _evaluated_status ) {
    ....
  } else if ( StatusSet == _evaluated_status ) {
      ....
  }
}
....

Verwenden eines Nullzeigers

Diagnosemeldung von PVS-Studio :V595 Der 'priv'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Zeilen prüfen:154, 160. document.cpp 154

SPDocument::~SPDocument() 
{
  priv->destroySignal.emit();                      // <=
  ....
  if (oldSignalsConnected) {
    priv->selChangeConnection.disconnect();        // <=
    priv->desktopActivatedConnection.disconnect(); // <=
  } else {
    ....
  }
  if (priv) {                                      // <=
    ....
  }
  ....
}

Im untersten if Block, der priv Zeiger wird auf NULL getestet da der Programmierer davon ausgeht, dass es NULL sein kann . Allerdings wurde dieser Zeiger schon etwas früher ungeprüft verwendet. Dieser Fehler muss behoben werden, indem der Zeiger überprüft wird, bevor er verwendet wird.

Andere ähnliche Fehler:

  • V595 Der 'Teile'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:624, 641. sp-offset.cpp 624
  • V595 Der '_effects_list'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:103, 113. effect.cpp 103
  • V595 Der 'num'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:1312, 1315. cr-tknzr.c 1312
  • V595 Der 'Selektor'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:3463, 3481. cr-parser.c 3463
  • V595 Der 'a_this'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:1552, 1562. cr-sel-eng.c 1552
  • V595 Der 'FillData'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:5898, 5901. upmf.c 5898
  • V595 Der 'event_context'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:1014, 1023. tool-base.cpp 1014
  • V595 Der 'event_context'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Zeilen prüfen:959, 970. tool-base.cpp 959
  • V595 Der 'this->repr'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:662, 665. eraser-tool.cpp 662
  • V595 Der 'this->repr'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:662, 665. eraser-tool.cpp 662
  • V595 Der 'modified_connection'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:1114, 1122. gradient-vector.cpp 1114
  • V595 Der 'c'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Zeilen prüfen:762, 770. freehand-base.cpp 762
  • V595 Der 'release_connection'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:505, 511. gradient-toolbar.cpp 505
  • V595 Der 'modified_connection'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen:506, 514. gradient-toolbar.cpp 506

Fehlendes Semikolon

Diagnosemeldung von PVS-Studio :V504 Es ist sehr wahrscheinlich, dass das Semikolon ';' fehlt nach dem Schlüsselwort „return“. svg-fonts-dialog.cpp 167

void GlyphComboBox::update(SPFont* spfont)
{
  if (!spfont) return // <=
//TODO: figure out why do we need to append("")
// before clearing items properly...

//Gtk is refusing to clear the combobox 
//when I comment out this line
  this->append(""); 
  this->remove_all();
}

Nach return fehlt ein Semikolon (";") , was eigentlich die Ursache für das in den Kommentaren erwähnte Problem ist. Es passiert, weil die Zeile auskommentiert wird:

 this->append("");

ergibt folgendes Konstrukt:

if (!spfont) return this->remove_all();

Daher wird die Combobox nur geleert, wenn spfont ==NULL .

Unbenutzter Parameter

Diagnosemeldung von PVS-Studio :V763 Parameter 'new_value' wird immer neu in den Funktionskörper geschrieben, bevor er verwendet wird. sp-xmlview-tree.cpp 259

void element_attr_changed(.... const gchar * new_value, ....)
{
  NodeData *data = static_cast<NodeData *>(ptr);
  gchar *label;

  if (data->tree->blocked) return;

  if (0 != strcmp (key, "id") &&
      0 != strcmp (key, "inkscape:label"))
        return;

  new_value = repr->attribute("id"); // <=
  ....
}

Der Wert von new_value Parameter ändert sich immer, bevor er verwendet wird. Vielleicht sollte dieser Parameter aus der Parameterliste entfernt werden, da es im Moment keinen Sinn macht, ihn dort zu haben.

Ein weiteres ähnliches Problem:

  • 763 Der Parameter 'widget' wird immer im Funktionsrumpf umgeschrieben, bevor er verwendet wird. ruler.cpp 923

Zeiger auf ein nicht vorhandenes Array

Diagnosemeldung von PVS-Studio :V507 Zeiger auf lokales Array 'n' wird außerhalb des Bereichs dieses Arrays gespeichert. Ein solcher Zeiger wird ungültig. inkscape.cpp 582

void
Application::crash_handler (int /*signum*/)
{
  ....
  if (doc->isModifiedSinceSave()) {
    const gchar *docname;
  ....
  if (docname) {
    ....
    if (*d=='.' && d>docname && dots==2) {
      char n[64];
      size_t len = MIN (d - docname, 63);
      memcpy (n, docname, len);
      n[len] = '\0';
      docname = n;
    }
  }
  if (!docname || !*docname) docname = "emergency";
  ....
}

Das n Die Lebensdauer des Arrays ist kürzer als die des docname Zeiger, der auf dieses Array zeigt. Dieses Problem führt dazu, dass mit dem ungültigen Zeiger docname gearbeitet wird . Eine der möglichen Lösungen besteht darin, das n zu definieren Array neben dem docname Zeiger:

....
if (doc->isModifiedSinceSave()) {
  const gchar *docname;
  char n[64];
....

Andere ähnliche Fehler:

  • V507 Zeiger auf lokales Array 'in_buffer' wird außerhalb des Bereichs dieses Arrays gespeichert. Ein solcher Zeiger wird ungültig. inkjar.cpp 371
  • V507 Zeiger auf lokales Array 'out_buffer' wird außerhalb des Bereichs dieses Arrays gespeichert. Ein solcher Zeiger wird ungültig. inkjar.cpp 375

Falscher Objektname in einer Bedingung

Diagnosemeldung von PVS-Studio :V517 Die Verwendung des Musters „if (A) {...} else if (A) {...}“ wurde erkannt. Es besteht die Wahrscheinlichkeit des Vorliegens eines logischen Fehlers. Zeilen prüfen:640, 643. font-variants.cpp 640

void
FontVariants::fill_css( SPCSSAttr *css ) 
{
  ....
  if( _caps_normal.get_active() ) {
    css_string = "normal";
    caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL;
  } else if( _caps_small.get_active() ) {
    ....
  } else if( _caps_all_small.get_active() ) {
    ....
  } else if( _caps_all_petite.get_active() ) { // <=
    css_string = "petite";                     // <=
    caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE;
  } else if( _caps_all_petite.get_active() ) { // <=
    css_string = "all-petite";                 // <=
    caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE;
  } 
  ....
}

In der Bedingung vor _caps_all_petite.get_active() , die _caps_petite Objektname sollte anstelle von _caps_all_petite verwendet werden . Dieser Code sieht aus, als wäre er mit Copy-Paste geschrieben worden.

Leichtsinnige Verwendung numerischer Konstanten

Diagnosemeldung von PVS-Studio :V624 Die Konstante 0,707107 wird verwendet. Der resultierende Wert könnte ungenau sein. Erwägen Sie die Verwendung der M_SQRT1_2-Konstante aus . PathOutline.cpp 1198


void
Path::OutlineJoin (....)
{
  ....
  if (fabs(c2) > 0.707107) {
    ....
  }
  ....
}

Dieses Format ist nicht ganz korrekt und kann zu einem Verlust an Rechengenauigkeit führen. Verwenden Sie besser die mathematische Konstante M_SQRT1_2 (die Umkehrung der Quadratwurzel von 2), die in der Datei deklariert ist . Ich denke, dieser Code funktioniert eigentlich gut genug, aber ich dachte, ich sollte ihn als Beispiel für unordentlichen Code erwähnen.

Andere ähnliche Defekte:

  • V624 Die Konstante 1.414213562 wird verwendet. Der resultierende Wert könnte ungenau sein. Erwägen Sie die Verwendung der M_SQRT2-Konstante aus . verbs.cpp 1848
  • V624 Die Konstante 3.14159 wird verwendet. Der resultierende Wert könnte ungenau sein. Erwägen Sie die Verwendung der M_PI-Konstante aus . odf.cpp 1568
  • V624 Die Konstante 1.414213562 wird verwendet. Der resultierende Wert könnte ungenau sein. Erwägen Sie die Verwendung der M_SQRT2-Konstante aus . inkscape-preferences.cpp 1334

Identische Ausdrücke

Diagnosemeldung von PVS-Studio :V501 Links und rechts vom Operator '&&' gibt es identische Teilausdrücke 'Ar.maxExtent()

void mono_intersect(....)
{
   if(depth > 12 || (Ar.maxExtent() < tol && Ar.maxExtent() < tol)) 
   {
     ....
   }
   ....
}

Die Überprüfung des Ar.maxExtent() Bedingung wird zweimal ausgeführt, was anscheinend auf einige Änderungen im Code zurückzuführen ist. Die Autoren müssen entweder den Ausdruck korrigieren oder einfach die Duplikatprüfung entfernen.

Eine weitere ähnliche Prüfung:

  • V501 Links und rechts vom Operator '&&' gibt es identische Teilausdrücke 'Ar.maxExtent() <0.1'. path-intersection.cpp 364

Identische Operationen in if- und else-Blöcken

Diagnosemeldung von PVS-Studio :V523 Die 'then'-Anweisung entspricht der 'else'-Anweisung. ShapeRaster.cpp 1825

void Shape::AvanceEdge(....)
{
  ....
  if ( swrData[no].sens ) { 
    if ( swrData[no].curX < swrData[no].lastX ) {
      line->AddBord(swrData[no].curX,
                    swrData[no].lastX,
                    false);
    } else if ( swrData[no].curX > swrData[no].lastX ) { 
        line->AddBord(swrData[no].lastX,
                      swrData[no].curX,
                      false);
      }
  } else {
    if ( swrData[no].curX < swrData[no].lastX ) {
      line->AddBord(swrData[no].curX,
                    swrData[no].lastX,
                    false);
    } else if ( swrData[no].curX > swrData[no].lastX ) {
        line->AddBord(swrData[no].lastX,
                      swrData[no].curX,
                      false);
    }
  }
}

Das wenn und sonst Blöcke enthalten denselben Code, daher müssen die Autoren dieses Fragment untersuchen und entweder die Logik korrigieren oder den doppelten Zweig entfernen.

Andere ähnliche Probleme:

  • V523 Die 'then'-Anweisung entspricht der 'else'-Anweisung. ShapeRaster.cpp 1795
  • V523 Die 'then'-Anweisung entspricht der 'else'-Anweisung. PathCutting.cpp 1323
  • V523 Die 'then'-Anweisung entspricht der 'else'-Anweisung. ShapeSweep.cpp 2340

Schlussfolgerung

Diese Analyse deckte viele Programmierfehler auf, die durch mangelnde Aufmerksamkeit verursacht wurden. Der statische Analysator von PVS-Studio ist sehr gut darin, solche Fehler zu erkennen, was hilft, Programmierern Zeit und Nerven zu sparen. Das Wichtigste bei der statischen Analyse ist, dass sie regelmäßig durchgeführt werden sollte, damit das Tool Tippfehler und andere Fehler erkennen kann, sobald sie auftreten. Einmalige Schecks, wie dieser, sind gut für die Werbung für PVS-Studio, aber nicht wirklich effektiv. Stellen Sie sich statische Analysewarnungen als erweiterte Compiler-Warnungen vor, und Compiler-Warnungen sind etwas, mit dem Sie sich ständig auseinandersetzen möchten, nicht nur einmal vor einer Veröffentlichung. Ich hoffe, jeder Programmierer, der sich um die Qualität seines Codes kümmert, kann sich auf diese Analogie beziehen.

Willkommen beim Herunterladen von PVS-Studio und beim Testen mit Ihren eigenen Projekten.

P.S.