计算器代码的研究仍在继续! 在这次审查中,将审查SpeedCrunch项目-在免费计算器中第二受欢迎的项目。
引言
SpeedCrunch是一款具有快速用户界面的精密键盘驱动型科学计算器。 这是Windows,Linux和macOS上的免费开源软件。
源代码托管在
BitBucket上 。 我真的不喜欢汇编文档,我认为应该更详细地编写。 要求指定“ Qt 5.2或更高版本”,尽管需要几个特定的软件包,但从CMake日志中不容易学习。 顺便说一句,现在,将Dockerfile应用于项目以快速配置所需的开发人员环境是一种很好的做法。
为了与其他计算器进行比较,我带来了Cloc实用程序的输出:
其他项目中的错误的评论:
PVS-Studio被用作静态分析工具。 这是一组用于代码质量控制,搜索错误和潜在漏洞的解决方案。 支持的语言包括:C,C ++,C#和Java。 该分析仪可以在Windows,Linux和macOS上启动。
循环中的奇怪逻辑
V560条件表达式的一部分始终为true :! RuleFound。 evaluator.cpp 1410
void Evaluator::compile(const Tokens& tokens) { .... while (!syntaxStack.hasError()) { bool ruleFound = false;
注意
ruleFound变量。 在每次迭代时,将其设置为false。 但是,如果您查看整个循环的主体,则在某些条件下,此变量将设置为true,但在循环的新迭代中将不考虑该变量。 最有可能的是,
必须在循环之前声明
ruleFound变量。
可疑比较
V560条件表达式的一部分始终为true: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) {
如果
shouldStop变量为
true ,则
m_scrollDirection变量将具有以下两个值之一:-1或1。因此,在以下条件语句中,
m_scrollDirection变量的值肯定不会为零,分析器
将对此进行警告。
V668测试“ item”指针是否为null没有意义,因为使用“ new”运算符分配了内存。 如果内存分配错误,将生成异常。 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); .... } .... }
使用new运算符分配
QTreeWidgetItem类型的对象的内存。 这意味着如果无法进行动态内存分配,则将引发异常
std :: bad_alloc() 。 因此,检查
项目指针是多余的,可以删除。
潜在的NULL取消引用
V595在针对nullptr进行验证之前,已使用了“ ioparams”指针。 检查线:969,983。floatio.c 969
int cattokens(....) { .... if (printexp) { if (expbase < 2) expbase = ioparams->expbase;
在检查有效性之前,先取消引用
ioparams指针。 很有可能,潜在的错误潜入了代码中。 由于取消引用是在几种情况下进行的,因此该问题很少会出现,但会准确地显示出来。
被零除
V609除以零。 分母范围[0..4]。 第266章
static int lgbase( signed char base) { switch(base) { case 2: return 1; case 8: return 3; case 16: return 4; } return 0;
lgbase函数允许返回空值,然后通过该值执行除法。 可以将值2、8和16以外的任何内容传递给该函数。
未定义的行为
V610未定义的行为。 检查移位运算符“ <<”。 左操作数'(〜0)'为负。 floatlogic.c 64
static char _signextend( t_longint* longint) { unsigned mask; signed char sign; sign = _signof(longint); mask = (~0) << SIGNBIT;
零反转的结果放置在符号类型
int中 ,因此结果将为负数,然后对其执行移位。 向左移动负数是未定义的行为。
危险场所的完整列表:
- V610未定义的行为。 检查移位运算符“ <<”。 左操作数'(-1)'为负。 floatnum.c 289
- V610未定义的行为。 检查移位运算符“ <<”。 左操作数'(-1)'为负。 floatnum.c 325
- V610未定义的行为。 检查移位运算符“ <<”。 左操作数'(-1)'为负。 floatnum.c 344
- V610未定义的行为。 检查移位运算符“ <<”。 左操作数'(-1)'为负。 floatnum.c 351
未封闭的HTML标签
V735可能是不正确的HTML。 遇到“ </ body>”结束标记,而应使用“ </ div>”标记。 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; }
正如C / C ++代码经常发生的那样,从源头上还不清楚什么,所以让我们来看一下此片段的预处理代码:

分析仪检测到未关闭的div标签。 该文件中有许多html代码片段,现在开发人员应该对其进行额外检查。
以下是使用PVS-Studio发现的一些可疑的地方:
- V735可能是不正确的HTML。 遇到“ </ td>”结束标记,而“ </ sub>”标记是预期的。 book.cpp 344
- V735可能是不正确的HTML。 遇到“ </ td>”结束标记,而“ </ sub>”标记是预期的。 book.cpp 347
赋值运算符
V794应该保护赋值运算符免受'this ==&other'的影响。 数量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; }
建议通过比较指针来考虑将对象分配给自身的情况。
换句话说,应将以下两行代码添加到函数主体的开头:
if (this == &other) return *this;
温馨提示
V601'false '值隐式转换为整数类型。 cmath.cpp 318
int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false;
有时,在对我们文章的评论中,他们建议某些警告是针对不完整的代码发出的。 是的,它确实发生了,但是实际上它是直接写在它上面的。
结论
已有三个计算器的评论:Windows计算器,Qalculate! 和SpeedCrunch。 我们准备继续研究流行的计算器的代码。 您可以提供项目进行验证,因为软件的等级并不总是反映真实情况。
通过下载
PVS-Studio并尝试您的项目来检查“计算器” :-)

如果您想与说英语的读者分享这篇文章,请使用以下链接:Svyatoslav Razmyslov。
跟随计算器的脚步:SpeedCrunch