Hier sind wir und erforschen weiterhin den Code von Taschenrechnern! Heute werfen wir einen Blick auf das Projekt SpeedCrunch, den zweitbeliebtesten kostenlosen Taschenrechner.
Einführung
SpeedCrunch ist ein hochpräziser wissenschaftlicher Taschenrechner mit einer schnellen, tastaturgesteuerten Benutzeroberfläche. Es handelt sich um kostenlose Open-Source-Software, die unter der GPL lizenziert ist und unter Windows, Linux und MacOS ausgeführt wird.
Der Quellcode ist auf
BitBucket verfügbar. Ich war etwas enttäuscht von der Build-Dokumentation, die detaillierter sein könnte. Es heißt, dass Sie "Qt 5.2 oder höher" benötigen, um das Projekt zu erstellen, aber es waren tatsächlich einige spezifische Pakete erforderlich, die aus dem CMake-Protokoll nicht einfach herauszufinden waren. Übrigens wird es heutzutage als bewährte Methode angesehen, eine Docker-Datei in das Projekt aufzunehmen, um dem Benutzer das Einrichten der Entwicklungsumgebung zu erleichtern.
Die folgende Ausgabe des Dienstprogramms Cloc zeigt, wie SpeedCrunch mit anderen Taschenrechnern verglichen wird:
Bug Reviews für die anderen Projekte:
Die Analyse wurde mit dem statischen Analysegerät
PVS-Studio durchgeführt . Dies ist ein Lösungspaket zur Softwarequalitätskontrolle und Erkennung von Fehlern und potenziellen Schwachstellen. PVS-Studio unterstützt C, C ++, C # und Java und läuft unter Windows, Linux und MacOS.
Seltsame Logik in einer Schleife
V560 Ein Teil des bedingten Ausdrucks ist immer wahr:! RuleFound. evaluator.cpp 1410
void Evaluator::compile(const Tokens& tokens) { .... while (!syntaxStack.hasError()) { bool ruleFound = false;
Beachten Sie die Variable
ruleFound : Sie wird bei jeder Iteration auf false gesetzt. Im Hauptteil der Schleife wird diese Variable unter bestimmten Bedingungen auf true gesetzt, bei der nächsten Iteration jedoch wieder auf false. Die Variable
ruleFound sollte wahrscheinlich vor der Schleife deklariert worden sein.
Verdächtige Vergleiche
V560 Ein Teil des bedingten Ausdrucks ist immer wahr: m_scrollDirection! = 0. resultdisplay.cpp 242
void ResultDisplay::fullContentScrollEvent() { QScrollBar* bar = verticalScrollBar(); int value = bar->value(); bool shouldStop = (m_scrollDirection == -1 && value <= 0) || (m_scrollDirection == 1 && value >= bar->maximum()); if (shouldStop && m_scrollDirection != 0) {
Wenn der
Wert der Variable
shouldStop wahr ist , nimmt die Variable
m_scrollDirection einen der beiden Werte an: -1 oder 1. Daher unterscheidet sich ihr Wert in der nächsten bedingten Anweisung definitiv von Null, worüber der Analysator warnt.
V668 Es macht keinen Sinn, den Zeiger 'item' gegen null zu testen, da der Speicher mit dem Operator 'new' zugewiesen wurde. Die Ausnahme wird bei einem Speicherzuordnungsfehler generiert. editor.cpp 998
void EditorCompletion::showCompletion(const QStringList& choices) { .... for (int i = 0; i < choices.count(); ++i) { QStringList pair = choices.at(i).split(':'); QTreeWidgetItem* item = new QTreeWidgetItem(m_popup, pair); if (item && m_editor->layoutDirection() == Qt::RightToLeft) item->setTextAlignment(0, Qt::AlignRight); .... } .... }
Der Speicher für ein Objekt vom Typ
QTreeWidgetItem wird mit dem
neuen Operator zugewiesen.
Dies bedeutet, dass ein Speicherzuordnungsfehler dazu führt, dass eine
std :: bad_alloc () - Ausnahme
ausgelöst wird . Das Überprüfen des Elementzeigers ist daher redundant und kann entfernt werden.
Mögliche NULL-Dereferenzierung
V595 Der Zeiger 'ioparams' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 969, 983. floatio.c 969
int cattokens(....) { .... if (printexp) { if (expbase < 2) expbase = ioparams->expbase;
Der
ioparams- Zeiger wird vor der Prüfung dereferenziert. Es sieht so aus, als ob hier ein Fehler vorliegt. Da der Dereferenzierung eine Reihe von Bedingungen vorausgehen, tritt der Fehler nicht häufig auf, wirkt sich jedoch drastisch aus.
Division durch Null
V609 Durch Null teilen. Nennerbereich [0..4]. floatconvert.c 266
static int lgbase( signed char base) { switch(base) { case 2: return 1; case 8: return 3; case 16: return 4; } return 0;
Die
lgbase- Funktion kann Null zurückgeben, die dann als Divisor verwendet werden kann. Die Funktion kann möglicherweise mit einem beliebigen Wert aufgerufen werden, nicht nur mit 2, 8 oder 16.
Undefiniertes Verhalten
V610 Undefiniertes Verhalten. Überprüfen Sie den Schichtführer '<<'. Der linke Operand '(~ 0)' ist negativ. floatlogic.c 64
static char _signextend( t_longint* longint) { unsigned mask; signed char sign; sign = _signof(longint); mask = (~0) << SIGNBIT;
Da das Ergebnis der Invertierung von Null in einem vorzeichenbehafteten
int gespeichert wird, ist der resultierende Wert eine negative Zahl, die dann verschoben wird. Das Verschieben eines negativen Werts nach links ist ein undefiniertes Verhalten.
Hier ist eine vollständige Liste all dieser Fälle:
- V610 Undefiniertes Verhalten. Überprüfen Sie den Schichtführer '<<'. Der linke Operand '(- 1)' ist negativ. floatnum.c 289
- V610 Undefiniertes Verhalten. Überprüfen Sie den Schichtführer '<<'. Der linke Operand '(- 1)' ist negativ. floatnum.c 325
- V610 Undefiniertes Verhalten. Überprüfen Sie den Schichtführer '<<'. Der linke Operand '(- 1)' ist negativ. floatnum.c 344
- V610 Undefiniertes Verhalten. Überprüfen Sie den Schichtführer '<<'. Der linke Operand '(- 1)' ist negativ. floatnum.c 351
Nicht geschlossene HTML-Tags
V735 Möglicherweise ein falsches HTML. Das schließende Tag "</ body>" wurde gefunden, während das Tag "</ div>" erwartet wurde. book.cpp 127
static QString makeAlgebraLogBaseConversionPage() { return BEGIN INDEX_LINK TITLE(Book::tr("Logarithmic Base Conversion")) FORMULA(y = log(x) / log(a), log<sub>a</sub>x = log(x) / log(a)) END; }
Wie so oft bei C / C ++ - Code hilft das Studium der Quelle nicht viel, um die Dinge herauszufinden. Wir werden uns stattdessen den vorverarbeiteten Code ansehen:

Der Analysator hat ein nicht geschlossenes
div- Tag erkannt. Diese Datei enthält viele HTML-Schnipsel, und die Entwickler müssen auch diesen Code überprüfen.
Hier sind einige andere verdächtige Fälle, die von PVS-Studio gefunden wurden:
- V735 Möglicherweise ein falsches HTML. Das schließende Tag "</ td>" wurde gefunden, während das Tag "</ sub>" erwartet wurde. book.cpp 344
- V735 Möglicherweise ein falsches HTML. Das schließende Tag "</ td>" wurde gefunden, während das Tag "</ sub>" erwartet wurde. book.cpp 347
Zuweisungsoperator
V794 Der Zuweisungsoperator sollte vor dem Fall 'this == & other' geschützt werden. Quantity.cpp 373
Quantity& Quantity::operator=(const Quantity& other) { m_numericValue = other.m_numericValue; m_dimension = other.m_dimension; m_format = other.m_format; stripUnits(); if(other.hasUnit()) { m_unit = new CNumber(*other.m_unit); m_unitName = other.m_unitName; } cleanDimension(); return *this; }
Es wird empfohlen, Situationen zu überprüfen, in denen ein Objekt sich selbst zugewiesen ist, indem Sie die Zeiger vergleichen. Mit anderen Worten, fügen Sie am Anfang des Funktionskörpers die folgenden zwei Zeilen hinzu:
if (this == &other) return *this;
Zur Erinnerung
V601 Der Wert 'false' wird implizit in den Integer-Typ umgewandelt. cmath.cpp 318
int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false;
Manchmal sagen Sie in Kommentaren, dass möglicherweise einige der Warnungen durch unvollständigen Code ausgelöst werden. Ja, das passiert ab und zu, aber wir weisen ausdrücklich auf solche Fälle hin.
Fazit
Wir haben bereits den Code von drei Taschenrechnerprogrammen überprüft - Windows Calculator, Qalculate! Und SpeedCrunch - und werden nicht aufhören. Sie können gerne Projekte vorschlagen, die wir überprüfen sollen, da Software-Rankings nicht immer den tatsächlichen Stand der Dinge widerspiegeln.
Willkommen zum Herunterladen von
PVS-Studio und zum Ausprobieren auf Ihrem eigenen „Rechner“. :-)