Temukan bug di LLVM 8 menggunakan penganalisa PVS-Studio

PVS-Studio dan LLVM 8.0.0

Lebih dari dua tahun telah berlalu sejak verifikasi terakhir dari kode proyek LLVM menggunakan penganalisa PVS-Studio kami. Mari kita pastikan bahwa penganalisa PVS-Studio masih merupakan alat terkemuka untuk mendeteksi kesalahan dan kerentanan potensial. Untuk melakukan ini, periksa dan temukan kesalahan baru dalam rilis LLVM 8.0.0.

Artikel yang akan ditulis


Sejujurnya, saya tidak ingin menulis artikel ini. Tidak menarik untuk menulis tentang proyek yang telah kami uji berulang kali ( 1 , 2 , 3 ). Lebih baik menulis tentang sesuatu yang baru, tetapi saya tidak punya pilihan.

Setiap kali versi baru LLVM dirilis atau Clang Static Analyzer diperbarui, pertanyaan-pertanyaan berikut muncul di surat kami:

Lihat, versi baru Clang Static Analyzer telah belajar menemukan bug baru! Menurut saya relevansi penggunaan PVS-Studio menurun. Dentang menemukan lebih banyak kesalahan dari sebelumnya dan mengejar kemampuan PVS-Studio. Apa yang Anda pikirkan tentang ini?

Untuk ini, saya selalu ingin menjawab sesuatu dalam roh:

Kami juga tidak duduk diam! Kami telah secara signifikan meningkatkan kemampuan penganalisa PVS-Studio. Jadi jangan khawatir, kami terus memimpin, seperti sebelumnya.

Sayangnya, ini jawaban yang buruk. Tidak ada bukti di dalamnya. Dan itulah sebabnya saya menulis artikel ini sekarang. Jadi, proyek LLVM sekali lagi telah diuji dan berbagai kesalahan telah ditemukan di dalamnya. Yang tampaknya menarik bagi saya, sekarang saya akan tunjukkan. Kesalahan ini tidak dapat ditemukan oleh Clang Static Analyzer (atau sangat tidak nyaman untuk melakukannya). Dan kita bisa. Dan saya menemukan dan menulis semua kesalahan ini dalam satu malam.

Tetapi penulisan artikel itu berlangsung selama beberapa minggu. Saya tidak bisa memaksakan diri untuk mengatur semua ini dalam bentuk teks :).

Ngomong-ngomong, jika Anda tertarik pada teknologi apa yang digunakan dalam alat analisa PVS-Studio untuk mendeteksi kesalahan dan kerentanan potensial, maka saya sarankan agar Anda membiasakan diri dengan catatan ini.

Diagnostik baru dan lama


Seperti yang sudah dicatat, sekitar dua tahun lalu, proyek LLVM sekali lagi diverifikasi, dan kesalahan yang ditemukan diperbaiki. Sekarang di artikel ini sebagian kesalahan baru akan disajikan. Mengapa bug baru ditemukan? Ada 3 alasan untuk ini:

  1. Proyek LLVM berkembang, kode lama berubah di dalamnya, dan yang baru muncul. Secara alami, ada kesalahan baru dalam kode yang dimodifikasi dan ditulis. Ini menunjukkan dengan baik bahwa analisis statis harus diterapkan secara teratur, dan bukan dari kasus ke kasus. Artikel kami menunjukkan kemampuan alat analisa PVS-Studio dengan baik, tetapi ini tidak ada hubungannya dengan meningkatkan kualitas kode dan mengurangi biaya memperbaiki kesalahan. Gunakan penganalisa kode statis secara teratur!
  2. Kami sedang menyelesaikan dan meningkatkan diagnostik yang ada. Oleh karena itu, penganalisa dapat mendeteksi kesalahan yang tidak diperhatikan selama pemeriksaan sebelumnya.
  3. PVS-Studio memperkenalkan diagnostik baru, yang tidak 2 tahun yang lalu. Saya memutuskan untuk memisahkan mereka menjadi bagian yang terpisah untuk menunjukkan dengan jelas perkembangan PVS-Studio.

Cacat diidentifikasi oleh diagnostik yang ada 2 tahun yang lalu


Fragmen N1: Salin-Tempel

static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { if (Name == "addcarryx.u32" || // Added in 8.0 .... Name == "avx512.mask.cvtps2pd.128" || // Added in 7.0 Name == "avx512.mask.cvtps2pd.256" || // Added in 7.0 Name == "avx512.cvtusi2sd" || // Added in 7.0 Name.startswith("avx512.mask.permvar.") || // Added in 7.0 // <= Name.startswith("avx512.mask.permvar.") || // Added in 7.0 // <= Name == "sse2.pmulu.dq" || // Added in 7.0 Name == "sse41.pmuldq" || // Added in 7.0 Name == "avx2.pmulu.dq" || // Added in 7.0 .... } 

Peringatan PVS-Studio: V501 [CWE-570] Ada sub-ekspresi identik 'Name.startswith ("avx512.mask.permvar.")' Di sebelah kiri dan di sebelah kanan '||' operator. AutoUpgrade.cpp 73

Diperiksa ulang bahwa namanya dimulai dengan substring “avx512.mask.permvar.”. Pada tes kedua, mereka jelas ingin menulis sesuatu yang lain, tetapi lupa untuk memperbaiki teks yang disalin.

Fragmen N2: Typo

 enum CXNameRefFlags { CXNameRange_WantQualifier = 0x1, CXNameRange_WantTemplateArgs = 0x2, CXNameRange_WantSinglePiece = 0x4 }; void AnnotateTokensWorker::HandlePostPonedChildCursor( CXCursor Cursor, unsigned StartTokenIndex) { const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier; .... } 

Peringatan PVS-Studio: V501 Ada sub-ekspresi identik 'CXNameRange_WantQualifier' di kiri dan di kanan '|' operator. CIndex.cpp 7245

Karena kesalahan ketik, CXNameRange_WantQualifier konstanta yang sama digunakan dua kali .

Cuplikan N3: Kebingungan tentang Prioritas Operator

 int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) { .... if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0) return 0; .... } 

Peringatan PVS-Studio: V502 [CWE-783] Mungkin Operator '?:' Bekerja dengan cara yang berbeda dari yang diharapkan. Operator '?:' Memiliki prioritas lebih rendah daripada operator '=='. PPCTargetTransformInfo.cpp 404

Menurut pendapat saya, ini adalah kesalahan yang sangat indah. Ya, saya tahu saya punya ide aneh tentang kecantikan :).

Sekarang, sesuai dengan prioritas operator , ekspresi dihitung sebagai berikut:

 (ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0 

Dari sudut pandang praktis, kondisi seperti itu tidak masuk akal, karena dapat direduksi menjadi:

 (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian()) 

Ini adalah kesalahan yang jelas. Kemungkinan besar, 0/1 ingin membandingkan dengan variabel Indeks . Untuk memperbaiki kode, tambahkan tanda kurung di sekitar operator ternary:

 if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0)) 

Omong-omong, operator ternary sangat berbahaya dan memicu kesalahan logis. Berhati-hatilah dengan itu dan jangan serakah untuk menempatkan tanda kurung. Saya membahas topik ini secara lebih rinci di sini, di bab “Takut pada operator?: Dan lampirkan dalam tanda kurung”.

Fragmen N4, N5: Null pointer

 Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { .... TypedInit *LHS = dyn_cast<TypedInit>(Result); .... LHS = dyn_cast<TypedInit>( UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()) ->Fold(CurRec)); if (!LHS) { Error(PasteLoc, Twine("can't cast '") + LHS->getAsString() + "' to string"); return nullptr; } .... } 

Peringatan PVS-Studio: V522 [CWE-476] Dereferencing dari null pointer 'LHS' mungkin terjadi. TGParser.cpp 2152

Jika pointer LHS adalah nol, peringatan harus dikeluarkan. Namun, alih-alih ini akan mengubah pointer nol ini: LHS-> getAsString () .

Ini adalah situasi yang sangat khas ketika kesalahan disembunyikan di penangan kesalahan, karena tidak ada yang menguji mereka. Analisis statis memeriksa semua kode yang dapat dijangkau, tidak peduli seberapa sering digunakan. Ini adalah contoh yang sangat baik tentang bagaimana analisis statis melengkapi teknik pengujian dan perlindungan kesalahan lainnya.

Kesalahan serupa yang memproses pointer RHS dibuat dalam kode di bawah ini: V522 [CWE-476] Dereferencing dari null pointer 'RHS' mungkin terjadi. TGParser.cpp 2186

Fragmen N6: Menggunakan kursor setelah bergerak

 static Expected<bool> ExtractBlocks(....) { .... std::unique_ptr<Module> ProgClone = CloneModule(BD.getProgram(), VMap); .... BD.setNewProgram(std::move(ProgClone)); // <= MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); // <= assert(NewF && "Function not found??"); MiscompiledFunctions.push_back(NewF); } .... } 

Peringatan PVS-Studio: V522 [CWE-476] Dereferencing dari penunjuk nol 'ProgClone' mungkin terjadi. Miscompilation.cpp 601

Pada awalnya, penunjuk pintar ProgClone berhenti memiliki objek:

 BD.setNewProgram(std::move(ProgClone)); 

Bahkan, sekarang ProgClone adalah pointer nol. Oleh karena itu, dereferencing dari null pointer harus terjadi tepat di bawah:

 Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); 

Tetapi, pada kenyataannya, ini tidak akan terjadi! Perhatikan bahwa loop tidak benar-benar berjalan.

Pada awalnya, wadah MiscompiledFunctions dihapus:

 MiscompiledFunctions.clear(); 

Selanjutnya, ukuran wadah ini digunakan dalam kondisi loop:

 for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { 

Sangat mudah untuk melihat bahwa loop tidak dimulai. Saya pikir ini juga kesalahan, dan kode harus ditulis berbeda.

Sepertinya kita bertemu dengan kesalahan yang sangat terkenal itu! Satu kesalahan menyamarkan yang lain :).

Fragmen N7: Menggunakan kursor setelah bergerak

 static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test, std::unique_ptr<Module> Safe) { outs() << " Optimizing functions being tested: "; std::unique_ptr<Module> Optimized = BD.runPassesOn(Test.get(), BD.getPassesToRun()); if (!Optimized) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setNewProgram(std::move(Test)); // <= BD.EmitProgressBitcode(*Test, "pass-error", false); // <= if (Error E = BD.debugOptimizerCrash()) return std::move(E); return false; } .... } 

Peringatan PVS-Studio: V522 [CWE-476] Dereferencing dari null pointer 'Test' mungkin terjadi. Miscompilation.cpp 709

Lagi-lagi situasi yang sama. Pada awalnya, isi objek dipindahkan, dan kemudian digunakan seolah-olah tidak ada yang terjadi. Saya semakin melihat situasi ini dalam kode program, setelah semantik gerakan muncul di C ++. Untuk ini saya suka bahasa C ++! Ada banyak cara baru untuk menembak kaki Anda sendiri. Alat analisa PVS-Studio akan selalu bekerja :).

Fragmen N8: Null Pointer

 void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { uint32_t TypeId = Symbol.getTypeId(); auto Type = Symbol.getSession().getSymbolById(TypeId); if (Type) Printer << "<unknown-type>"; else Type->dump(*this); } 

PVS-Studio Warning: V522 [CWE-476] Dereferencing dari null pointer 'Type' mungkin terjadi. PrettyFunctionDumper.cpp 233

Selain penangan kesalahan, fungsi untuk debugging cetakan biasanya tidak diuji. Di hadapan kita adalah kasus seperti itu. Fungsi sedang menunggu pengguna yang, alih-alih menyelesaikan masalahnya, akan dipaksa untuk memperbaikinya.

Dengan benar:

 if (Type) Type->dump(*this); else Printer << "<unknown-type>"; 

Fragmen N9: Null Pointer

 void SearchableTableEmitter::collectTableEntries( GenericTable &Table, const std::vector<Record *> &Items) { .... RecTy *Ty = resolveTypes(Field.RecType, TI->getType()); if (!Ty) // <= PrintFatalError(Twine("Field '") + Field.Name + "' of table '" + Table.Name + "' has incompatible type: " + Ty->getAsString() + " vs. " + // <= TI->getType()->getAsString()); .... } 

PVS-Studio Warning: V522 [CWE-476] Dereferencing dari null pointer 'Ty' mungkin terjadi. SearchableTableEmitter.cpp 614

Saya pikir, jadi semuanya jelas dan tidak memerlukan penjelasan.

Fragmen N10: Typo

 bool FormatTokenLexer::tryMergeCSharpNullConditionals() { .... auto &Identifier = *(Tokens.end() - 2); auto &Question = *(Tokens.end() - 1); .... Identifier->ColumnWidth += Question->ColumnWidth; Identifier->Type = Identifier->Type; // <= Tokens.erase(Tokens.end() - 1); return true; } 

PVS-Studio Warning: V570 Variabel 'Identifier-> Type' ditugaskan untuk dirinya sendiri. FormatTokenLexer.cpp 249

Tidak masuk akal untuk menetapkan variabel ke dirinya sendiri. Kemungkinan besar mereka ingin menulis:

 Identifier->Type = Question->Type; 

Fragmen N11: Istirahat yang mencurigakan
 void SystemZOperand::print(raw_ostream &OS) const { switch (Kind) { break; case KindToken: OS << "Token:" << getToken(); break; case KindReg: OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg()); break; .... } 

Peringatan PVS-Studio: V622 [CWE-478] Pertimbangkan untuk memeriksa pernyataan 'sakelar'. Mungkin saja operator 'case' pertama hilang. SystemZAsmParser.cpp 652

Pada awalnya ada pernyataan istirahat yang sangat mencurigakan. Apakah Anda lupa menulis sesuatu yang lain di sini?

Fragmen N12: Memeriksa pointer setelah dereferencing

 InlineCost AMDGPUInliner::getInlineCost(CallSite CS) { Function *Callee = CS.getCalledFunction(); Function *Caller = CS.getCaller(); TargetTransformInfo &TTI = TTIWP->getTTI(*Callee); if (!Callee || Callee->isDeclaration()) return llvm::InlineCost::getNever("undefined callee"); .... } 

Peringatan PVS-Studio: V595 [CWE-476] Pointer 'Callee' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 172, 174. AMDGPUInline.cpp 172

Pointer Callee di awal ditereferensi ketika fungsi getTTI dipanggil .

Dan kemudian ternyata pointer ini harus diperiksa untuk kesetaraan nullptr :

 if (!Callee || Callee->isDeclaration()) 

Tapi sudah terlambat ...

Fragment N13 - N ...: Memeriksa pointer setelah dereferencing

Situasi yang dibahas dalam cuplikan kode sebelumnya tidak unik. Dia ditemukan di sini:

 static Value *optimizeDoubleFP(CallInst *CI, IRBuilder<> &B, bool isBinary, bool isPrecise = false) { .... Function *CalleeFn = CI->getCalledFunction(); StringRef CalleeNm = CalleeFn->getName(); // <= AttributeList CalleeAt = CalleeFn->getAttributes(); if (CalleeFn && !CalleeFn->isIntrinsic()) { // <= .... } 

Peringatan PVS-Studio: V595 [CWE-476] Pointer 'CalleeFn' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 1079, 1081. SederhanakanLibCalls.cpp 1079

Dan di sini:

 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, LocalInstantiationScope *OuterMostScope) { .... NamedDecl *ND = dyn_cast<NamedDecl>(New); CXXRecordDecl *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); // <= CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(), ND && ND->isCXXInstanceMember()); // <= .... } 

Peringatan PVS-Studio: V595 [CWE-476] Pointer 'ND' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Dan di sini:

  • V595 [CWE-476] Pointer 'U' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 404, 407. DWARFFormValue.cpp 404
  • V595 [CWE-476] Pointer 'ND' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Dan kemudian menjadi tidak menarik bagi saya untuk mempelajari peringatan dengan nomor V595. Jadi saya tidak tahu apakah ada kesalahan serupa selain yang tercantum di sini. Kemungkinan besar ada.

Fragmen N17, N18: Pergeseran mencurigakan

 static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, uint64_t &Encoding) { .... unsigned Size = RegSize; .... uint64_t NImms = ~(Size-1) << 1; .... } 

Peringatan PVS-Studio: V629 [CWE-190] Pertimbangkan untuk memeriksa ekspresi '~ (Ukuran - 1) << 1'. Pergeseran bit dari nilai 32-bit dengan ekspansi selanjutnya ke tipe 64-bit. AArch64AddressingModes.h 260

Mungkin ini bukan kesalahan, dan kode berfungsi persis seperti yang dimaksudkan. Tapi ini jelas tempat yang sangat mencurigakan, dan perlu diperiksa.

Misalkan variabel Ukuran adalah 16, dan kemudian pembuat kode berencana untuk mendapatkan nilai dalam variabel NImms :

11111111111111111111111111111111111111111111111111111111111111100000000

Namun, pada kenyataannya, hasilnya adalah:

00000000000000000000000000000000000000111111111111111111111111111111000000

Faktanya adalah bahwa semua perhitungan terjadi menggunakan tipe unsigned 32-bit. Dan hanya kemudian, tipe unsigned 32-bit ini akan secara implisit diperluas ke uint64_t . Dalam hal ini, bit yang paling signifikan adalah nol.

Anda dapat memperbaiki situasi seperti ini:

 uint64_t NImms = ~static_cast<uint64_t>(Size-1) << 1; 

Situasi serupa: V629 [CWE-190] Pertimbangkan untuk memeriksa ekspresi 'Immr << 6'. Pergeseran bit dari nilai 32-bit dengan ekspansi selanjutnya ke tipe 64-bit. AArch64AddressingModes.h 269

Cuplikan N19: Kehilangan kata kunci lain ?

 void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) { .... if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) { // VOP2b (v_add_u32, v_sub_u32 ...) dpp use "vcc" token. // Skip it. continue; } if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) { // <= Op.addRegWithFPInputModsOperands(Inst, 2); } else if (Op.isDPPCtrl()) { Op.addImmOperands(Inst, 1); } else if (Op.isImm()) { // Handle optional arguments OptionalIdx[Op.getImmTy()] = I; } else { llvm_unreachable("Invalid operand type"); } .... } 

Peringatan PVS-Studio: V646 [CWE-670] Pertimbangkan untuk memeriksa logika aplikasi. Mungkin kata kunci 'lain' tidak ada. AMDGPUAsmParser.cpp 5655

Tidak ada kesalahan di sini. Karena kemudian blok pertama jika diakhiri dengan melanjutkan , tidak masalah apakah ada kata kunci lain atau tidak. Bagaimanapun, kode akan bekerja sama. Namun, kehilangan yang lain membuat kode lebih tidak jelas dan berbahaya. Jika di masa depan terus menghilang, maka kode akan mulai bekerja dengan cara yang sama sekali berbeda. Menurut pendapat saya, lebih baik menambahkan yang lain .

Fragment N20: Empat kesalahan ketik dari jenis yang sama

 LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const { std::string Result; if (isUndefined()) Result += "(undef) "; if (isWeakDefined()) Result += "(weak-def) "; if (isWeakReferenced()) Result += "(weak-ref) "; if (isThreadLocalValue()) Result += "(tlv) "; switch (Kind) { case SymbolKind::GlobalSymbol: Result + Name.str(); // <= break; case SymbolKind::ObjectiveCClass: Result + "(ObjC Class) " + Name.str(); // <= break; case SymbolKind::ObjectiveCClassEHType: Result + "(ObjC Class EH) " + Name.str(); // <= break; case SymbolKind::ObjectiveCInstanceVariable: Result + "(ObjC IVar) " + Name.str(); // <= break; } OS << Result; } 

Peringatan PVS-Studio:

  • V655 [CWE-480] Senar digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + Nama.str ()'. Symbol.cpp 32
  • V655 [CWE-480] Senar digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(Kelas ObjC)" + Name.str ()'. Symbol.cpp 35
  • V655 [CWE-480] Senar digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(ObjC Kelas EH)" + Name.str ()'. Symbol.cpp 38
  • V655 [CWE-480] Senar digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(ObjC IVar)" + Name.str ()'. Symbol.cpp 41

Secara kebetulan, operator + digunakan alih-alih operator + =. Hasilnya adalah desain yang tidak berarti.

Fragmen N21: Perilaku tidak terdefinisi

 static void getReqFeatures(std::map<StringRef, int> &FeaturesMap, const std::vector<Record *> &ReqFeatures) { for (auto &R : ReqFeatures) { StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); SmallVector<StringRef, 4> Ops; SplitString(AsmCondString, Ops, ","); assert(!Ops.empty() && "AssemblerCondString cannot be empty"); for (auto &Op : Ops) { assert(!Op.empty() && "Empty operator"); if (FeaturesMap.find(Op) == FeaturesMap.end()) FeaturesMap[Op] = FeaturesMap.size(); } } } 

Coba cari sendiri kode yang berbahaya. Dan ini adalah gambar untuk gangguan, agar tidak segera melihat jawabannya:

Hmmm ...


Peringatan PVS-Studio: V708 [CWE-758] Konstruksi berbahaya digunakan: 'FeaturesMap [Op] = FeaturesMap.size ()', di mana 'FeaturesMap' adalah dari kelas 'map'. Ini dapat menyebabkan perilaku yang tidak terdefinisi. RISCVCompressInstEmitter.cpp 490

Garis masalah:

 FeaturesMap[Op] = FeaturesMap.size(); 

Jika elemen Op tidak ditemukan, elemen baru dibuat di peta dan jumlah elemen di peta ini ditulis di sana. Hanya tidak diketahui apakah fungsi ukuran akan dipanggil sebelum atau setelah menambahkan elemen baru.

Fragmen N22-N24: Penugasan Kembali

 Error MachOObjectFile::checkSymbolTable() const { .... } else { MachO::nlist STE = getSymbolTableEntry(SymDRI); NType = STE.n_type; // <= NType = STE.n_type; // <= NSect = STE.n_sect; NDesc = STE.n_desc; NStrx = STE.n_strx; NValue = STE.n_value; } .... } 

PVS-Studio Warning: V519 [CWE-563] Variabel 'NType' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 1663, 1664. MachOObjectFile.cpp 1664

Saya pikir tidak ada kesalahan nyata di sini. Hanya mengulangi tugas yang tidak perlu. Tapi masih ada kesalahan.

Demikian pula:

  • V519 [CWE-563] Variabel 'B.NDesc' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Variabel diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 59, 61. coff2yaml.cpp 61

Fragmen N25-N27: Penugasan ulang lainnya

Sekarang pertimbangkan opsi penugasan yang sedikit berbeda.

 bool Vectorizer::vectorizeLoadChain( ArrayRef<Instruction *> Chain, SmallPtrSet<Instruction *, 16> *InstructionsProcessed) { .... unsigned Alignment = getAlignment(L0); .... unsigned NewAlign = getOrEnforceKnownAlignment(L0->getPointerOperand(), StackAdjustedAlignment, DL, L0, nullptr, &DT); if (NewAlign != 0) Alignment = NewAlign; Alignment = NewAlign; .... } 

PVS-Studio Warning: V519 [CWE-563] Variabel 'Alignment' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 1158, 1160. LoadStoreVectorizer.cpp 1160

Ini adalah kode yang sangat aneh yang tampaknya mengandung kesalahan logis. Pada awalnya, variabel Alignment diberi nilai tergantung pada kondisinya. Dan kemudian penugasan terjadi lagi, tetapi sekarang tanpa verifikasi.

Situasi serupa dapat dilihat di sini:

  • V519 [CWE-563] Variabel 'Efek' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Variabel 'ExpectNoDerefChunk' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 4970, 4973. SemaType.cpp 4973

Fragmen N28: Selalu kondisi yang benar

 static int readPrefixes(struct InternalInstruction* insn) { .... uint8_t byte = 0; uint8_t nextByte; .... if (byte == 0xf3 && (nextByte == 0x88 || nextByte == 0x89 || nextByte == 0xc6 || nextByte == 0xc7)) { insn->xAcquireRelease = true; if (nextByte != 0x90) // PAUSE instruction support // <= break; } .... } 

Peringatan PVS-Studio: V547 [CWE-571] Ekspresi 'nextByte! = 0x90' selalu benar. X86DisassemblerDecoder.cpp 379

Verifikasi tidak masuk akal. Variabel nextByte selalu tidak sama dengan 0x90 , yang mengikuti dari pemeriksaan sebelumnya. Ini semacam kesalahan logis.

Fragment N29 - N ...: Selalu benar / kondisi salah

Penganalisa memberikan banyak peringatan bahwa seluruh kondisi ( V547 ) atau bagian dari itu ( V560 ) selalu benar atau salah. Seringkali ini bukan kesalahan nyata, tetapi hanya kode yang tidak akurat, hasil dari penyebaran makro dan sejenisnya. Namun demikian, masuk akal untuk melihat semua peringatan ini, karena dari waktu ke waktu ada kesalahan logis yang nyata. Misalnya, kode ini mencurigakan:

 static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success; if (RegNo > 13) return MCDisassembler::Fail; if ((RegNo & 1) || RegNo == 0xe) S = MCDisassembler::SoftFail; .... } 

Peringatan PVS-Studio: V560 [CWE-570] Bagian dari ekspresi kondisional selalu salah: RegNo == 0xe. ARMDisassembler.cpp 939

Konstanta 0xE adalah nilai 14 dalam sistem desimal. Memeriksa RegNo == 0xe tidak masuk akal, karena jika RegNo> 13 , maka fungsi akan menyelesaikan eksekusi.

Ada banyak peringatan lain dengan pengidentifikasi V547 dan V560, tetapi, seperti dalam kasus V595 , saya tidak tertarik mempelajari peringatan ini. Sudah jelas bahwa saya punya cukup bahan untuk menulis artikel :). Oleh karena itu, tidak diketahui berapa banyak kesalahan jenis ini dapat dideteksi dalam LLVM menggunakan PVS-Studio.

Saya akan memberikan contoh mengapa membosankan untuk mempelajari respons ini. Penganalisa benar dalam mengeluarkan peringatan untuk kode berikut. Tapi ini bukan kesalahan.

 bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, tok::TokenKind ClosingBraceKind) { bool HasError = false; .... HasError = true; if (!ContinueOnSemicolons) return !HasError; .... } 

Peringatan PVS-Studio: V547 [CWE-570] Ekspresi '! HasError' selalu salah. UnwrappedLineParser.cpp 1635

Fragmen N30: ​​Pengembalian yang mencurigakan

 static bool isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) { for (MachineRegisterInfo::def_instr_iterator It = MRI.def_instr_begin(Reg), E = MRI.def_instr_end(); It != E; ++It) { return (*It).isImplicitDef(); } .... } 

Peringatan PVS-Studio: V612 [CWE-670] 'pengembalian' tanpa syarat dalam satu lingkaran. R600OptimizeVectorRegisters.cpp 63

Ini adalah kesalahan atau trik khusus yang dimaksudkan untuk menjelaskan sesuatu kepada programmer yang membaca kode. Desain ini tidak menjelaskan apa pun kepada saya dan terlihat sangat mencurigakan. Lebih baik tidak menulis seperti itu :).

Apakah kamu lelah? Lalu saatnya membuat teh atau kopi.

Kopi


Cacat terdeteksi oleh diagnostik baru


Saya pikir 30 pemicu diagnostik lama sudah cukup. Sekarang mari kita lihat apa yang menarik dapat ditemukan dengan diagnostik baru yang muncul di analisa setelah pemeriksaan sebelumnya . Secara total, 66 diagnostik tujuan umum ditambahkan ke penganalisa C ++ selama waktu ini.

Fragmen N31: Kode tidak dapat dijangkau

 Error CtorDtorRunner::run() { .... if (auto CtorDtorMap = ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names), NoDependenciesToRegister, true)) { .... return Error::success(); } else return CtorDtorMap.takeError(); CtorDtorsByPriority.clear(); return Error::success(); } 

Peringatan PVS-Studio: V779 [CWE-561] Kode tidak dapat dideteksi terdeteksi. Mungkin saja ada kesalahan. ExecutionUtils.cpp 146

Seperti yang Anda lihat, kedua cabang pernyataan if diakhiri dengan panggilan ke pernyataan pengembalian . Dengan demikian, wadah CtorDtorsByPriority tidak akan pernah dikosongkan .

Cuplikan N32: Kode Tidak Terjangkau

 bool LLParser::ParseSummaryEntry() { .... switch (Lex.getKind()) { case lltok::kw_gv: return ParseGVEntry(SummaryID); case lltok::kw_module: return ParseModuleEntry(SummaryID); case lltok::kw_typeid: return ParseTypeIdEntry(SummaryID); // <= break; // <= default: return Error(Lex.getLoc(), "unexpected summary kind"); } Lex.setIgnoreColonInIdentifiers(false); // <= return false; } 

Peringatan PVS-Studio: V779 [CWE-561] Kode tidak dapat dideteksi terdeteksi. Mungkin saja ada kesalahan. LLParser.cpp 835

Situasi yang menarik. Mari kita lihat awal tempat ini:

 return ParseTypeIdEntry(SummaryID); break; 

Sekilas, sepertinya tidak ada kesalahan. Tampaknya pernyataan break berlebihan di sini, dan Anda dapat menghapusnya. Namun, tidak semuanya begitu sederhana.

Penganalisa menghasilkan peringatan pada baris:

 Lex.setIgnoreColonInIdentifiers(false); return false; 

Memang, kode ini tidak dapat dijangkau. Semua case di akhir beralih dengan panggilan ke pernyataan kembali . Dan sekarang break kesepian tanpa tujuan tidak terlihat begitu berbahaya! Mungkin salah satu cabang harus diakhiri dengan istirahat , dan bukan dengan kembali ?

Fragmen N33: Kebetulan bit tinggi

 unsigned getStubAlignment() override { if (Arch == Triple::systemz) return 8; else return 1; } Expected<unsigned> RuntimeDyldImpl::emitSection(const ObjectFile &Obj, const SectionRef &Section, bool IsCode) { .... uint64_t DataSize = Section.getSize(); .... if (StubBufSize > 0) DataSize &= ~(getStubAlignment() - 1); .... } 

PVS-Studio Warning: V784 Ukuran bit mask kurang dari ukuran operan pertama. Ini akan menyebabkan hilangnya bit yang lebih tinggi. RuntimeDyld.cpp 815

Perhatikan bahwa fungsi getStubAlignment mengembalikan tipe yang tidak ditandatangani . Kami menghitung nilai ekspresi jika kami menganggap bahwa fungsi mengembalikan nilai 8:

~ (getStubAlignment () - 1)

~ (8u-1)

0xFFFFFFF8u

Sekarang perhatikan bahwa variabel DataSize memiliki tipe unsigned 64-bit. Ternyata selama operasi DataSize & 0xFFFFFFF88, ketiga puluh dua bit tingkat tinggi akan diatur ulang. Kemungkinan besar, ini bukan yang diinginkan oleh programmer. Saya menduga bahwa dia ingin menghitung: DataSize & 0xFFFFFFFFFFFFFFFFFFF8u.

Untuk memperbaiki kesalahan, Anda harus menulis seperti ini:

 DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1); 

Atau lebih:

 DataSize &= ~(getStubAlignment() - 1ULL); 

Fragmen N34: Gagal eksplisit yang gagal

 template <typename T> void scaleShuffleMask(int Scale, ArrayRef<T> Mask, SmallVectorImpl<T> &ScaledMask) { assert(0 < Scale && "Unexpected scaling factor"); int NumElts = Mask.size(); ScaledMask.assign(static_cast<size_t>(NumElts * Scale), -1); .... } 

Peringatan PVS-Studio: V1028 [CWE-190] Kemungkinan meluap. Pertimbangkan casting operan dari operator 'NumElts * Scale' ke tipe 'size_t', bukan hasilnya. X86ISelLowering.h 1577

Konversi tipe eksplisit digunakan untuk mencegah overflow ketika mengalikan variabel tipe int . Namun, casting eksplisit di sini tidak melindungi terhadap overflow.Pada awalnya, variabel akan dikalikan, dan hanya dengan demikian hasil penggandaan 32-bit akan diperluas ke tipe size_t .

Fragmen N35: Salin-Tempel yang gagal

 Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { .... if (!match(Op0, m_PosZeroFP()) && isKnownNeverNaN(Op0, &TLI)) { I.setOperand(0, ConstantFP::getNullValue(Op0->getType())); return &I; } if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) { I.setOperand(1, ConstantFP::getNullValue(Op0->getType())); // <= return &I; } .... } 

V778 [CWE-682] Dua fragmen kode serupa ditemukan. Mungkin, ini adalah kesalahan ketik dan variabel 'Op1' harus digunakan alih-alih 'Op0'. InstCombineCompares.cpp 5507 Diagnostik

baru yang menarik ini mengungkapkan situasi ketika sepotong kode disalin dan beberapa nama mulai berubah di dalamnya, tetapi tidak diperbaiki di satu tempat.

Perhatikan bahwa dalam perubahan blok kedua Op0 di OP1 . Tetapi di satu tempat mereka tidak memperbaikinya. Kemungkinan besar, seharusnya ditulis seperti ini:

 if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) { I.setOperand(1, ConstantFP::getNullValue(Op1->getType())); return &I; } 

Fragmen N36: Kebingungan dalam variabel

 struct Status { unsigned Mask; unsigned Mode; Status() : Mask(0), Mode(0){}; Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) { Mode &= Mask; }; .... }; 

PVS-Studio Warning: V1001 [CWE-563] Variabel 'Mode' ditugaskan tetapi tidak digunakan pada akhir fungsi. SIModeRegister.cpp 48

Sangat berbahaya untuk memberikan argumen fungsi dengan nama yang sama dengan anggota kelas. Sangat mudah bingung. Di hadapan kita adalah kasus seperti itu. Ungkapan ini tidak masuk akal:

 Mode &= Mask; 

Argumen fungsi berubah. Dan itu dia. Argumen ini tidak lagi digunakan. Kemungkinan besar, perlu menulis seperti ini:

 Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) { this->Mode &= Mask; }; 

Fragmen N37: Kebingungan dalam variabel

 class SectionBase { .... uint64_t Size = 0; .... }; class SymbolTableSection : public SectionBase { .... }; void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, uint64_t Size) { .... Sym.Value = Value; Sym.Visibility = Visibility; Sym.Size = Size; Sym.Index = Symbols.size(); Symbols.emplace_back(llvm::make_unique<Symbol>(Sym)); Size += this->EntrySize; } 

Peringatan PVS-Studio: V1001 [CWE-563] Variabel 'Ukuran' ditetapkan tetapi tidak digunakan pada akhir fungsi. Object.cpp 424

Situasinya mirip dengan yang sebelumnya. Itu harus ditulis:

 this->Size += this->EntrySize; 

Fragmen N38-N47: Pointer lupa untuk memeriksa.

Sebelumnya, kami memeriksa contoh pemicu diagnostik V595 . Esensinya adalah bahwa pointer dereferenced pada awalnya, dan hanya kemudian diperiksa. Diagnostik muda V1004 adalah kebalikan dari maknanya, tetapi juga mendeteksi banyak kesalahan. Ini mengidentifikasi situasi di mana pointer diperiksa di awal, dan kemudian lupa melakukannya. Pertimbangkan kasus-kasus seperti yang ditemukan di dalam LLVM.

 int getGEPCost(Type *PointeeType, const Value *Ptr, ArrayRef<const Value *> Operands) { .... if (Ptr != nullptr) { // <= assert(....); BaseGV = dyn_cast<GlobalValue>(Ptr->stripPointerCasts()); } bool HasBaseReg = (BaseGV == nullptr); auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType()); // <= .... } 

Peringatan PVS-Studio: V1004 [CWE-476] Pointer 'Ptr' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 729, 738. TargetTransformInfoImpl.h 738

Variabel Ptr dapat berupa nullptr , sebagaimana dibuktikan oleh centang:

 if (Ptr != nullptr) 

Namun, di bawah penunjuk ini dereferensi tanpa verifikasi sebelumnya:

 auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType()); 

Pertimbangkan kasus serupa lainnya.

 llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD, bool Stub) { .... auto *FD = dyn_cast<FunctionDecl>(GD.getDecl()); SmallVector<QualType, 16> ArgTypes; if (FD) // <= for (const ParmVarDecl *Parm : FD->parameters()) ArgTypes.push_back(Parm->getType()); CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv(); // <= .... } 

Peringatan PVS-Studio: V1004 [CWE-476] Pointer 'FD' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 3228, 3231. CGDebugInfo.cpp 3231

Perhatikan pointer FD . Saya yakin masalahnya jelas terlihat, dan tidak diperlukan penjelasan khusus.

Dan juga:

 static void computePolynomialFromPointer(Value &Ptr, Polynomial &Result, Value *&BasePtr, const DataLayout &DL) { PointerType *PtrTy = dyn_cast<PointerType>(Ptr.getType()); if (!PtrTy) { // <= Result = Polynomial(); BasePtr = nullptr; } unsigned PointerBits = DL.getIndexSizeInBits(PtrTy->getPointerAddressSpace()); // <= .... } 

Peringatan PVS-Studio: V1004 [CWE-476] Pointer 'PtrTy' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 960, 965. InterleavedLoadCombinePass.cpp 965

Bagaimana melindungi diri Anda dari kesalahan seperti itu? Berhati-hatilah pada Code-Review dan gunakan analisa statis PVS-Studio untuk secara teratur memeriksa kode Anda.

Tidak masuk akal untuk membawa fragmen kode lain dengan kesalahan jenis ini. Saya hanya akan meninggalkan daftar peringatan di artikel:

  • V1004 [CWE-476] Pointer 'Expr' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Pointer 'PI' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] The 'StatepointCall' pointer was used unsafely after it was verified against nullptr. Check lines: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] The 'RV' pointer was used unsafely after it was verified against nullptr. Check lines: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] The 'CalleeFn' pointer was used unsafely after it was verified against nullptr. Check lines: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] The 'TC' pointer was used unsafely after it was verified against nullptr. Check lines: 1819, 1824. Driver.cpp 1824

N48-N60: , ( )

 std::unique_ptr<IRMutator> createISelMutator() { .... std::vector<std::unique_ptr<IRMutationStrategy>> Strategies; Strategies.emplace_back( new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps())); .... } 

Peringatan PVS-Studio: V1023 [CWE-460] Pointer tanpa pemilik ditambahkan ke wadah 'Strategi' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-isel-fuzzer.cpp 58

Untuk menambahkan item ke akhir wadah seperti std :: vector <std :: unique_ptr <X>> Anda tidak dapat menulis xxx.push_back (X baru) , karena tidak ada konversi implisit dari X * ke std: : unique_ptr <X> .

Solusi umum adalah menulis xxx.emplace_back (X baru) , karena ia mengkompilasi: metode emplace_back membangun elemen langsung dari argumen dan karenanya dapat menggunakan konstruktor eksplisit.

Ini tidak aman. Jika vektor penuh, maka memori dialokasikan. Operasi realokasi memori mungkin gagal, menghasilkan pengecualian std :: bad_alloc dilemparkan . Dalam hal ini, penunjuk akan hilang, dan objek yang dibuat tidak akan pernah dihapus.

Solusi yang aman adalah membuat unique_ptr , yang akan memiliki pointer sebelum vektor mencoba mengalokasikan kembali memori:

 xxx.push_back(std::unique_ptr<X>(new X)) 

Dimulai dengan C ++ 14, Anda dapat menggunakan 'std :: make_unique':

 xxx.push_back(std::make_unique<X>()) 

Jenis cacat ini tidak penting untuk LLVM. Jika memori tidak dapat dialokasikan, maka kompiler hanya akan berhenti bekerja. Namun, untuk aplikasi dengan waktu aktif yang lama yang tidak dapat berakhir begitu saja jika alokasi memori gagal, ini bisa menjadi bug yang jahat.

Jadi, meskipun kode ini tidak menimbulkan bahaya praktis untuk LLVM, saya merasa berguna untuk berbicara tentang pola kesalahan ini dan bahwa penganalisa PVS-Studio belajar untuk mendeteksinya.

Peringatan lain dari jenis ini:

  • V1023 [CWE-460] Pointer tanpa pemilik ditambahkan ke wadah 'Lulus' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. PassManager.h 546
  • V1023 [CWE-460] A pointer without owner is added to the 'AAs' container by the 'emplace_back' method. A memory leak will occur in case of an exception. AliasAnalysis.h 324
  • V1023 [CWE-460] A pointer without owner is added to the 'Entries' container by the 'emplace_back' method. A memory leak will occur in case of an exception. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] A pointer without owner is added to the 'AllEdges' container by the 'emplace_back' method. A memory leak will occur in case of an exception. CFGMST.h 268
  • V1023 [CWE-460] A pointer without owner is added to the 'VMaps' container by the 'emplace_back' method. A memory leak will occur in case of an exception. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] A pointer without owner is added to the 'Records' container by the 'emplace_back' method. A memory leak will occur in case of an exception. FDRLogBuilder.h 30
  • V1023 [CWE-460] A pointer without owner is added to the 'PendingSubmodules' container by the 'emplace_back' method. A memory leak will occur in case of an exception. ModuleMap.cpp 810
  • V1023 [CWE-460] A pointer without owner is added to the 'Objects' container by the 'emplace_back' method. A memory leak will occur in case of an exception. DebugMap.cpp 88
  • V1023 [CWE-460] A pointer without owner is added to the 'Strategies' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 685
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 686
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 688
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 689
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 690
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 691
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 692
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 693
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 694
  • V1023 [CWE-460] A pointer without owner is added to the 'Operands' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] A pointer without owner is added to the 'Stash' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] A pointer without owner is added to the 'Matchers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 2702

Kesimpulan


Secara total, saya menulis 60 peringatan, setelah itu saya berhenti. Apakah ada cacat lain yang terdeteksi oleh analyzer PVS-Studio di LLVM? Ya ada. Namun, ketika saya menulis cuplikan kode untuk artikel itu, sudah larut malam, atau lebih tepatnya, bahkan malam, dan saya memutuskan sudah waktunya untuk mengakhiri.

Saya harap Anda tertarik, dan Anda ingin mencoba alat analisa PVS-Studio.

Anda dapat mengunduh penganalisa dan mendapatkan kunci percobaan di halaman ini .

Yang paling penting, gunakan analisis statis secara teratur. Pemeriksaan satu kali yang kami lakukan untuk mempopulerkan metodologi analisis statis dan PVS-Studio bukanlah skenario normal.

Semoga berhasil dalam meningkatkan kualitas dan keandalan kode!



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Andrey Karpov. Menemukan Bug di LLVM 8 dengan PVS-Studio .

Source: https://habr.com/ru/post/id450008/


All Articles