Studi tentang kode kalkulator berlanjut! Dalam ulasan ini, proyek SpeedCrunch akan ditinjau - yang paling populer kedua di antara kalkulator gratis.
Pendahuluan
SpeedCrunch adalah kalkulator ilmiah berbasis keyboard presisi dengan antarmuka pengguna yang cepat. Ini gratis, perangkat lunak sumber terbuka tersedia di Windows, Linux, dan macOS.
Kode sumber dihosting di
BitBucket . Saya tidak terlalu suka dokumentasi perakitan, yang, menurut pendapat saya, harus ditulis lebih terinci. Persyaratan menentukan "Qt 5.2 atau yang lebih baru", meskipun beberapa paket spesifik diperlukan, yang tidak mudah dipelajari dari log CMake. Ngomong-ngomong, sekarang praktik yang baik untuk menerapkan Dockerfile ke proyek untuk dengan cepat mengkonfigurasi lingkungan pengembang yang diinginkan.
Untuk perbandingan dengan kalkulator lain, saya membawa output dari utilitas Cloc:
Ulasan bug di proyek lain:
PVS-Studio digunakan sebagai alat analisis statis. Ini adalah serangkaian solusi untuk kontrol kualitas kode, mencari kesalahan dan kerentanan potensial. Bahasa yang didukung meliputi: C, C ++, C #, dan Java. Alat analisis dapat diluncurkan pada Windows, Linux dan macOS.
Logika aneh dalam satu lingkaran
V560 Bagian dari ekspresi kondisional selalu benar:! RuleFound. evaluator.cpp 1410
void Evaluator::compile(const Tokens& tokens) { .... while (!syntaxStack.hasError()) { bool ruleFound = false;
Perhatikan variabel
ruleFound . Pada setiap iterasi, disetel ke false. Tetapi jika Anda melihat tubuh seluruh siklus, maka dalam kondisi tertentu variabel ini disetel ke true, tetapi tidak akan diperhitungkan pada iterasi baru siklus. Kemungkinan besar, variabel
ruleFound perlu dideklarasikan sebelum loop.
Perbandingan yang mencurigakan
V560 Bagian dari ekspresi kondisional selalu benar: 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) {
Jika variabel
shouldStop benar , maka variabel
m_scrollDirection akan memiliki satu dari dua nilai: -1 atau 1. Oleh karena itu, dalam pernyataan kondisional berikut, nilai variabel
m_scrollDirection pasti tidak akan nol, yang diperingatkan oleh penganalisa.
V668 Tidak ada gunanya menguji pointer 'item' terhadap null, karena memori dialokasikan menggunakan operator 'baru'. Pengecualian akan dihasilkan jika terjadi kesalahan alokasi memori. 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); .... } .... }
Memori untuk objek bertipe
QTreeWidgetItem dialokasikan menggunakan operator baru. Ini berarti bahwa jika alokasi memori dinamis tidak memungkinkan, pengecualian
std :: bad_alloc () akan dibuang. Oleh karena itu, memeriksa penunjuk
item tidak perlu dan dapat dihapus.
Potensi NULL Dereference
V595 Pointer 'ioparams' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 969, 983. floatio.c 969
int cattokens(....) { .... if (printexp) { if (expbase < 2) expbase = ioparams->expbase;
Pointer
ioparams ditereferensi sebelum diperiksa validitasnya. Kemungkinan besar, kesalahan potensial merayap ke dalam kode. Karena dereferencing berada di bawah beberapa kondisi, masalah dapat memanifestasikan dirinya jarang, tetapi akurat.
Pembagian dengan nol
V609 Bagilah dengan nol. Kisaran penyebut [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;
Fungsi
lgbase memungkinkan nilai nol untuk dikembalikan, dimana divisi kemudian dilakukan. Berpotensi, apa pun selain nilai 2, 8, dan 16 dapat diteruskan ke fungsi.
Perilaku tidak terdefinisi
V610 Perilaku tidak terdefinisi. Periksa operator shift '<<'. Operan kiri '(~ 0)' negatif. floatlogic.c 64
static char _signextend( t_longint* longint) { unsigned mask; signed char sign; sign = _signof(longint); mask = (~0) << SIGNBIT;
Hasil inversi nol ditempatkan di
int jenis tanda, sehingga hasilnya akan menjadi angka negatif, yang kemudian dilakukan pergeseran. Menggeser angka negatif ke kiri adalah perilaku yang tidak terdefinisi.
Seluruh daftar tempat berbahaya:
- V610 Perilaku tidak terdefinisi. Periksa operator shift '<<'. Operan kiri '(- 1)' negatif. floatnum.c 289
- V610 Perilaku tidak terdefinisi. Periksa operator shift '<<'. Operan kiri '(- 1)' negatif. floatnum.c 325
- V610 Perilaku tidak terdefinisi. Periksa operator shift '<<'. Operan kiri '(- 1)' negatif. floatnum.c 344
- V610 Perilaku tidak terdefinisi. Periksa operator shift '<<'. Operan kiri '(- 1)' negatif. floatnum.c 351
Tag HTML Tidak Tertutup
V735 Mungkin HTML yang salah. Tag penutup "</body>" ditemukan, sedangkan tag "</div>" diharapkan. 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; }
Seperti yang sering terjadi dengan kode C / C ++, tidak ada yang jelas dari sumbernya, jadi mari kita beralih ke kode preprocessed untuk fragmen ini:

Analyzer mendeteksi tag div tidak tertutup. Ada banyak fragmen kode html dalam file ini dan sekarang harus diperiksa tambahan oleh pengembang.
Berikut adalah beberapa tempat mencurigakan yang ditemukan menggunakan PVS-Studio:
- V735 Mungkin HTML yang salah. Tag penutup "</td>" ditemukan, sedangkan tag "</sub>" diharapkan. book.cpp 344
- V735 Mungkin HTML yang salah. Tag penutup "</td>" ditemukan, sedangkan tag "</sub>" diharapkan. book.cpp 347
Operator penugasan
V794 Operator penugasan harus dilindungi dari kasus 'this == & other'. kuantitas.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; }
Disarankan untuk mempertimbangkan situasi ketika objek ditugaskan untuk dirinya sendiri dengan membandingkan pointer.
Dengan kata lain, dua baris kode berikut harus ditambahkan ke awal fungsi tubuh:
if (this == &other) return *this;
Pengingat
V601 Nilai 'salah' secara implisit dilemparkan ke tipe integer. cmath.cpp 318
int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false;
Terkadang dalam komentar untuk artikel kami, mereka menyarankan bahwa beberapa peringatan dikeluarkan pada kode yang tidak lengkap. Ya, itu terjadi, tetapi ketika itu benar-benar terjadi, itu langsung ditulis tentang hal itu.
Kesimpulan
Ulasan yang sudah tersedia dari tiga kalkulator: Windows Calculator, Qalculate! dan SpeedCrunch. Kami siap untuk terus meneliti kode kalkulator populer. Anda dapat menawarkan proyek untuk verifikasi, karena peringkat perangkat lunak tidak selalu mencerminkan gambaran nyata.
Periksa "Kalkulator" Anda dengan mengunduh
PVS-Studio dan mencoba proyek Anda :-)

Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Svyatoslav Razmyslov.
Mengikuti Jejak Kalkulator: SpeedCrunch