Menemukan bug di LLVM 8 menggunakan penganalisis PVS-Studio

Menemukan bug di LLVM 8 menggunakan penganalisis PVS-Studio
Lebih dari dua tahun telah berlalu sejak pemeriksaan kode terakhir proyek LLVM menggunakan penganalisis PVS-Studio kami. Mari pastikan bahwa penganalisis PVS-Studio masih menjadi alat terdepan untuk mengidentifikasi kesalahan dan potensi kerentanan. Untuk melakukan ini, kami akan memeriksa dan menemukan kesalahan baru di rilis LLVM 8.0.0.

Artikel yang akan ditulis

Sejujurnya, saya tidak ingin menulis artikel ini. Tidak menarik untuk menulis tentang proyek yang sudah kita periksa beberapa kali (1, 2, 3). Lebih baik menulis tentang sesuatu yang baru, tapi saya tidak punya pilihan.

Setiap kali versi baru LLVM dirilis atau diperbarui Penganalisis Statis Dentang, kami menerima pertanyaan jenis berikut di email kami:

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

Untuk ini saya selalu ingin menjawab sesuatu seperti:

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

Sayangnya, ini adalah jawaban yang buruk. Tidak ada bukti di dalamnya. Dan itulah mengapa saya menulis artikel ini sekarang. Jadi, proyek LLVM sekali lagi diperiksa dan ditemukan berbagai kesalahan di dalamnya. Sekarang saya akan mendemonstrasikan hal-hal yang menurut saya menarik. Clang Static Analyzer tidak dapat menemukan kesalahan ini (atau sangat merepotkan untuk melakukannya dengan bantuannya). Tapi kita bisa. Terlebih lagi, saya menemukan dan menuliskan semua kesalahan ini dalam satu malam.

Namun penulisan artikel itu memakan waktu beberapa minggu. Saya tidak sanggup untuk menuliskan semua ini ke dalam teks :).

Omong-omong, jika Anda tertarik dengan teknologi apa yang digunakan dalam penganalisis PVS-Studio untuk mengidentifikasi kesalahan dan potensi kerentanan, saya sarankan untuk membiasakan diri dengan ini catatan.

Diagnostik baru dan lama

Seperti telah disebutkan, sekitar dua tahun yang lalu proyek LLVM diperiksa kembali dan kesalahan yang ditemukan telah diperbaiki. Sekarang artikel ini akan menyajikan kumpulan kesalahan baru. Mengapa bug baru ditemukan? Ada 3 alasan untuk ini:

  1. Proyek LLVM terus berkembang, mengubah kode lama dan menambahkan kode baru. Tentu saja, ada kesalahan baru dalam kode yang dimodifikasi dan ditulis. Hal ini jelas menunjukkan bahwa analisis statis harus digunakan secara teratur, dan tidak sesekali. Artikel kami menunjukkan dengan baik kemampuan penganalisis PVS-Studio, tetapi ini tidak ada hubungannya dengan peningkatan kualitas kode dan mengurangi biaya perbaikan kesalahan. Gunakan penganalisis kode statis secara teratur!
  2. Kami sedang menyelesaikan dan meningkatkan diagnostik yang ada. Oleh karena itu, penganalisis dapat mengidentifikasi kesalahan yang tidak diketahuinya selama pemindaian sebelumnya.
  3. Diagnostik baru telah muncul di PVS-Studio yang tidak ada 2 tahun lalu. Saya memutuskan untuk menyorotinya di bagian terpisah untuk menunjukkan dengan jelas perkembangan PVS-Studio.

Cacat diidentifikasi dengan diagnostik yang ada 2 tahun 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 kiri dan kanan '||' operator. Peningkatan Otomatis.cpp 73

Diperiksa ulang apakah nama dimulai dengan substring "avx512.mask.permvar.". Pada pemeriksaan kedua, mereka jelas ingin menulis sesuatu yang lain, tetapi lupa mengoreksi teks yang disalin.

Fragmen N2: Salah ketik

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 'CXNameRange_WantQualifier' yang identik di kiri dan kanan '|' operator. CIndex.cpp 7245

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

Fragmen N3: Kebingungan dengan 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 dibandingkan operator '=='. PPCTargetTransformInfo.cpp 404

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

Sekarang, menurut prioritas operator, ekspresi dievaluasi sebagai berikut:

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

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

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

Ini jelas merupakan kesalahan. Kemungkinan besar, mereka ingin membandingkan 0/1 dengan suatu variabel Indeks. Untuk memperbaiki kode, Anda perlu menambahkan 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 logika. Berhati-hatilah dengan itu dan jangan serakah dengan tanda kurung. Saya melihat topik ini lebih detail di sini, pada bab β€œWaspadalah terhadap ?: Operator dan Lampirkan dalam Tanda Kurung”.

Fragmen N4, N5: Penunjuk nol

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] Dereferensi penunjuk nol 'LHS' mungkin terjadi. TGParser.cpp 2152

Jika penunjuk LHS adalah null, peringatan harus dikeluarkan. Namun, sebaliknya, penunjuk nol yang sama ini akan direferensikan: LHS->getAsString().

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

Kesalahan penanganan penunjuk serupa RHS diperbolehkan dalam kode di bawah ini: V522 [CWE-476] Dereferensi penunjuk nol 'RHS' mungkin terjadi. TGParser.cpp 2186

Fragmen N6: Menggunakan penunjuk setelah berpindah

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] Dereferensi penunjuk nol 'ProgClone' mungkin terjadi. Kesalahan kompilasi.cpp 601

Pada awalnya penunjuk cerdas Klon Prog berhenti memiliki objek:

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

Faktanya, sekarang Klon Prog adalah penunjuk nol. Oleh karena itu, dereferensi penunjuk nol harus terjadi tepat di bawah:

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

Namun kenyataannya, hal ini tidak akan terjadi! Perhatikan bahwa perulangan tidak benar-benar dijalankan.

Di awal wadah Fungsi yang Salah Dikompilasi dibersihkan:

MiscompiledFunctions.clear();

Selanjutnya, ukuran container ini digunakan dalam kondisi loop:

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

Sangat mudah untuk melihat bahwa perulangan tidak dimulai. Saya pikir ini juga merupakan bug dan kodenya harus ditulis secara berbeda.

Tampaknya kita telah menemukan kesamaan kesalahan yang terkenal itu! Satu kesalahan menutupi kesalahan lainnya :).

Fragmen N7: Menggunakan penunjuk setelah berpindah

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] Dereferensi penunjuk nol 'Tes' mungkin terjadi. Kesalahan kompilasi.cpp 709

Situasi yang sama lagi. Mula-mula isi benda tersebut dipindahkan, kemudian digunakan seolah-olah tidak terjadi apa-apa. Saya melihat situasi ini semakin sering dalam kode program setelah semantik gerakan muncul di C++. Inilah mengapa saya menyukai bahasa C++! Ada semakin banyak cara baru untuk menembak mati diri Anda sendiri. Penganalisis PVS-Studio akan selalu berfungsi :).

Fragmen N8: Penunjuk nol

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);
}

Peringatan PVS-Studio: V522 [CWE-476] Dereferensi penunjuk nol 'Jenis' mungkin terjadi. PrettyFunctionDumper.cpp 233

Selain penangan kesalahan, fungsi cetakan debug biasanya tidak diuji. Kita punya kasus seperti itu di hadapan kita. Fungsi tersebut menunggu pengguna, yang alih-alih menyelesaikan masalahnya, malah terpaksa memperbaikinya.

Dengan benar:

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

Fragmen N9: Penunjuk nol

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());
   ....
}

Peringatan PVS-Studio: V522 [CWE-476] Dereferensi penunjuk nol 'Ty' mungkin terjadi. Dapat DicariTableEmitter.cpp 614

Saya pikir semuanya sudah jelas dan tidak memerlukan penjelasan.

Fragmen N10: Salah ketik

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;
}

Peringatan PVS-Studio: V570 Variabel 'Identifier->Type' ditetapkan ke dirinya sendiri. FormatTokenLexer.cpp 249

Tidak ada gunanya menugaskan 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 'saklar'. Mungkin saja operator 'kasus' pertama tidak ada. SystemZAsmParser.cpp 652

Ada operator yang sangat mencurigakan di awal istirahat. Apakah Anda lupa menulis sesuatu yang lain di sini?

Fragmen N12: Memeriksa pointer setelah dereferensi

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] Penunjuk 'Callee' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 172, 174. AMDGPUInline.cpp 172

penunjuk Callee di awal direferensikan pada saat fungsi dipanggil dapatkanTTI.

Dan ternyata penunjuk ini harus diperiksa kesetaraannya nullptr:

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

Tapi sudah terlambat…

Fragmen N13 - N...: Memeriksa pointer setelah dereferensi

Situasi yang dibahas dalam potongan kode sebelumnya tidaklah unik. Tampaknya 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] Penunjuk 'CalleeFn' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 1079, 1081. SimplifyLibCalls.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] Penunjuk 'ND' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Dan di sini:

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

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

Fragmen N17, N18: Pergeseran yang 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 perluasan selanjutnya ke tipe 64-bit. AArch64AddressingModes.h 260

Ini mungkin bukan bug dan kodenya berfungsi persis seperti yang diharapkan. Tapi ini jelas tempat yang sangat mencurigakan dan perlu diperiksa.

Katakanlah variabelnya Ukuran sama dengan 16, dan kemudian pembuat kode berencana untuk memasukkannya ke dalam variabel NImms nilai:

1111111111111111111111111111111111111111111111111111111111100000

Namun kenyataannya, hasilnya adalah:

0000000000000000000000000000000011111111111111111111111111100000

Faktanya adalah bahwa semua perhitungan dilakukan menggunakan tipe unsigned 32-bit. Dan hanya dengan begitu, tipe 32-bit yang tidak ditandatangani ini akan diperluas secara implisit uint64_t. Dalam hal ini, bit paling signifikan akan menjadi 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 perluasan selanjutnya ke tipe 64-bit. AArch64AddressingModes.h 269

Fragmen N19: Kata kunci tidak ada 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 saja kata kunci 'lainnya' tidak ada. AMDGPUAsmParser.cpp 5655

Tidak ada kesalahan di sini. Sejak itu-blok yang pertama if berakhir dengan terus, maka tidak masalah, ada kata kuncinya lain atau tidak. Apa pun caranya, kodenya akan bekerja sama. Masih terlewatkan lain membuat kode menjadi lebih tidak jelas dan berbahaya. Jika di masa depan terus menghilang, kode akan mulai bekerja dengan cara yang berbeda. Menurut saya lebih baik ditambahkan lain.

Fragmen N20: Empat kesalahan ketik dengan tipe 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] Senarnya digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + Nama.str()'. Simbol.cpp 32
  • V655 [CWE-480] Senarnya digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(Kelas ObjC)" + Nama.str()'. Simbol.cpp 35
  • V655 [CWE-480] Senarnya digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(ObjC Kelas EH) " + Nama.str()'. Simbol.cpp 38
  • V655 [CWE-480] Senarnya digabungkan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ekspresi 'Hasil + "(ObjC IVar)" + Nama.str()'. Simbol.cpp 41

Secara tidak sengaja, operator + digunakan sebagai pengganti operator +=. Hasilnya adalah desain yang tidak bermakna.

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 berbahayanya. Dan ini gambar untuk mengalihkan perhatian agar tidak langsung melihat jawabannya:

Menemukan bug di LLVM 8 menggunakan penganalisis PVS-Studio

Peringatan PVS-Studio: V708 [CWE-758] Konstruksi berbahaya digunakan: 'FeaturesMap[Op] = FeaturesMap.size()', dengan 'FeaturesMap' berasal dari kelas 'peta'. Hal ini dapat menyebabkan perilaku tidak terdefinisi. RISCVCompressInstEmitter.cpp 490

Garis masalah:

FeaturesMap[Op] = FeaturesMap.size();

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

Fragmen N22-N24: Penugasan berulang

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;
  }
  ....
}

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

Saya rasa tidak ada kesalahan nyata di sini. Hanya tugas berulang yang tidak perlu. Namun masih merupakan kesalahan besar.

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: Lebih banyak penugasan ulang

Sekarang mari kita lihat versi penugasan kembali 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;
  ....
}

Peringatan PVS-Studio: 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 logika. Pada awalnya, variabel Strategi suatu nilai diberikan tergantung pada kondisinya. Dan kemudian penugasan terjadi lagi, tetapi sekarang tanpa pemeriksaan apa pun.

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: Kondisi selalu 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

Memeriksa tidak masuk akal. Variabel byte berikutnya selalu tidak sama dengan nilainya 0x90, yang mengikuti dari pemeriksaan sebelumnya. Ini adalah semacam kesalahan logis.

Fragmen N29 - N...: Kondisi selalu benar/salah

Penganalisis mengeluarkan banyak peringatan bahwa seluruh kondisi (V547) atau bagiannya (V560) selalu benar atau salah. Seringkali ini bukan kesalahan nyata, tetapi hanya kode yang ceroboh, hasil dari ekspansi makro, dan sejenisnya. Namun, masuk akal untuk melihat semua peringatan ini, karena kesalahan logika yang sebenarnya memang terjadi dari waktu ke waktu. Misalnya, bagian 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 desimal. Penyelidikan Nomor Reg == 0xe tidak masuk akal karena jika Nomor Registrasi > 13, maka fungsi tersebut akan menyelesaikan eksekusinya.

Ada banyak peringatan lain dengan ID V547 dan V560, tetapi juga dengan V595, saya tidak tertarik mempelajari peringatan ini. Sudah jelas saya punya cukup bahan untuk menulis artikel :). Oleh karena itu, tidak diketahui berapa banyak kesalahan jenis ini yang dapat diidentifikasi di LLVM menggunakan PVS-Studio.

Saya akan memberi Anda contoh mengapa mempelajari pemicu ini membosankan. Penganalisis benar sekali dalam mengeluarkan peringatan untuk kode berikut. Tapi ini bukanlah sebuah 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. Membuka bungkusLineParser.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 putaran. R600OptimizeVectorRegisters.cpp 63

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

Lelah? Maka saatnya membuat teh atau kopi.

Menemukan bug di LLVM 8 menggunakan penganalisis PVS-Studio

Cacat diidentifikasi oleh diagnostik baru

Saya rasa 30 aktivasi diagnostik lama sudah cukup. Sekarang mari kita lihat hal menarik apa yang dapat ditemukan dengan diagnostik baru yang muncul di penganalisis setelahnya sebelumnya pemeriksaan. Selama waktu ini, total 66 diagnostik tujuan umum ditambahkan ke penganalisis C++.

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 dijangkau terdeteksi. Mungkin saja ada kesalahan. ExecutionUtils.cpp 146

Seperti yang Anda lihat, kedua cabang operator if diakhiri dengan panggilan ke operator kembali. Oleh karena itu, wadahnya CtorDtorsBerdasarkan Prioritas tidak akan pernah dibersihkan.

Fragmen N32: Kode tidak dapat dijangkau

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 dijangkau terdeteksi. Mungkin saja ada kesalahan. LLParser.cpp 835

Situasi yang menarik. Mari kita lihat tempat ini dulu:

return ParseTypeIdEntry(SummaryID);
break;

Sekilas sepertinya tidak ada kesalahan di sini. Sepertinya operatornya istirahat ada satu tambahan di sini, dan Anda cukup menghapusnya. Namun, tidak semuanya sesederhana itu.

Penganalisis mengeluarkan peringatan pada baris:

Lex.setIgnoreColonInIdentifiers(false);
return false;

Dan memang benar, kode ini tidak dapat dijangkau. Semua kasus di saklar diakhiri dengan panggilan dari operator kembali. Dan sekarang tidak masuk akal sendirian istirahat sepertinya tidak berbahaya! Mungkin salah satu cabangnya harus diakhiri dengan istirahattapi tidak menyala kembali?

Fragmen N33: Reset acak 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);
  ....
}

Peringatan PVS-Studio: V784 Ukuran bit mask lebih kecil dari ukuran operan pertama. Hal ini akan menyebabkan hilangnya bit yang lebih tinggi. RuntimeDyld.cpp 815

Harap dicatat bahwa fungsinya dapatkan StubAlignment tipe pengembalian unsigned. Mari kita hitung nilai ekspresi, dengan asumsi fungsi mengembalikan nilai 8:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFFF8u

Sekarang perhatikan bahwa variabelnya Ukuran Data memiliki tipe 64-bit yang tidak ditandatangani. Ternyata saat melakukan operasi DataSize & 0xFFFFFFF8u, ketiga puluh dua bit orde tinggi akan direset ke nol. Kemungkinan besar, ini bukan yang diinginkan programmer. Saya curiga dia ingin menghitung: DataSize & 0xFFFFFFFFFFFFFF8u.

Untuk memperbaiki kesalahan, Anda harus menulis ini:

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

Atau lebih:

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

Fragmen N34: Pemeran tipe eksplisit 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 untuk mentransmisikan operan operator 'NumElts * Scale' ke tipe 'size_t', bukan hasilnya. X86ISelMenurunkan.h 1577

Pengecoran tipe eksplisit digunakan untuk menghindari overflow saat mengalikan variabel tipe int. Namun, pengecoran tipe eksplisit di sini tidak melindungi terhadap luapan. Pertama, variabel-variabelnya akan dikalikan, dan baru setelah itu hasil perkalian 32-bitnya akan diperluas ke tipe ukuran_t.

Fragmen N35: Gagal Salin-Tempel

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 salah ketik dan variabel 'Op1' harus digunakan daripada 'Op0'. InstCombineCompares.cpp 5507

Diagnostik baru yang menarik ini mengidentifikasi situasi di mana sepotong kode telah disalin dan beberapa nama di dalamnya mulai diubah, tetapi di satu tempat mereka belum memperbaikinya.

Harap dicatat bahwa di blok kedua mereka berubah Op0 pada Op1. Namun 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 Variabel

struct Status {
  unsigned Mask;
  unsigned Mode;

  Status() : Mask(0), Mode(0){};

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

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

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

Mode &= Mask;

Argumen fungsi berubah. Itu saja. Argumen ini tidak lagi digunakan. Kemungkinan besar Anda seharusnya menulisnya seperti ini:

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

Fragmen N37: Kebingungan 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. Objek.cpp 424

Situasinya mirip dengan yang sebelumnya. Itu harus ditulis:

this->Size += this->EntrySize;

Fragmen N38-N47: Mereka lupa memeriksa indeks

Sebelumnya, kita melihat contoh pemicu diagnostik V595. Esensinya adalah bahwa penunjuknya direferensikan di awal, dan baru kemudian diperiksa. Diagnostik muda V1004 adalah kebalikannya, tetapi juga mengungkapkan banyak kesalahan. Ini mengidentifikasi situasi di mana penunjuk diperiksa di awal dan kemudian lupa melakukannya. Mari kita lihat kasus 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] Penunjuk 'Ptr' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 729, 738. TargetTransformInfoImpl.h 738

Variabel Ptr mungkin setara nullptr, dibuktikan dengan cek:

if (Ptr != nullptr)

Namun, di bawah penunjuk ini direferensikan tanpa pemeriksaan awal:

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

Mari kita 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] Penunjuk 'FD' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 3228, 3231. CGDebugInfo.cpp 3231

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

Dan selanjutnya:

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] Penunjuk 'PtrTy' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 960, 965. InterleavedLoadCombinePass.cpp 965

Bagaimana cara melindungi diri Anda dari kesalahan seperti itu? Lebih memperhatikan Tinjauan Kode dan gunakan penganalisa statis PVS-Studio untuk memeriksa kode Anda secara teratur.

Tidak ada gunanya mengutip potongan kode lain dengan kesalahan jenis ini. Saya hanya akan meninggalkan daftar peringatan di artikel:

  • V1004 [CWE-476] Penunjuk 'Expr' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Penunjuk 'PI' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Penunjuk 'StatepointCall' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Penunjuk 'RV' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Penunjuk 'CalleeFn' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Penunjuk 'TC' digunakan secara tidak aman setelah diverifikasi terhadap nullptr. Periksa baris: 1819, 1824. Driver.cpp 1824

Fragmen N48-N60: Tidak kritis, tetapi cacat (kemungkinan kebocoran memori)

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] Sebuah 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 elemen ke akhir wadah seperti std::vektor > kamu tidak bisa hanya menulis xxx.push_back(X baru), karena tidak ada konversi implisit dari X* Π² std::unique_ptr.

Solusi umum adalah menulis xxx.emplace_back(X baru)sejak dikompilasi: metode emplace_back membangun elemen langsung dari argumennya dan karenanya dapat menggunakan konstruktor eksplisit.

Itu tidak aman. Jika vektornya penuh, maka memori dialokasikan kembali. Operasi realokasi memori mungkin gagal, mengakibatkan pengecualian dilempar std::bad_alloc. Dalam hal ini, penunjuk akan hilang dan objek yang dibuat tidak akan pernah terhapus.

Solusi yang aman adalah dengan berkreasi unik_ptryang akan memiliki penunjuk sebelum vektor mencoba mengalokasikan kembali memori:

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

Sejak 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, kompiler akan berhenti begitu saja. Namun, untuk aplikasi dengan panjang waktu aktif, yang tidak bisa dihentikan begitu saja jika alokasi memori gagal, ini bisa menjadi bug yang sangat buruk.

Jadi, meskipun kode ini tidak menimbulkan ancaman praktis bagi LLVM, saya merasa berguna untuk membicarakan pola kesalahan ini dan penganalisis PVS-Studio telah belajar mengidentifikasinya.

Peringatan lain dari jenis ini:

  • V1023 [CWE-460] Pointer tanpa pemilik ditambahkan ke container 'Passes' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. PassManager.h 546
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'AAs' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. Analisis Alias.h 324
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Entri' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'AllEdges' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. CFGMST.h 268
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'VMaps' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Records' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. FDRLogBuilder.h 30
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'PendingSubmodules' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. ModuleMap.cpp 810
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Objek' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. DebugMap.cpp 88
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Strategi' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 685
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 686
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 688
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 689
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 690
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 691
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 692
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 693
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Pengubah' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. llvm-stress.cpp 694
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Operand' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Stash' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Sebuah pointer tanpa pemilik ditambahkan ke wadah 'Matchers' dengan metode 'emplace_back'. Kebocoran memori akan terjadi jika ada pengecualian. GlobalISelEmitter.cpp 2702

Kesimpulan

Saya mengeluarkan total 60 peringatan dan kemudian berhenti. Apakah ada cacat lain yang terdeteksi oleh penganalisis PVS-Studio di LLVM? Ya saya punya. Namun, ketika saya menulis potongan kode untuk artikel tersebut, saat itu sudah larut malam, atau bahkan malam hari, dan saya memutuskan sudah waktunya untuk mengakhirinya.

Saya harap ini menarik bagi Anda dan ingin mencoba penganalisa PVS-Studio.

Anda dapat mengunduh penganalisis dan mendapatkan kunci kapal penyapu ranjau di Halaman ini.

Yang terpenting, 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 Anda!

Menemukan bug di LLVM 8 menggunakan penganalisis PVS-Studio

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

Sumber: www.habr.com

Tambah komentar