تستمر دراسة رمز الآلة الحاسبة! في هذا الاستعراض ، سيتم مراجعة مشروع SpeedCrunch - وهو الثاني الأكثر شعبية بين الآلات الحاسبة المجانية.
مقدمة
SpeedCrunch هو آلة حاسبة علمية عالية الدقة يحركها لوحة المفاتيح مع واجهة مستخدم سريعة. هذا برنامج مجاني ومفتوح المصدر متاح على أنظمة Windows و Linux و macOS.
شفرة المصدر مستضافة على
BitBucket . لم يعجبني حقًا وثائق التجميع ، والتي ، في رأيي ، ينبغي كتابتها بمزيد من التفاصيل. تحدد المتطلبات "Qt 5.2 أو أحدث" ، على الرغم من الحاجة إلى عدة حزم محددة ، والتي لم تكن سهلة التعلم من سجل CMake. بالمناسبة ، من الممارسات الجيدة الآن تطبيق Dockerfile على مشروع لتهيئة بيئة المطور المطلوبة بسرعة.
للمقارنة مع الآلات الحاسبة الأخرى ، أحمل إخراج الأداة المساعدة Cloc:
مراجعات الأخطاء في مشاريع أخرى:
تم استخدام
PVS-Studio كأداة تحليل ثابتة. هذه مجموعة من الحلول لمراقبة جودة الكود والبحث عن الأخطاء ونقاط الضعف المحتملة. تتضمن اللغات المدعومة: C و C ++ و C # و Java. يمكن إطلاق المحلل على أنظمة التشغيل Windows و Linux و macOS.
منطق غريب في حلقة
V560 جزء من التعبير الشرطي صحيح دائمًا:! RuleFound. Evaluator.cpp 1410
void Evaluator::compile(const Tokens& tokens) { .... while (!syntaxStack.hasError()) { bool ruleFound = false;
لاحظ المتغير
ruleFound . في كل تكرار ، يتم ضبطه على "خطأ". لكن إذا نظرت إلى نص الدورة بأكملها ، فسيتم ضبط هذا المتغير في ظروف معينة على "صحيح" ، لكن لن يتم أخذ ذلك في الاعتبار عند التكرار الجديد للدورة. على الأرجح ،
هناك حاجة إلى إعلان متغير
ruleFound قبل الحلقة.
مقارنات مشبوهة
V560 جزء من التعبير الشرطي صحيح دائمًا: 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 صحيحًا ،
فسيكون للمتغير
m_scrollDirection إحدى قيمتين: -1 أو 1. لذلك ، في البيان الشرطي التالي ، لن تكون قيمة المتغير
m_scrollDirection صفراً ، وهو ما يحذر المحلل منه.
V668 لا يوجد أي معنى في اختبار مؤشر "العنصر" مقابل قيمة خالية ، حيث تم تخصيص الذاكرة باستخدام عامل التشغيل "الجديد". سيتم إنشاء الاستثناء في حالة خطأ تخصيص الذاكرة. 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); .... } .... }
يتم تخصيص ذاكرة لكائن من النوع
QTreeWidgetItem باستخدام عامل التشغيل الجديد. هذا يعني أنه إذا كان تخصيص الذاكرة الديناميكية غير ممكن ، فسيتم طرح استثناء
std :: bad_alloc () . لذلك ، يعد التحقق من مؤشر
العنصر غير ضروري ويمكن حذفه.
محتمل NULL Dereference
V595 تم استخدام مؤشر "ioparams" قبل أن يتم التحقق منه ضد nullptr. خطوط التحقق: 969 ، 983. floatio.c 969
int cattokens(....) { .... if (printexp) { if (expbase < 2) expbase = ioparams->expbase;
يتم
إلغاء تحديد مؤشر
ioparams قبل التحقق من صحته. على الأرجح ، تسلل خطأ محتمل إلى الكود. نظرًا لأن إلغاء التسجيل يخضع لشروط عديدة ، يمكن أن تظهر المشكلة بشكل نادر ، ولكن بدقة.
القسمة على صفر
V609 قسّم على صفر. نطاق المقام [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;
تسمح وظيفة
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 يجب حماية مشغل المهمة من حالة "هذا == & غيرها". 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; }
يوصى بالنظر في الموقف عند تعيين الكائن لنفسه من خلال مقارنة المؤشرات.
بمعنى آخر ، يجب إضافة سطرين التعليمات البرمجية التاليين إلى بداية نص الدالة:
if (this == &other) return *this;
تذكير
V601 القيمة "الخاطئة" يتم ضمنيًا ضمنا لنوع الأعداد الصحيحة. cmath.cpp 318
int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false;
في بعض الأحيان في التعليقات على مقالاتنا تشير إلى أن بعض التحذيرات تصدر على رمز غير مكتمل. نعم ، يحدث ذلك ، لكن عندما يكون الأمر حقًا ، يتم كتابته مباشرةً حول هذا الموضوع.
استنتاج
الاستعراضات المتاحة بالفعل من ثلاث آلات حاسبة: حاسبة ويندوز ، Qalculate! و SpeedCrunch. نحن على استعداد لمواصلة البحث في مدونة الآلات الحاسبة الشعبية. يمكنك تقديم مشاريع للتحقق منها ، لأن تصنيفات البرنامج لا تعكس دائمًا الصورة الحقيقية.
تحقق من "الحاسبة" عن طريق تنزيل
PVS-Studio ومحاولة مشروعك :-)

إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط الخاص بالترجمة: Svyatoslav Razmyslov.
التالية على خطى الآلات الحاسبة: SpeedCrunch