Mencari pepijat dalam LLVM 8 menggunakan penganalisis PVS-Studio

Mencari pepijat dalam LLVM 8 menggunakan penganalisis PVS-Studio
Lebih daripada dua tahun telah berlalu sejak semakan kod terakhir projek LLVM menggunakan penganalisis PVS-Studio kami. Mari pastikan bahawa penganalisis PVS-Studio masih menjadi alat utama untuk mengenal pasti ralat dan potensi kelemahan. Untuk melakukan ini, kami akan menyemak dan mencari ralat baharu dalam keluaran LLVM 8.0.0.

Artikel yang akan ditulis

Sejujurnya, saya tidak mahu menulis artikel ini. Tidak menarik untuk menulis tentang projek yang telah kami periksa beberapa kali (1, 2, 3). Adalah lebih baik untuk menulis tentang sesuatu yang baru, tetapi saya tidak mempunyai pilihan.

Setiap kali versi baharu LLVM dikeluarkan atau dikemas kini Penganalisis Statik Clang, kami menerima soalan jenis berikut dalam mel kami:

Lihat, versi baharu Penganalisis Statik Clang telah belajar mencari ralat baharu! Nampaknya kepada saya bahawa perkaitan menggunakan PVS-Studio semakin berkurangan. Clang menemui lebih banyak ralat berbanding sebelum ini dan mengejar keupayaan PVS-Studio. Apa pandangan anda tentang ini?

Untuk ini saya sentiasa ingin menjawab sesuatu seperti:

Kami juga tidak duduk diam! Kami telah meningkatkan dengan ketara keupayaan penganalisis PVS-Studio. Jadi jangan risau, kami terus memimpin seperti sebelum ini.

Malangnya, ini adalah jawapan yang tidak baik. Tiada bukti di dalamnya. Dan itulah sebabnya saya menulis artikel ini sekarang. Jadi, projek LLVM sekali lagi telah disemak dan pelbagai ralat telah ditemui di dalamnya. Saya kini akan menunjukkan perkara yang kelihatan menarik kepada saya. Penganalisis Statik Clang tidak dapat mencari ralat ini (atau sangat menyusahkan untuk berbuat demikian dengan bantuannya). Tetapi kita boleh. Lebih-lebih lagi, saya menemui dan menulis semua kesilapan ini dalam satu petang.

Tetapi menulis artikel itu mengambil masa beberapa minggu. Saya tidak dapat membawa diri saya untuk memasukkan semua ini ke dalam teks :).

Ngomong-ngomong, jika anda berminat dengan teknologi yang digunakan dalam penganalisis PVS-Studio untuk mengenal pasti ralat dan potensi kelemahan, maka saya cadangkan untuk membiasakan diri dengan ini catatan.

Diagnostik baru dan lama

Seperti yang telah dinyatakan, kira-kira dua tahun lalu projek LLVM telah disemak sekali lagi, dan ralat yang ditemui telah diperbetulkan. Kini artikel ini akan membentangkan kumpulan ralat baharu. Mengapakah pepijat baharu ditemui? Terdapat 3 sebab untuk ini:

  1. Projek LLVM sedang berkembang, menukar kod lama dan menambah kod baharu. Sememangnya, terdapat ralat baharu dalam kod yang diubah suai dan ditulis. Ini jelas menunjukkan bahawa analisis statik harus digunakan dengan kerap, dan bukan sekali-sekala. Artikel kami menunjukkan dengan baik keupayaan penganalisis PVS-Studio, tetapi ini tiada kaitan dengan meningkatkan kualiti kod dan mengurangkan kos membetulkan ralat. Gunakan penganalisis kod statik dengan kerap!
  2. Kami sedang memuktamadkan dan menambah baik diagnostik sedia ada. Oleh itu, penganalisis boleh mengenal pasti ralat yang tidak disedari semasa imbasan sebelumnya.
  3. Diagnostik baharu telah muncul dalam PVS-Studio yang tidak wujud 2 tahun lalu. Saya memutuskan untuk menyerlahkannya dalam bahagian berasingan untuk menunjukkan dengan jelas perkembangan PVS-Studio.

Kecacatan yang dikenal pasti oleh diagnostik yang wujud 2 tahun lalu

Serpihan N1: Salin-Tampal

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

Amaran PVS-Studio: V501 [CWE-570] Terdapat sub-ungkapan yang sama 'Name.startswith("avx512.mask.permvar.")' di sebelah kiri dan di sebelah kanan '||' pengendali. AutoUpgrade.cpp 73

Ia disemak dua kali bahawa nama itu bermula dengan subrentetan "avx512.mask.permvar.". Dalam semakan kedua, mereka jelas mahu menulis sesuatu yang lain, tetapi terlupa untuk membetulkan teks yang disalin.

Serpihan N2: Taip

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

Amaran PVS-Studio: V501 Terdapat sub-ungkapan yang sama 'CXNameRange_WantQualifier' di sebelah kiri dan di sebelah kanan '|' pengendali. CIindex.cpp 7245

Disebabkan kesilapan menaip, pemalar bernama yang sama digunakan dua kali CXNameRange_WantQualifier.

Fragmen N3: Kekeliruan dengan keutamaan operator

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

Amaran PVS-Studio: V502 [CWE-783] Mungkin pengendali '?:' berfungsi dengan cara yang berbeza daripada yang dijangkakan. Pengendali '?:' mempunyai keutamaan yang lebih rendah daripada pengendali '=='. PPCTargetTransformInfo.cpp 404

Pada pendapat saya, ini adalah kesilapan yang sangat indah. Ya, saya tahu saya mempunyai idea yang pelik tentang kecantikan :).

Sekarang, menurut keutamaan pengendali, ungkapan dinilai seperti berikut:

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

Dari sudut pandangan praktikal, keadaan sedemikian tidak masuk akal, kerana ia boleh dikurangkan kepada:

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

Ini adalah kesilapan yang jelas. Kemungkinan besar, mereka ingin membandingkan 0/1 dengan pembolehubah indeks. Untuk membetulkan kod anda perlu menambah kurungan di sekeliling pengendali ternary:

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

Dengan cara ini, pengendali ternary sangat berbahaya dan menimbulkan ralat logik. Berhati-hati dengannya dan jangan tamak dengan kurungan. Saya melihat topik ini dengan lebih terperinci di sini, dalam bab "Berhati-hati dengan ?: Operator dan Lampirkan Ia dalam Tanda Kurung."

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

Amaran PVS-Studio: V522 [CWE-476] Penyahrujukan penuding nol 'LHS' mungkin berlaku. TGParser.cpp 2152

Jika penunjuk LHS adalah batal, amaran harus dikeluarkan. Walau bagaimanapun, sebaliknya, penunjuk nol yang sama ini akan dinyahrujuk: LHS->getAsString().

Ini adalah situasi yang sangat biasa apabila ralat disembunyikan dalam pengendali ralat, kerana tiada siapa yang mengujinya. Penganalisis statik menyemak semua kod yang boleh dicapai, tidak kira berapa kerap ia digunakan. Ini adalah contoh yang sangat baik tentang cara analisis statik melengkapkan ujian lain dan teknik perlindungan ralat.

Ralat pengendalian penunjuk yang serupa RHS dibenarkan dalam kod di bawah: V522 [CWE-476] Penyahrujukan penuding nol 'RHS' mungkin berlaku. TGParser.cpp 2186

Serpihan N6: Menggunakan penunjuk selepas 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);
  }
  ....
}

Amaran PVS-Studio: V522 [CWE-476] Penyahrujukan penuding nol 'ProgClone' mungkin berlaku. Penyusunan salah.cpp 601

Pada mulanya penunjuk pintar ProgClone berhenti memiliki objek:

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

Malah, sekarang ProgClone ialah penunjuk nol. Oleh itu, penolakan penunjuk nol harus berlaku di bawah:

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

Tetapi, pada hakikatnya, ini tidak akan berlaku! Ambil perhatian bahawa gelung sebenarnya tidak dilaksanakan.

Pada permulaan bekas Fungsi yang salah susun dibersihkan:

MiscompiledFunctions.clear();

Seterusnya, saiz bekas ini digunakan dalam keadaan gelung:

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

Sangat mudah untuk melihat bahawa gelung tidak bermula. Saya fikir ini juga pepijat dan kod itu harus ditulis secara berbeza.

Nampaknya kita telah menemui pariti kesilapan yang terkenal itu! Satu kesilapan bertopengkan yang lain :).

Serpihan N7: Menggunakan penunjuk selepas 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;
  }
  ....
}

Amaran PVS-Studio: V522 [CWE-476] Penyahrujukan 'Ujian' penuding nol mungkin berlaku. Penyusunan salah.cpp 709

Keadaan yang sama lagi. Pada mulanya, kandungan objek digerakkan, dan kemudian ia digunakan seolah-olah tiada apa-apa yang berlaku. Saya melihat situasi ini lebih dan lebih kerap dalam kod program selepas semantik pergerakan muncul dalam C++. Inilah sebabnya saya suka bahasa C++! Terdapat lebih banyak cara baharu untuk menembak kaki anda sendiri. Penganalisis PVS-Studio akan sentiasa berfungsi :).

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

Amaran PVS-Studio: V522 [CWE-476] Penyahrujukan 'Jenis' penunjuk nol mungkin berlaku. PrettyFunctionDumper.cpp 233

Selain pengendali ralat, fungsi cetakan nyahpepijat biasanya tidak diuji. Kami mempunyai kes sedemikian di hadapan kami. Fungsi ini sedang menunggu pengguna, yang, bukannya menyelesaikan masalahnya, akan dipaksa untuk membetulkannya.

Betul:

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

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

Amaran PVS-Studio: V522 [CWE-476] Penyahrujukan penuding nol 'Ty' mungkin berlaku. SearchableTableEmitter.cpp 614

Saya rasa semuanya jelas dan tidak memerlukan penjelasan.

Serpihan N10: Taip

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

Amaran PVS-Studio: V570 Pembolehubah 'Pengecam->Jenis' diberikan kepada dirinya sendiri. FormatTokenLexer.cpp 249

Tidak ada gunanya menetapkan pembolehubah kepada dirinya sendiri. Kemungkinan besar mereka mahu menulis:

Identifier->Type = Question->Type;

Serpihan N11: Pemecahan 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;
  ....
}

Amaran PVS-Studio: V622 [CWE-478] Pertimbangkan untuk memeriksa pernyataan 'suis'. Ada kemungkinan bahawa operator 'kes' pertama hilang. SystemZAsmParser.cpp 652

Terdapat pengendali yang sangat mencurigakan pada mulanya memecahkan. Adakah anda terlupa untuk menulis sesuatu yang lain di sini?

Serpihan N12: Menyemak penunjuk selepas penyahrujukan

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

Amaran PVS-Studio: V595 [CWE-476] Penunjuk 'Callee' telah digunakan sebelum ia disahkan terhadap nullptr. Semak talian: 172, 174. AMDGPUInline.cpp 172

Penunjuk Callee pada permulaan dinyahrujuk pada masa fungsi dipanggil dapatkanTTI.

Dan kemudian ternyata penunjuk ini harus diperiksa untuk kesamaan nullptr:

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

Tetapi sudah terlambat…

Serpihan N13 - N...: Menyemak penunjuk selepas penyahrujukan

Situasi yang dibincangkan dalam serpihan kod sebelumnya bukanlah unik. Ia muncul 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()) {               // <=
  ....
}

Amaran PVS-Studio: V595 [CWE-476] Penunjuk 'CalleeFn' telah digunakan sebelum ia disahkan terhadap nullptr. Semak talian: 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());     // <=
  ....
}

Amaran PVS-Studio: V595 [CWE-476] Penunjuk 'ND' telah digunakan sebelum ia disahkan terhadap nullptr. Semak baris: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Dan di sini:

  • V595 [CWE-476] Penunjuk 'U' telah digunakan sebelum ia disahkan terhadap nullptr. Semak baris: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] Penunjuk 'ND' telah digunakan sebelum ia disahkan terhadap nullptr. Semak talian: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Dan kemudian saya menjadi tidak berminat untuk mengkaji amaran dengan nombor V595. Jadi saya tidak tahu sama ada terdapat lebih banyak ralat yang serupa selain yang disenaraikan di sini. Kemungkinan besar ada.

Serpihan N17, N18: Peralihan yang mencurigakan

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

Amaran PVS-Studio: V629 [CWE-190] Pertimbangkan untuk memeriksa ungkapan '~(Saiz - 1) << 1'. Peralihan bit nilai 32-bit dengan pengembangan seterusnya kepada jenis 64-bit. AArch64AddressingModes.h 260

Ia mungkin bukan pepijat dan kod itu berfungsi betul-betul seperti yang dimaksudkan. Tetapi ini jelas tempat yang sangat mencurigakan dan perlu diperiksa.

Katakan pembolehubah Saiz adalah sama dengan 16, dan kemudian pengarang kod merancang untuk mendapatkannya dalam pembolehubah NImms maksud:

1111111111111111111111111111111111111111111111111111111111100000

Walau bagaimanapun, pada hakikatnya hasilnya akan menjadi:

0000000000000000000000000000000011111111111111111111111111100000

Hakikatnya ialah semua pengiraan berlaku menggunakan jenis 32-bit unsigned. Dan hanya selepas itu, jenis 32-bit yang tidak ditandatangani ini akan dikembangkan secara tersirat kepada uint64_t. Dalam kes ini, bit yang paling ketara adalah sifar.

Anda boleh membetulkan keadaan seperti ini:

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

Situasi yang sama: V629 [CWE-190] Pertimbangkan untuk memeriksa ungkapan 'Immr << 6'. Peralihan bit nilai 32-bit dengan pengembangan seterusnya kepada jenis 64-bit. AArch64AddressingModes.h 269

Serpihan N19: Kata kunci tiada lagi?

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

Amaran PVS-Studio: V646 [CWE-670] Pertimbangkan untuk memeriksa logik aplikasi. Ada kemungkinan kata kunci 'lain' tiada. AMDGPUAsmParser.cpp 5655

Tiada kesilapan di sini. Sejak itu-blok yang pertama if berakhir dengan terus, maka tidak mengapa, ada kata kunci lagi atau tidak. Sama ada cara kod akan berfungsi sama. Masih terlepas lagi menjadikan kod lebih jelas dan berbahaya. Jika pada masa hadapan terus hilang, kod akan mula berfungsi dengan cara yang berbeza. Pada pendapat saya adalah lebih baik untuk menambah lagi.

Serpihan N20: Empat kesilapan taip daripada 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;
}

Amaran PVS-Studio:

  • V655 [CWE-480] Rentetan telah disatukan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ungkapan 'Result + Name.str()'. Simbol.cpp 32
  • V655 [CWE-480] Rentetan telah disatukan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ungkapan 'Result + "(ObjC Class)" + Name.str()'. Simbol.cpp 35
  • V655 [CWE-480] Rentetan telah disatukan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ungkapan 'Result + "(ObjC Class EH) " + Name.str()'. Simbol.cpp 38
  • V655 [CWE-480] Rentetan telah disatukan tetapi tidak digunakan. Pertimbangkan untuk memeriksa ungkapan 'Result + "(ObjC IVar)" + Name.str()'. Simbol.cpp 41

Secara tidak sengaja, operator + digunakan dan bukannya operator +=. Hasilnya adalah reka bentuk yang tidak mempunyai makna.

Fragmen N21: Tingkah laku tidak ditentukan

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

Cuba cari sendiri kod berbahaya itu. Dan ini adalah gambar untuk mengalih perhatian perhatian supaya tidak segera melihat jawapannya:

Mencari pepijat dalam LLVM 8 menggunakan penganalisis PVS-Studio

Amaran PVS-Studio: V708 [CWE-758] Pembinaan berbahaya digunakan: 'FeaturesMap[Op] = FeaturesMap.size()', dengan 'FeaturesMap' ialah kelas 'map'. Ini boleh membawa kepada tingkah laku yang tidak ditentukan. RISCVCompressInstEmitter.cpp 490

Garis masalah:

FeaturesMap[Op] = FeaturesMap.size();

Jika unsur Op tidak dijumpai, maka elemen baru dicipta dalam peta dan bilangan elemen dalam peta ini ditulis di sana. Ia tidak diketahui sama ada fungsi itu akan dipanggil saiz sebelum atau selepas menambah elemen baharu.

Serpihan N22-N24: Tugasan 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;
  }
  ....
}

Amaran PVS-Studio: V519 [CWE-563] Pembolehubah 'NType' diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak baris: 1663, 1664. MachOObjectFile.cpp 1664

Saya tidak fikir ada kesilapan sebenar di sini. Hanya tugasan berulang yang tidak perlu. Tetapi masih kesilapan.

Begitu juga:

  • V519 [CWE-563] Pembolehubah 'B.NDesc' diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak talian: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Pembolehubah diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak talian: 59, 61. coff2yaml.cpp 61

Serpihan N25-N27: Lebih banyak penugasan semula

Sekarang mari kita lihat versi penugasan semula yang sedikit berbeza.

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

Amaran PVS-Studio: V519 [CWE-563] Pembolehubah 'Penjajaran' diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak talian: 1158, 1160. LoadStoreVectorizer.cpp 1160

Ini adalah kod yang sangat pelik yang nampaknya mengandungi ralat logik. Pada mulanya, berubah-ubah Penjajaran nilai ditetapkan bergantung pada keadaan. Dan kemudian tugasan berlaku lagi, tetapi kini tanpa sebarang semakan.

Situasi yang sama boleh dilihat di sini:

  • V519 [CWE-563] Pembolehubah 'Kesan' diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak baris: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Pembolehubah 'ExpectNoDerefChunk' diberikan nilai dua kali berturut-turut. Mungkin ini satu kesilapan. Semak talian: 4970, 4973. SemaType.cpp 4973

Serpihan N28: Keadaan sentiasa 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;
  }
  ....
}

Amaran PVS-Studio: V547 [CWE-571] Ungkapan 'nextByte != 0x90' sentiasa benar. X86DisassemblerDecoder.cpp 379

Menyemak tidak masuk akal. Pembolehubah nextByte sentiasa tidak sama dengan nilai 0x90, yang mengikuti daripada semakan sebelumnya. Ini adalah sejenis ralat logik.

Serpihan N29 - N...: Keadaan sentiasa benar/salah

Penganalisis mengeluarkan banyak amaran bahawa keseluruhan keadaan (V547) atau sebahagian daripadanya (V560) sentiasa benar atau salah. Selalunya ini bukan ralat sebenar, tetapi hanya kod ceroboh, hasil pengembangan makro, dan seumpamanya. Walau bagaimanapun, adalah wajar untuk melihat semua amaran ini, kerana ralat logik yang tulen berlaku dari semasa ke semasa. Sebagai contoh, bahagian kod 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;
  ....
}

Amaran PVS-Studio: V560 [CWE-570] Sebahagian daripada ungkapan bersyarat sentiasa palsu: RegNo == 0xe. ARMDisassembler.cpp 939

Pemalar 0xE ialah nilai 14 dalam perpuluhan. Peperiksaan RegNo == 0xe tidak masuk akal kerana jika Nombor Reg > 13, maka fungsi akan menyelesaikan pelaksanaannya.

Terdapat banyak amaran lain dengan ID V547 dan V560, tetapi seperti dengannya V595, saya tidak berminat untuk mengkaji amaran ini. Sudah jelas bahawa saya mempunyai bahan yang mencukupi untuk menulis artikel :). Oleh itu, tidak diketahui berapa banyak ralat jenis ini boleh dikenal pasti dalam LLVM menggunakan PVS-Studio.

Saya akan memberi anda contoh mengapa mengkaji pencetus ini membosankan. Penganalisis benar-benar tepat dalam mengeluarkan amaran untuk kod berikut. Tetapi ini bukan satu kesilapan.

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

Amaran PVS-Studio: V547 [CWE-570] Ungkapan '!HasError' sentiasa palsu. UnwrappedLineParser.cpp 1635

Serpihan N30: ​​Pulangan 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();
  }
  ....
}

Amaran PVS-Studio: V612 [CWE-670] 'pulangan' tanpa syarat dalam gelung. R600OptimizeVectorRegisters.cpp 63

Ini sama ada ralat atau teknik khusus yang bertujuan untuk menerangkan sesuatu kepada pengaturcara yang membaca kod. Reka bentuk ini tidak menjelaskan apa-apa kepada saya dan kelihatan sangat mencurigakan. Lebih baik jangan tulis macam tu :).

Penat? Kemudian tiba masanya untuk membuat teh atau kopi.

Mencari pepijat dalam LLVM 8 menggunakan penganalisis PVS-Studio

Kecacatan yang dikenal pasti oleh diagnostik baharu

Saya rasa 30 pengaktifan diagnostik lama sudah memadai. Sekarang mari kita lihat perkara menarik yang boleh ditemui dengan diagnostik baharu yang muncul dalam penganalisis selepas itu sebelumnya cek. Pada masa ini, sejumlah 66 diagnostik tujuan umum telah ditambahkan pada penganalisis C++.

Serpihan N31: Kod tidak boleh dicapai

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

Amaran PVS-Studio: V779 [CWE-561] Kod tidak boleh dicapai dikesan. Ada kemungkinan ralat berlaku. ExecutionUtils.cpp 146

Seperti yang anda lihat, kedua-dua cawangan pengendali if berakhir dengan panggilan kepada operator pulangan. Sehubungan itu, bekas CtorDtorsByPriority tidak akan pernah dibersihkan.

Serpihan N32: Kod tidak boleh dicapai

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

Amaran PVS-Studio: V779 [CWE-561] Kod tidak boleh dicapai dikesan. Ada kemungkinan ralat berlaku. LLParser.cpp 835

Situasi yang menarik. Jom tengok tempat ni dulu:

return ParseTypeIdEntry(SummaryID);
break;

Sekali pandang, nampaknya tiada ralat di sini. Ia kelihatan seperti pengendali memecahkan terdapat tambahan di sini, dan anda boleh memadamkannya. Walau bagaimanapun, tidak semuanya begitu mudah.

Penganalisis mengeluarkan amaran pada talian:

Lex.setIgnoreColonInIdentifiers(false);
return false;

Dan sememangnya, kod ini tidak dapat dicapai. Semua kes dalam bertukar berakhir dengan panggilan daripada operator pulangan. Dan kini tidak masuk akal sendirian memecahkan tidak kelihatan begitu tidak berbahaya! Mungkin salah satu cabang harus berakhir dengan memecahkan, bukan pada pulangan?

Fragmen N33: Tetapan semula rawak 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);
  ....
}

Amaran PVS-Studio: V784 Saiz topeng bit adalah kurang daripada saiz operan pertama. Ini akan menyebabkan kehilangan bit yang lebih tinggi. RuntimeDyld.cpp 815

Sila ambil perhatian bahawa fungsi getStubAlignment jenis pulangan tidak ditandatangani. Mari kita hitung nilai ungkapan, dengan mengandaikan bahawa fungsi mengembalikan nilai 8:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFFF8u

Sekarang perhatikan bahawa pembolehubah Saiz Data mempunyai jenis unsigned 64-bit. Ternyata apabila menjalankan operasi DataSize & 0xFFFFFFF8u, kesemua tiga puluh dua bit tertib tinggi akan ditetapkan semula kepada sifar. Kemungkinan besar, ini bukan yang diinginkan oleh pengaturcara. Saya mengesyaki bahawa dia ingin mengira: DataSize & 0xFFFFFFFFFFFFFFFF8u.

Untuk membetulkan ralat, anda harus menulis ini:

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

Atau begitu:

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

Serpihan N34: Pelakon jenis 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);
  ....
}

Amaran PVS-Studio: V1028 [CWE-190] Kemungkinan limpahan. Pertimbangkan untuk menghantar operan 'NumElts * Scale' kepada jenis 'size_t', bukan hasilnya. X86ISelLowering.h 1577

Pemutus jenis eksplisit digunakan untuk mengelakkan limpahan apabila mendarab pembolehubah jenis int. Walau bagaimanapun, penghantaran jenis eksplisit di sini tidak melindungi daripada limpahan. Mula-mula, pembolehubah akan didarab, dan hanya kemudian hasil 32-bit pendaraban akan dikembangkan kepada jenis saiz_t.

Serpihan N35: Salin-Tampal 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 serpihan kod serupa ditemui. Mungkin, ini adalah kesilapan taip dan pembolehubah 'Op1' harus digunakan dan bukannya 'Op0'. InstCombineCompares.cpp 5507

Diagnostik menarik baharu ini mengenal pasti situasi di mana sekeping kod telah disalin dan beberapa nama telah mula ditukar di dalamnya, tetapi di satu tempat mereka tidak membetulkannya.

Sila ambil perhatian bahawa dalam blok kedua mereka berubah Op0 pada Op1. Tetapi di satu tempat mereka tidak membetulkannya. Kemungkinan besar ia sepatutnya ditulis seperti ini:

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

Serpihan N36: Kekeliruan Pembolehubah

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

Amaran PVS-Studio: V1001 [CWE-563] Pembolehubah 'Mod' ditetapkan tetapi tidak digunakan pada penghujung fungsi. SIModeRegister.cpp 48

Adalah sangat berbahaya untuk memberikan argumen fungsi nama yang sama dengan ahli kelas. Ia sangat mudah untuk keliru. Kami mempunyai kes sedemikian di hadapan kami. Ungkapan ini tidak masuk akal:

Mode &= Mask;

Argumen fungsi berubah. Itu sahaja. Hujah ini tidak lagi digunakan. Kemungkinan besar anda sepatutnya menulisnya seperti ini:

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

Serpihan N37: Kekeliruan Pembolehubah

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

Amaran PVS-Studio: V1001 [CWE-563] Pembolehubah 'Saiz' ditetapkan tetapi tidak digunakan pada penghujung fungsi. Object.cpp 424

Keadaannya serupa dengan yang sebelumnya. Ia harus ditulis:

this->Size += this->EntrySize;

Fragmen N38-N47: Mereka terlupa untuk menyemak indeks

Sebelum ini, kami melihat contoh pencetus diagnostik V595. Intipatinya ialah penunjuk dinyahrujuk pada permulaan, dan hanya kemudian diperiksa. Diagnostik muda V1004 adalah sebaliknya dalam makna, tetapi juga mendedahkan banyak kesilapan. Ia mengenal pasti situasi di mana penunjuk telah diperiksa pada mulanya dan kemudian terlupa untuk berbuat demikian. Mari kita lihat kes sebegini yang terdapat 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());  // <=
  ....
}

Amaran PVS-Studio: V1004 [CWE-476] Penunjuk 'Ptr' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 729, 738. TargetTransformInfoImpl.h 738

Pembolehubah Ptr mungkin sama nullptr, seperti yang dibuktikan oleh cek:

if (Ptr != nullptr)

Walau bagaimanapun, di bawah penunjuk ini dinyahrujuk tanpa semakan awal:

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

Mari kita pertimbangkan satu lagi kes yang serupa.

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

Amaran PVS-Studio: V1004 [CWE-476] Penunjuk 'FD' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 3228, 3231. CGDebugInfo.cpp 3231

Perhatikan tanda itu FD. Saya pasti masalahnya jelas kelihatan dan tiada penjelasan khas diperlukan.

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

Amaran PVS-Studio: V1004 [CWE-476] Penunjuk 'PtrTy' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 960, 965. InterleavedLoadCombinePass.cpp 965

Bagaimana untuk melindungi diri anda daripada kesilapan sedemikian? Lebih prihatin pada Semakan Kod dan gunakan penganalisis statik PVS-Studio untuk menyemak kod anda dengan kerap.

Tidak ada gunanya memetik serpihan kod lain dengan ralat jenis ini. Saya hanya akan meninggalkan senarai amaran dalam artikel:

  • V1004 [CWE-476] Penunjuk 'Expr' digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak baris: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Penunjuk 'PI' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Penunjuk 'StatepointCall' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Penunjuk 'RV' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Penunjuk 'CalleeFn' telah digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Penunjuk 'TC' digunakan secara tidak selamat selepas ia disahkan terhadap nullptr. Semak talian: 1819, 1824. Driver.cpp 1824

Serpihan N48-N60: Tidak kritikal, tetapi kecacatan (kemungkinan kebocoran memori)

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

Amaran PVS-Studio: V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Strategi' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-isel-fuzzer.cpp 58

Untuk menambah elemen pada penghujung bekas seperti std::vektor > anda tidak boleh menulis sahaja xxx.push_back(X baharu), kerana tiada penukaran tersirat daripada X* Π² std::unique_ptr.

Penyelesaian biasa ialah menulis xxx.emplace_back(X baharu)kerana ia menyusun: kaedah emplace_back membina elemen terus daripada hujahnya dan oleh itu boleh menggunakan pembina eksplisit.

Ia tidak selamat. Jika vektor penuh, maka memori diperuntukkan semula. Operasi pengagihan semula memori mungkin gagal, menyebabkan pengecualian dilemparkan std::bad_alloc. Dalam kes ini, penunjuk akan hilang dan objek yang dibuat tidak akan dipadamkan.

Penyelesaian yang selamat ialah mencipta unique_ptryang akan memiliki penunjuk sebelum vektor cuba mengagihkan semula memori:

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

Sejak C++14, anda boleh menggunakan 'std::make_unique':

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

Kecacatan jenis ini tidak kritikal untuk LLVM. Jika memori tidak dapat diperuntukkan, pengkompil hanya akan berhenti. Walau bagaimanapun, untuk aplikasi dengan panjang masa beroperasi, yang tidak boleh ditamatkan begitu sahaja jika peruntukan memori gagal, ini boleh menjadi pepijat jahat yang sebenar.

Jadi, walaupun kod ini tidak menimbulkan ancaman praktikal kepada LLVM, saya mendapati ia berguna untuk bercakap tentang corak ralat ini dan bahawa penganalisis PVS-Studio telah belajar untuk mengenal pastinya.

Amaran lain jenis ini:

  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Passes' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. PassManager.h 546
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'AA' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. AliasAnalysis.h 324
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Entri' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'AllEdges' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. CFGMST.h 268
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'VMaps' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Rekod' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. FDRLogBuilder.h 30
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'PendingSubmodules' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. ModuleMap.cpp 810
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Objek' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. DebugMap.cpp 88
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Strategi' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 685
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 686
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 688
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 689
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 690
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 691
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 692
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 693
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Pengubah suai' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. llvm-stress.cpp 694
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Operan' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Stash' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Penunjuk tanpa pemilik ditambahkan pada bekas 'Matchers' dengan kaedah 'emplace_back'. Kebocoran memori akan berlaku sekiranya berlaku pengecualian. GlobalISelEmitter.cpp 2702

Kesimpulan

Saya mengeluarkan 60 amaran secara keseluruhan dan kemudian berhenti. Adakah terdapat kecacatan lain yang dikesan oleh penganalisis PVS-Studio dalam LLVM? Ya saya ada. Walau bagaimanapun, apabila saya menulis serpihan kod untuk artikel itu, hari sudah lewat petang, atau lebih tepat lagi malam, dan saya memutuskan bahawa sudah tiba masanya untuk memanggilnya sehari.

Saya harap anda mendapati ia menarik dan ingin mencuba penganalisis PVS-Studio.

Anda boleh memuat turun penganalisis dan mendapatkan kunci penyapu ranjau di halaman ini.

Paling penting, gunakan analisis statik dengan kerap. Cek sekali, yang dijalankan oleh kami untuk mempopularkan metodologi analisis statik dan PVS-Studio bukanlah senario biasa.

Semoga berjaya dalam meningkatkan kualiti dan kebolehpercayaan kod anda!

Mencari pepijat dalam LLVM 8 menggunakan penganalisis PVS-Studio

Jika anda ingin berkongsi artikel ini dengan khalayak berbahasa Inggeris, sila gunakan pautan terjemahan: Andrey Karpov. Mencari Pepijat dalam LLVM 8 dengan PVS-Studio.

Sumber: www.habr.com

Tambah komen