L'étude du code de la calculatrice continue! Dans cette revue, le projet SpeedCrunch sera examiné - le deuxiÚme plus populaire parmi les calculatrices gratuites.
Présentation
SpeedCrunch est une calculatrice scientifique de précision pilotée par clavier avec une interface utilisateur rapide. Il s'agit d'un logiciel gratuit et open source disponible sur Windows, Linux et macOS.
Le code source est hébergé sur
BitBucket . Je n'aimais pas vraiment la documentation d'assemblage, qui, Ă mon avis, devrait ĂȘtre Ă©crite plus en dĂ©tail. Les exigences spĂ©cifient «Qt 5.2 ou version ultĂ©rieure», bien que plusieurs packages spĂ©cifiques aient Ă©tĂ© nĂ©cessaires, ce qui n'Ă©tait pas facile Ă apprendre du journal CMake. Soit dit en passant, il est dĂ©sormais recommandĂ© d'appliquer un Dockerfile Ă un projet pour configurer rapidement l'environnement de dĂ©veloppement souhaitĂ©.
Pour comparaison avec d'autres calculatrices, j'apporte la sortie de l'utilitaire Cloc:
Avis de bugs dans d'autres projets:
PVS-Studio a Ă©tĂ© utilisĂ© comme outil d'analyse statique. Il s'agit d'un ensemble de solutions pour le contrĂŽle de la qualitĂ© du code, la recherche d'erreurs et les vulnĂ©rabilitĂ©s potentielles. Les langages pris en charge incluent: C, C ++, C # et Java. L'analyseur peut ĂȘtre lancĂ© sur Windows, Linux et macOS.
Logique étrange dans une boucle
V560 Une partie de l'expression conditionnelle est toujours vraie:! RuleFound. evaluator.cpp 1410
void Evaluator::compile(const Tokens& tokens) { .... while (!syntaxStack.hasError()) { bool ruleFound = false;
Notez la variable
ruleFound . à chaque itération, elle est définie sur false. Mais si vous regardez le corps de l'ensemble du cycle, dans certaines conditions, cette variable est définie sur true, mais elle ne sera pas prise en compte lors de la nouvelle itération du cycle. TrÚs probablement, la variable
ruleFound devait ĂȘtre dĂ©clarĂ©e avant la boucle.
Comparaisons suspectes
V560 Une partie de l'expression conditionnelle est toujours vraie: 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) {
Si la variable
shouldStop est
vraie , alors la variable
m_scrollDirection aura l'une des deux valeurs: -1 ou 1. Par conséquent, dans l'instruction conditionnelle suivante, la valeur de la variable
m_scrollDirection ne
sera certainement pas nulle, ce que l'analyseur avertit.
V668 Il est inutile de tester le pointeur 'item' sur null, car la mémoire a été allouée à l'aide de l'opérateur 'new'. L'exception sera générée en cas d'erreur d'allocation de mémoire. 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); .... } .... }
La mémoire d'un objet de type
QTreeWidgetItem est allouée à l'aide du nouvel opérateur. Cela signifie que si l'allocation dynamique de mémoire n'est pas possible, une exception
std :: bad_alloc () sera levée. Par conséquent, la vérification du pointeur de l'
Ă©lĂ©ment est superflue et peut ĂȘtre supprimĂ©e.
Déréférence NULL potentielle
V595 Le pointeur «ioparams» a Ă©tĂ© utilisĂ© avant d'ĂȘtre vĂ©rifiĂ© par rapport Ă nullptr. VĂ©rifiez les lignes: 969, 983. floatio.c 969
int cattokens(....) { .... if (printexp) { if (expbase < 2) expbase = ioparams->expbase;
Le pointeur
ioparams est dĂ©rĂ©fĂ©rencĂ© avant d'ĂȘtre vĂ©rifiĂ© pour sa validitĂ©. TrĂšs probablement, une erreur potentielle s'est glissĂ©e dans le code. Le dĂ©rĂ©fĂ©rencement Ă©tant soumis Ă plusieurs conditions, le problĂšme peut se manifester rarement, mais avec prĂ©cision.
Division par zéro
V609 Divisez par zéro. Plage du dénominateur [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;
La fonction
lgbase permet de
renvoyer une valeur nulle, par laquelle la division est ensuite effectuĂ©e. Potentiellement, tout autre Ă©lĂ©ment que les valeurs 2, 8 et 16 peut ĂȘtre transmis Ă la fonction.
Comportement indéfini
V610 Comportement
indéfini . Vérifiez l'opérateur de décalage «<<». L'opérande gauche '(~ 0)' est négatif. floatlogic.c 64
static char _signextend( t_longint* longint) { unsigned mask; signed char sign; sign = _signof(longint); mask = (~0) << SIGNBIT;
Le résultat de l'inversion de zéro est placé dans le type de signe
int , donc le résultat sera un nombre négatif, pour lequel un décalage est ensuite effectué. Décaler un nombre négatif vers la gauche est un comportement indéfini.
La liste complĂšte des endroits dangereux:
- V610 Comportement indéfini. Vérifiez l'opérateur de décalage «<<». L'opérande gauche '(- 1)' est négatif. floatnum.c 289
- V610 Comportement indéfini. Vérifiez l'opérateur de décalage «<<». L'opérande gauche '(- 1)' est négatif. floatnum.c 325
- V610 Comportement indéfini. Vérifiez l'opérateur de décalage «<<». L'opérande gauche '(- 1)' est négatif. floatnum.c 344
- V610 Comportement indéfini. Vérifiez l'opérateur de décalage «<<». L'opérande gauche '(- 1)' est négatif. floatnum.c 351
Balises HTML non fermées
V735 Peut-ĂȘtre un HTML incorrect. La balise de fermeture "</body>" a Ă©tĂ© rencontrĂ©e, tandis que la balise "</div>" Ă©tait attendue. 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; }
Comme cela arrive souvent avec le code C / C ++, rien n'est clair à partir de la source, alors passons au code prétraité pour ce fragment:

L'analyseur a dĂ©tectĂ© une Ă©tiquette div non fermĂ©e. Il y a beaucoup de fragments de code html dans ce fichier et maintenant il devrait ĂȘtre vĂ©rifiĂ© en plus par les dĂ©veloppeurs.
Voici quelques endroits plus suspects qui ont été trouvés en utilisant PVS-Studio:
- V735 Peut-ĂȘtre un HTML incorrect. La balise de fermeture "</td>" a Ă©tĂ© rencontrĂ©e, tandis que la balise "</sub>" Ă©tait attendue. book.cpp 344
- V735 Peut-ĂȘtre un HTML incorrect. La balise de fermeture "</td>" a Ă©tĂ© rencontrĂ©e, tandis que la balise "</sub>" Ă©tait attendue. book.cpp 347
Opérateur d'affectation
V794 L'opĂ©rateur d'affectation doit ĂȘtre protĂ©gĂ© contre le cas de 'this == & other'. quantitĂ©.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; }
Il est recommandĂ© de considĂ©rer la situation lorsque l'objet est assignĂ© Ă lui-mĂȘme en comparant les pointeurs.
En d'autres termes, les deux lignes de code suivantes doivent ĂȘtre ajoutĂ©es au dĂ©but du corps de la fonction:
if (this == &other) return *this;
Rappel
V601 La valeur 'false' est implicitement
convertie en type entier. cmath.cpp 318
int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false;
Parfois, dans les commentaires de nos articles, ils suggÚrent que certains avertissements sont émis sur un code incomplet. Oui, cela arrive, mais quand c'est vraiment le cas, c'est écrit directement à ce sujet.
Conclusion
Examens dĂ©jĂ disponibles de trois calculatrices: Windows Calculator, Qalculate! et SpeedCrunch. Nous sommes prĂȘts Ă continuer de rechercher le code des calculatrices populaires. Vous pouvez proposer des projets pour vĂ©rification, car les Ă©valuations du logiciel ne reflĂštent pas toujours l'image rĂ©elle.
Vérifiez votre «calculatrice» en téléchargeant
PVS-Studio et en essayant votre projet :-)

Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Svyatoslav Razmyslov.
Suivre les traces des calculatrices: SpeedCrunch