在这里,我们将继续探索计算器的代码! 今天,我们将看看名为SpeedCrunch的项目,它是第二受欢迎的免费计算器。
引言
SpeedCrunch是一款高精度科学计算器,具有快速,键盘驱动的用户界面。 它是免费的开源软件,根据GPL许可,可在Windows,Linux和macOS上运行。
源代码可在
BitBucket上获得 。 生成文档令我有些失望,该文档可能会更详细。 它说您需要“ Qt 5.2或更高版本”来构建项目,但实际上它需要一些特定的程序包,这很难从CMake日志中找出。 顺便说一句,将Dockerfile包含到项目中以使用户更容易地设置开发环境已成为当今的好习惯。
这是Cloc实用程序的输出,显示SpeedCrunch与其他计算器的比较:
其他项目的错误评论:
使用
PVS-Studio静态分析仪进行分析。 这是用于软件质量控制以及错误和潜在漏洞检测的解决方案包。 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,但在下一次迭代时将设置为false。
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。因此,在下一个条件语句中,其值肯定不同于零,这是分析器警告的内容。
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指针在检查之前被取消引用。 看来这里有些错误。 由于取消引用之前有许多条件,因此该bug不会经常出现,但这样做时会产生巨大的影响。
被零除
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并在您自己的“计算器”上进行尝试。 :-)