Kupata hitilafu katika LLVM 8 kwa kutumia kichanganuzi cha PVS-Studio

Kupata hitilafu katika LLVM 8 kwa kutumia kichanganuzi cha PVS-Studio
Zaidi ya miaka miwili imepita tangu ukaguzi wa mwisho wa msimbo wa mradi wa LLVM kwa kutumia kichanganuzi chetu cha PVS-Studio. Hebu tuhakikishe kuwa kichanganuzi cha PVS-Studio bado ni zana inayoongoza ya kutambua makosa na udhaifu unaowezekana. Ili kufanya hivyo, tutaangalia na kupata makosa mapya katika toleo la LLVM 8.0.0.

Makala ya kuandikwa

Kusema kweli, sikutaka kuandika makala hii. Haifurahishi kuandika juu ya mradi ambao tayari tumeangalia mara kadhaa (1, 2, 3) Ni bora kuandika juu ya kitu kipya, lakini sina chaguo.

Kila wakati toleo jipya la LLVM linatolewa au kusasishwa Clang Static Analyzer, tunapokea maswali ya aina ifuatayo katika barua zetu:

Tazama, toleo jipya la Clang Static Analyzer limejifunza kupata makosa mapya! Inaonekana kwangu kwamba umuhimu wa kutumia PVS-Studio unapungua. Clang hupata makosa zaidi kuliko hapo awali na anapata uwezo wa PVS-Studio. Una maoni gani kuhusu hili?

Kwa hili kila wakati nataka kujibu kitu kama:

Hatukai bila kazi pia! Tumeboresha kwa kiasi kikubwa uwezo wa kichanganuzi cha PVS-Studio. Kwa hivyo usijali, tunaendelea kuongoza kama hapo awali.

Kwa bahati mbaya, hii ni jibu mbaya. Hakuna uthibitisho ndani yake. Na ndiyo sababu ninaandika makala hii sasa. Kwa hivyo, mradi wa LLVM umeangaliwa tena na makosa kadhaa yamepatikana ndani yake. Sasa nitaonyesha zile ambazo zilionekana kunivutia. Clang Static Analyzer haiwezi kupata makosa haya (au ni ngumu sana kufanya hivyo kwa msaada wake). Lakini tunaweza. Zaidi ya hayo, nilipata na kuandika makosa haya yote kwa jioni moja.

Lakini kuandika makala hiyo kulichukua wiki kadhaa. Sikuweza kujiletea kuweka haya yote kwenye maandishi :).

Kwa njia, ikiwa una nia ya ni teknolojia gani zinazotumiwa katika analyzer ya PVS-Studio kutambua makosa na udhaifu unaowezekana, basi ninapendekeza kufahamiana na hili. Kumbuka.

Utambuzi mpya na wa zamani

Kama ilivyoonyeshwa tayari, kama miaka miwili iliyopita mradi wa LLVM ulikaguliwa tena, na makosa yaliyopatikana yalisahihishwa. Sasa makala hii itawasilisha kundi jipya la makosa. Kwa nini mende mpya zilipatikana? Kuna sababu 3 za hii:

  1. Mradi wa LLVM unabadilika, kubadilisha msimbo wa zamani na kuongeza msimbo mpya. Kwa kawaida, kuna makosa mapya katika kanuni iliyorekebishwa na iliyoandikwa. Hii inaonyesha wazi kwamba uchambuzi wa tuli unapaswa kutumika mara kwa mara, na si mara kwa mara. Makala yetu yanaonyesha vizuri uwezo wa PVS-Studio analyzer, lakini hii haina uhusiano wowote na kuboresha ubora wa kanuni na kupunguza gharama ya kurekebisha makosa. Tumia kichanganuzi cha nambari tuli mara kwa mara!
  2. Tunakamilisha na kuboresha uchunguzi uliopo. Kwa hiyo, analyzer inaweza kutambua makosa ambayo haikuona wakati wa scans zilizopita.
  3. Uchunguzi mpya umeonekana katika PVS-Studio ambayo haikuwepo miaka 2 iliyopita. Niliamua kuwaangazia katika sehemu tofauti ili kuonyesha wazi maendeleo ya PVS-Studio.

Kasoro zilizotambuliwa na uchunguzi uliokuwepo miaka 2 iliyopita

Kipande N1: Nakili-Bandika

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

Onyo la PVS-Studio: V501 [CWE-570] Kuna maneno madogo yanayofanana 'Name.startswith("avx512.mask.permvar.")' upande wa kushoto na kulia wa '||' mwendeshaji. Kuboresha Kiotomatiki.cpp 73

Imeangaliwa mara mbili kwamba jina linaanza na kamba ndogo "avx512.mask.permvar.". Katika hundi ya pili, ni wazi walitaka kuandika kitu kingine, lakini walisahau kusahihisha maandishi yaliyonakiliwa.

Kipande N2: Chapa

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

Onyo la PVS-Studio: V501 Kuna vijisemo vidogo vinavyofanana 'CXNameRange_WantQualifier' upande wa kushoto na kulia wa '|' mwendeshaji. CIndex.cpp 7245

Kwa sababu ya kosa la kuandika, ile ile inayoitwa mara kwa mara hutumiwa mara mbili CXNameRange_WantQualifier.

Sehemu N3: Kuchanganyikiwa na utangulizi wa waendeshaji

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

Onyo la PVS-Studio: V502 [CWE-783] Labda opereta '?:' hufanya kazi kwa njia tofauti na ilivyotarajiwa. Opereta '?:' ina kipaumbele cha chini kuliko opereta '=='. PPCTargetTransformInfo.cpp 404

Kwa maoni yangu, hii ni kosa nzuri sana. Ndiyo, najua nina mawazo ya ajabu kuhusu uzuri :).

Sasa, kulingana na vipaumbele vya waendeshaji, usemi huo unatathminiwa kama ifuatavyo:

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

Kwa mtazamo wa vitendo, hali kama hiyo haina maana, kwani inaweza kupunguzwa kuwa:

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

Hili ni kosa la wazi. Uwezekano mkubwa zaidi, walitaka kulinganisha 0/1 na kutofautisha index. Ili kurekebisha msimbo unahitaji kuongeza mabano karibu na opereta wa tatu:

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

Kwa njia, operator wa ternary ni hatari sana na husababisha makosa ya kimantiki. Kuwa mwangalifu nayo sana na usiwe mchoyo wa mabano. Niliangalia mada hii kwa undani zaidi hapa, katika sura β€œJihadhari na ?: Mwendeshaji na Uifunge Katika Mabano.”

Kipande N4, N5: Kielekezi tupu

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

Onyo la PVS-Studio: V522 [CWE-476] Urejeleaji wa kielekezi batili 'LHS' huenda ukafanyika. TGParser.cpp 2152

Ikiwa pointer LHS ni null, onyo itolewe. Walakini, badala yake, kiashiria hiki hiki kisicho na maana kitatolewa: LHS->getAsString().

Hii ni hali ya kawaida sana wakati kosa limefichwa kwenye kidhibiti makosa, kwani hakuna mtu anayezijaribu. Wachanganuzi tuli huangalia nambari zote zinazoweza kufikiwa, haijalishi inatumiwa mara ngapi. Huu ni mfano mzuri sana wa jinsi uchanganuzi tuli hukamilisha mbinu zingine za majaribio na ulinzi wa makosa.

Hitilafu sawa ya kushughulikia kielekezi RHS inaruhusiwa katika msimbo ulio hapa chini: V522 [CWE-476] Urejeleaji wa kiashirio batili 'RHS' huenda ukafanyika. TGParser.cpp 2186

Fragment N6: Kutumia pointer baada ya kusonga

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

Onyo la PVS-Studio: V522 [CWE-476] Urejeleaji wa kielekezi batili 'ProgClone' huenda ukafanyika. Kukosea.cpp 601

Hapo mwanzo kielekezi mahiri ProgClone huacha kumiliki kitu:

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

Kwa kweli, sasa ProgClone ni null pointer. Kwa hivyo, urejeleaji wa null pointer unapaswa kutokea hapa chini:

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

Lakini, kwa kweli, hii haitatokea! Kumbuka kuwa kitanzi hakijatekelezwa.

Mwanzoni mwa chombo MicompiledFunctions imefutwa:

MiscompiledFunctions.clear();

Ifuatayo, saizi ya chombo hiki hutumiwa katika hali ya kitanzi:

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

Ni rahisi kuona kwamba kitanzi hakianza. Nadhani hii pia ni mdudu na nambari inapaswa kuandikwa tofauti.

Inaonekana kwamba tumekutana na usawa huo maarufu wa makosa! Kosa moja hufunika lingine :).

Fragment N7: Kutumia pointer baada ya kusonga

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

Onyo la PVS-Studio: V522 [CWE-476] Kuacha kurejelea kwa 'Jaribio' la kiashiria batili kunaweza kufanyika. Kukosea.cpp 709

Hali hiyo hiyo tena. Mara ya kwanza, yaliyomo kwenye kitu huhamishwa, na kisha hutumiwa kana kwamba hakuna kitu kilichotokea. Ninaona hali hii mara nyingi zaidi katika nambari ya programu baada ya semantiki za harakati kuonekana katika C++. Hii ndiyo sababu ninapenda lugha ya C++! Kuna njia mpya zaidi za kufyatua mguu wako mwenyewe. Kichambuzi cha PVS-Studio kitakuwa na kazi kila wakati :).

Kipande N8: Kielekezi tupu

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

Onyo la PVS-Studio: V522 [CWE-476] Urejeleaji wa 'Aina' ya kiashirio batili huenda ukafanyika. PrettyFunctionDumper.cpp 233

Kando na vidhibiti vya hitilafu, utatuzi wa utendakazi wa kuchapisha kwa kawaida haujaribiwi. Tuna kesi kama hiyo mbele yetu. Kazi inasubiri mtumiaji, ambaye, badala ya kutatua matatizo yake, atalazimika kurekebisha.

Haki:

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

Kipande N9: Kielekezi tupu

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

Onyo la PVS-Studio: V522 [CWE-476] Urejeleaji wa kielekezi batili 'Ty' huenda ukafanyika. InatafutwaTableEmitter.cpp 614

Nadhani kila kitu kiko wazi na haihitaji maelezo.

Kipande N10: Chapa

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

Onyo la PVS-Studio: V570 Tofauti ya 'Kitambulisho->Aina' imekabidhiwa yenyewe. FormatTokenLexer.cpp 249

Hakuna maana katika kugawa kigezo yenyewe. Uwezekano mkubwa zaidi walitaka kuandika:

Identifier->Type = Question->Type;

Kipande N11: Mapumziko ya kutiliwa shaka

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

Onyo la PVS-Studio: V622 [CWE-478] Fikiria kukagua taarifa ya 'switch'. Inawezekana kwamba opereta wa "kesi" ya kwanza haipo. SystemZAsmParser.cpp 652

Kuna operator wa shaka sana mwanzoni kuvunja. Je, umesahau kuandika kitu kingine hapa?

Kipande N12: Kuangalia pointer baada ya kutenganisha

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

Onyo la PVS-Studio: V595 [CWE-476] Kielekezi cha 'Callee' kilitumika kabla ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 172, 174. AMDGPUInline.cpp 172

Pointer Calee mwanzoni huahirishwa wakati kazi inaitwa pataTTI.

Na kisha inageuka kuwa pointer hii inapaswa kuangaliwa kwa usawa nullptr:

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

Lakini ni kuchelewa sana ...

Kipande N13 - N...: Kuangalia kielekezi baada ya kutenganisha

Hali iliyojadiliwa katika kipande cha msimbo uliopita si ya kipekee. Inaonekana hapa:

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

Onyo la PVS-Studio: V595 [CWE-476] Kielekezi cha 'CalleeFn' kilitumika kabla ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 1079, 1081. SimplifyLibCalls.cpp 1079

Na hapa:

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

Onyo la PVS-Studio: V595 [CWE-476] Kielekezi cha 'ND' kilitumiwa kabla ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Na hapa:

  • V595 [CWE-476] Kielekezi cha 'U' kilitumika kabla ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] Kielekezi cha 'ND' kilitumika kabla ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Na kisha nikawa sipendi kusoma maonyo na nambari V595. Kwa hivyo sijui ikiwa kuna makosa zaidi sawa kando na yale yaliyoorodheshwa hapa. Uwezekano mkubwa zaidi kuna.

Kipande N17, N18: Mabadiliko ya kutiliwa shaka

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

Onyo la PVS-Studio: V629 [CWE-190] Fikiria kukagua usemi wa '~(Size - 1) << 1'. Kubadilisha kidogo kwa thamani ya 32-bit na upanuzi unaofuata hadi aina ya 64-bit. AArch64AddressingModes.h 260

Huenda isiwe mdudu na msimbo hufanya kazi kama ilivyokusudiwa. Lakini hii ni wazi mahali pa kutiliwa shaka sana na inahitaji kuangaliwa.

Hebu sema kutofautiana ukubwa ni sawa na 16, na kisha mwandishi wa kanuni alipanga kuipata kwa kutofautiana NImms maana:

1111111111111111111111111111111111111111111111111111111111100000

Walakini, kwa kweli matokeo yatakuwa:

0000000000000000000000000000000011111111111111111111111111100000

Ukweli ni kwamba mahesabu yote hutokea kwa kutumia aina ya 32-bit isiyosajiliwa. Na kisha tu, aina hii ya 32-bit ambayo haijatiwa saini itapanuliwa kikamilifu uint64_t. Katika kesi hii, bits muhimu zaidi zitakuwa sifuri.

Unaweza kurekebisha hali kama hii:

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

Hali sawa: V629 [CWE-190] Fikiria kukagua usemi wa 'Immr << 6'. Kubadilisha kidogo kwa thamani ya 32-bit na upanuzi unaofuata hadi aina ya 64-bit. AArch64AddressingModes.h 269

Kipande N19: Neno muhimu halipo mwingine?

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

Onyo la PVS-Studio: V646 [CWE-670] Fikiria kukagua mantiki ya programu. Inawezekana kwamba neno kuu la 'mwingine' halipo. AMDGPUAsmParser.cpp 5655

Hakuna makosa hapa. Tangu wakati huo-block ya kwanza if inaisha na kuendelea, basi haijalishi, kuna neno kuu mwingine au siyo. Kwa njia yoyote nambari itafanya kazi sawa. Bado amekosa mwingine hufanya msimbo kuwa wazi zaidi na hatari. Ikiwa katika siku zijazo kuendelea kutoweka, msimbo utaanza kufanya kazi tofauti kabisa. Kwa maoni yangu ni bora kuongeza mwingine.

Kipande N20: Chapa nne za aina moja

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

Maonyo ya PVS-Studio:

  • V655 [CWE-480] Mifuatano iliunganishwa lakini haitumiki. Fikiria kukagua usemi wa 'Result + Name.str()'. Alama.cpp 32
  • V655 [CWE-480] Mifuatano iliunganishwa lakini haitumiki. Fikiria kukagua usemi wa 'Result + "(ObjC Class)" + Name.str()'. Alama.cpp 35
  • V655 [CWE-480] Mifuatano iliunganishwa lakini haitumiki. Fikiria kukagua usemi wa 'Result + "(ObjC Class EH) " + Name.str()'. Alama.cpp 38
  • V655 [CWE-480] Mifuatano iliunganishwa lakini haitumiki. Fikiria kukagua usemi wa 'Result + "(ObjC IVar)" + Name.str()'. Alama.cpp 41

Kwa bahati mbaya, opereta + hutumiwa badala ya opereta +=. Matokeo yake ni miundo ambayo haina maana.

Sehemu N21: Tabia isiyobainishwa

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

Jaribu kupata nambari hatari mwenyewe. Na hii ni picha ya kuvuruga umakini ili usiangalie jibu mara moja:

Kupata hitilafu katika LLVM 8 kwa kutumia kichanganuzi cha PVS-Studio

Onyo la PVS-Studio: V708 [CWE-758] Ujenzi hatari hutumika: 'FeaturesMap[Op] = FeaturesMap.size()', ambapo 'FeaturesMap' ni ya darasa la 'map'. Hii inaweza kusababisha tabia isiyojulikana. RISCVCompressInstEmitter.cpp 490

Mstari wa tatizo:

FeaturesMap[Op] = FeaturesMap.size();

Ikiwa kipengele Op haipatikani, basi kipengele kipya kinaundwa kwenye ramani na idadi ya vipengele kwenye ramani hii imeandikwa hapo. Haijulikani ikiwa chaguo la kukokotoa litaitwa kawaida kabla au baada ya kuongeza kipengele kipya.

Sehemu N22-N24: Kazi zinazorudiwa

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

Onyo la PVS-Studio: V519 [CWE-563] Tofauti ya 'NType' imepewa maadili mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 1663, 1664. MachOObjectFile.cpp 1664

Sidhani kama kuna makosa ya kweli hapa. Mgawo wa kurudiwa tu usio wa lazima. Lakini bado ni kosa.

Vile vile:

  • V519 [CWE-563] Tofauti ya 'B.NDesc' imegawiwa thamani mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Tofauti hupewa maadili mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 59, 61. coff2yaml.cpp 61

Kipande N25-N27: Kazi nyingine tena

Sasa hebu tuangalie toleo tofauti kidogo la ugawaji upya.

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

Onyo la PVS-Studio: V519 [CWE-563] Tofauti ya 'Mpangilio' hupewa thamani mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 1158, 1160. LoadStoreVectorizer.cpp 1160

Hii ni nambari ya kushangaza sana ambayo inaonekana ina hitilafu ya kimantiki. Mwanzoni, kutofautiana Alignment thamani inatolewa kulingana na hali. Na kisha mgawo hutokea tena, lakini sasa bila hundi yoyote.

Hali zinazofanana zinaweza kuonekana hapa:

  • V519 [CWE-563] Tofauti ya 'Athari' hupewa thamani mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Tofauti ya 'ExpectNoDerefChunk' imepewa maadili mara mbili mfululizo. Pengine hili ni kosa. Angalia mistari: 4970, 4973. SemaType.cpp 4973

Sehemu N28: Hali halisi kila wakati

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

Onyo la PVS-Studio: V547 [CWE-571] Usemi 'nextByte != 0x90' huwa kweli kila wakati. X86DisassemblerDecoder.cpp 379

Kukagua haina maana. Inaweza kubadilika nextByte daima si sawa na thamani 0x90, ambayo inafuata kutoka kwa hundi iliyotangulia. Hii ni aina fulani ya makosa ya kimantiki.

Fragment N29 - N...: Hali za kweli/sio kweli kila wakati

Mchambuzi hutoa maonyo mengi kwamba hali nzima (V547) au sehemu yake (V560) daima ni kweli au uongo. Mara nyingi haya sio makosa ya kweli, lakini nambari duni tu, matokeo ya upanuzi wa jumla, na kadhalika. Hata hivyo, ni mantiki kuangalia maonyo haya yote, kwa kuwa makosa ya kweli ya kimantiki hutokea mara kwa mara. Kwa mfano, sehemu hii ya kanuni inatiliwa shaka:

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

Onyo la PVS-Studio: V560 [CWE-570] Sehemu ya usemi wa masharti huwa si kweli: RegNo == 0xe. ARMdisassembler.cpp 939

0xE isiyobadilika ni thamani 14 katika desimali. Uchunguzi RegNo == 0xe haina maana kwa sababu kama RegNo > 13, basi kazi itakamilisha utekelezaji wake.

Kulikuwa na maonyo mengine mengi yenye vitambulisho V547 na V560, lakini kama ilivyokuwa V595, sikupendezwa kusoma maonyo haya. Ilikuwa tayari wazi kwamba nilikuwa na nyenzo za kutosha kuandika makala :). Kwa hiyo, haijulikani jinsi makosa mengi ya aina hii yanaweza kutambuliwa katika LLVM kwa kutumia PVS-Studio.

Nitakupa mfano wa kwa nini kusoma vichochezi hivi kunachosha. Kichanganuzi kiko sahihi kabisa katika kutoa onyo kwa nambari ifuatayo. Lakini hili si kosa.

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

Onyo la PVS-Studio: V547 [CWE-570] Maneno '!HasError' huwa si ya kweli. UnwrappedLineParser.cpp 1635

Sehemu N30: ​​Kurudi kwa kutia shaka

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

Onyo la PVS-Studio: V612 [CWE-670] 'Kurudi' bila masharti ndani ya kitanzi. R600OptimizeVectorRegisters.cpp 63

Hili ni kosa au mbinu maalum ambayo imekusudiwa kuelezea kitu kwa watengeneza programu wanaosoma nambari. Muundo huu haunielezi chochote na unaonekana kuwa wa kutiliwa shaka sana. Ni bora si kuandika kama hiyo :).

Umechoka? Kisha ni wakati wa kufanya chai au kahawa.

Kupata hitilafu katika LLVM 8 kwa kutumia kichanganuzi cha PVS-Studio

Kasoro zinazotambuliwa na uchunguzi mpya

Nadhani uanzishaji 30 wa utambuzi wa zamani unatosha. Hebu sasa tuone ni mambo gani ya kuvutia yanaweza kupatikana na uchunguzi mpya ambao ulionekana kwenye analyzer baada ya uliopita hundi. Wakati huu, jumla ya uchunguzi wa madhumuni ya jumla 66 uliongezwa kwenye kichanganuzi cha C++.

Sehemu N31: Nambari isiyoweza kufikiwa

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

Onyo la PVS-Studio: V779 [CWE-561] Nambari ya kuthibitisha isiyoweza kufikiwa imetambuliwa. Inawezekana kuwa kuna kosa. ExecutionUtils.cpp 146

Kama unaweza kuona, matawi yote mawili ya operator if huisha kwa simu kwa opereta kurudi. Ipasavyo, chombo CtorDtorsByPriority haitafutwa kamwe.

Sehemu N32: Nambari isiyoweza kufikiwa

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

Onyo la PVS-Studio: V779 [CWE-561] Nambari ya kuthibitisha isiyoweza kufikiwa imetambuliwa. Inawezekana kuwa kuna kosa. LLParser.cpp 835

Hali ya kuvutia. Hebu tuangalie mahali hapa kwanza:

return ParseTypeIdEntry(SummaryID);
break;

Kwa mtazamo wa kwanza, inaonekana kwamba hakuna kosa hapa. Inaonekana kama operator kuvunja kuna ya ziada hapa, na unaweza kuifuta kwa urahisi. Walakini, sio zote rahisi sana.

Mchambuzi anatoa onyo kwenye mistari:

Lex.setIgnoreColonInIdentifiers(false);
return false;

Na hakika, kanuni hii haipatikani. Kesi zote ndani kubadili huisha kwa simu kutoka kwa opereta kurudi. Na sasa ujinga peke yako kuvunja haionekani kuwa haina madhara! Labda moja ya matawi inapaswa kumaliza na kuvunjasio kwenye kurudi?

Fragment N33: Kuweka upya bila mpangilio kwa biti za juu

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

Onyo la PVS-Studio: V784 Ukubwa wa mask kidogo ni chini ya ukubwa wa operand ya kwanza. Hii itasababisha upotezaji wa bits za juu. RuntimeDyld.cpp 815

Tafadhali kumbuka kuwa kazi getStubAlignment aina ya kurejesha haijasajiliwa. Wacha tuhesabu thamani ya usemi, tukichukulia kuwa chaguo za kukokotoa hurejesha thamani 8:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFFF8u

Sasa taarifa kwamba kutofautiana Ukubwa wa Data ina aina ya 64-bit ambayo haijasainiwa. Inabadilika kuwa wakati wa kufanya kazi ya DataSize & 0xFFFFFFF8u, bits zote thelathini na mbili za juu zitawekwa upya hadi sifuri. Uwezekano mkubwa zaidi, hii sio kile mtayarishaji wa programu alitaka. Ninashuku kuwa alitaka kukokotoa: DataSize & 0xFFFFFFFFFFFFFFF8u.

Ili kurekebisha kosa, unapaswa kuandika hivi:

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

Au hivyo:

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

Kipande N34: Imeshindwa kutuma aina chafu

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

Onyo la PVS-Studio: V1028 [CWE-190] Uwezekano wa kufurika. Zingatia kutuma oparesheni za opereta ya 'NumElts * Scale' kwa aina ya 'size_t', si matokeo. X86ISelLowering.h 1577

Utumaji wa aina dhahiri hutumika kuzuia kufurika wakati wa kuzidisha vigeu vya aina int. Walakini, utumaji wa aina dhahiri hapa haulinde dhidi ya kufurika. Kwanza, vigezo vitazidishwa, na kisha tu matokeo ya 32-bit ya kuzidisha yatapanuliwa kwa aina. saizi_t.

Kipande N35: Imeshindwa Kunakili-Bandika

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] Vipande viwili vya msimbo sawa vilipatikana. Labda, hii ni typo na tofauti ya 'Op1' inapaswa kutumika badala ya 'Op0'. InstCombineCompares.cpp 5507

Utambuzi huu mpya unaovutia unabainisha hali ambapo kipande cha msimbo kimenakiliwa na baadhi ya majina yameanza kubadilishwa ndani yake, lakini katika sehemu moja hawajaisahihisha.

Tafadhali kumbuka kuwa katika block ya pili walibadilika Op0 juu ya Op1. Lakini katika sehemu moja hawakurekebisha. Uwezekano mkubwa zaidi, inapaswa kuandikwa kama hii:

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

Kipande N36: Mchanganyiko Unaobadilika

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

Onyo la PVS-Studio: V1001 [CWE-563] Tofauti ya 'Modi' imetolewa lakini haitumiki kufikia mwisho wa chaguo la kukokotoa. SIModeRegister.cpp 48

Ni hatari sana kutoa hoja za kazi kwa majina sawa na washiriki wa darasa. Ni rahisi sana kuchanganyikiwa. Tuna kesi kama hiyo mbele yetu. Usemi huu hauna maana:

Mode &= Mask;

Hoja ya kukokotoa inabadilika. Ni hayo tu. Hoja hii haitumiki tena. Uwezekano mkubwa zaidi unapaswa kuandika kama hii:

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

Kipande N37: Mchanganyiko Unaobadilika

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

Onyo la PVS-Studio: V1001 [CWE-563] Tofauti ya 'Ukubwa' imetolewa lakini haitumiki kufikia mwisho wa chaguo la kukokotoa. Object.cpp 424

Hali ni sawa na ile iliyopita. Inapaswa kuandikwa:

this->Size += this->EntrySize;

Fragment N38-N47: Walisahau kuangalia index

Hapo awali, tuliangalia mifano ya kuchochea uchunguzi V595. Kiini chake ni kwamba pointer haijarejelewa mwanzoni, na kisha kukaguliwa. Utambuzi wa vijana V1004 ni kinyume katika maana, lakini pia hufichua makosa mengi. Inabainisha hali ambapo pointer iliangaliwa mwanzoni na kisha kusahau kufanya hivyo. Wacha tuangalie kesi kama hizi zinazopatikana ndani ya 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());  // <=
  ....
}

Onyo la PVS-Studio: V1004 [CWE-476] Kielekezi cha 'Ptr' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 729, 738. TargetTransformInfoImpl.h 738

Inaweza kubadilika Ptr inaweza kuwa sawa nullptr, kama inavyothibitishwa na hundi:

if (Ptr != nullptr)

Walakini, chini ya pointer hii imeahirishwa bila ukaguzi wa awali:

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

Wacha tuchunguze kesi nyingine kama hiyo.

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

Onyo la PVS-Studio: V1004 [CWE-476] Kielekezi cha 'FD' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 3228, 3231. CGDebugInfo.cpp 3231

Makini na ishara FD. Nina hakika shida inaonekana wazi na hakuna maelezo maalum inahitajika.

Na zaidi:

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

Onyo la PVS-Studio: V1004 [CWE-476] Kielekezi cha 'PtrTy' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 960, 965. InterleavedLoadCombinePass.cpp 965

Jinsi ya kujikinga na makosa kama haya? Kuwa mwangalifu zaidi kuhusu Ukaguzi wa Msimbo na utumie kichanganuzi tuli cha PVS-Studio ili kuangalia msimbo wako mara kwa mara.

Hakuna maana katika kutaja vipande vingine vya kanuni na makosa ya aina hii. Nitaacha orodha ya maonyo tu katika kifungu:

  • V1004 [CWE-476] Kielekezi cha 'Expr' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Kielekezi cha 'PI' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Kielekezi cha 'StatepointCall' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Kielekezi cha 'RV' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Kielekezi cha 'CalleeFn' kilitumika kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Kielekezi cha 'TC' kilitumiwa kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 1819, 1824. Driver.cpp 1824

Sehemu N48-N60: Sio muhimu, lakini kasoro (uvujaji wa kumbukumbu unaowezekana)

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

Onyo la PVS-Studio: V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Strategies' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-isel-fuzzer.cpp 58

Ili kuongeza kipengee hadi mwisho wa chombo kama std::vekta > huwezi kuandika tu xxx.push_back(X mpya), kwa kuwa hakuna ubadilishaji kamili kutoka X* Π² std::kipekee_ptr.

Suluhisho la kawaida ni kuandika xxx.emplace_back(X mpya)kwani inakusanya: mbinu emplace_back huunda kipengele moja kwa moja kutoka kwa hoja zake na kwa hivyo inaweza kutumia wajenzi wazi.

Sio salama. Ikiwa vekta imejaa, basi kumbukumbu inatolewa tena. Operesheni ya uhamishaji wa kumbukumbu inaweza kushindwa, na kusababisha ubaguzi kutupwa std::bad_alloc. Katika kesi hii, pointer itapotea na kitu kilichoundwa hakitafutwa kamwe.

Suluhisho salama ni kuunda kipekee_ptrambayo itamiliki pointer kabla ya vekta kujaribu kuhamisha kumbukumbu tena:

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

Tangu C++14, unaweza kutumia 'std::make_unique':

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

Aina hii ya kasoro sio muhimu kwa LLVM. Ikiwa kumbukumbu haiwezi kugawanywa, mkusanyaji ataacha tu. Hata hivyo, kwa maombi na muda mrefu uptime, ambayo haiwezi tu kusitisha ikiwa ugawaji wa kumbukumbu utashindwa, hii inaweza kuwa mdudu mbaya sana.

Kwa hivyo, ingawa nambari hii haileti tishio la vitendo kwa LLVM, niliona ni muhimu kuzungumza juu ya muundo huu wa makosa na kwamba mchambuzi wa PVS-Studio amejifunza kuitambua.

Maonyo mengine ya aina hii:

  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Passes' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. PassManager.h 546
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'AAs' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. LakabuUchambuzi.h 324
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Entries' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye kontena la 'AllEdges' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. CFGMST.h 268
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'VMaps' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Rekodi' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. FDRLogBuilder.h 30
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye chombo cha 'PendingSubmodules' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. ModuliMap.cpp 810
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Objects' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. DebugMap.cpp 88
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye kontena la 'Strategies' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 685
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 686
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 688
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 689
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 690
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 691
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 692
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 693
  • V1023 [CWE-460] Kielekezi kisicho na mmiliki kinaongezwa kwenye kontena la 'Modifiers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. llvm-stress.cpp 694
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Operands' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. GlobalISElEmitter.cpp 1911
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Stash' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. GlobalISElEmitter.cpp 2100
  • V1023 [CWE-460] Kielekezi bila mmiliki kinaongezwa kwenye chombo cha 'Matchers' kwa mbinu ya 'emplace_back'. Uvujaji wa kumbukumbu utatokea katika kesi ya ubaguzi. GlobalISElEmitter.cpp 2702

Hitimisho

Nilitoa maonyo 60 kwa jumla kisha nikaacha. Kuna kasoro zingine ambazo kichanganuzi cha PVS-Studio hugundua katika LLVM? Ndio ninayo. Hata hivyo, nilipokuwa nikiandika vipande vya msimbo wa makala hiyo, ilikuwa jioni sana, au tuseme hata usiku, na niliamua kuwa ni wakati wa kuiita siku.

Natumai umeipata ya kufurahisha na utataka kujaribu kichanganuzi cha PVS-Studio.

Unaweza kupakua kichanganuzi na kupata ufunguo wa minesweeper Ukurasa huu.

Muhimu zaidi, tumia uchambuzi wa tuli mara kwa mara. Hundi za mara moja, uliofanywa na sisi ili kutangaza mbinu ya uchambuzi wa tuli na PVS-Studio sio hali ya kawaida.

Bahati nzuri katika kuboresha ubora na uaminifu wa nambari yako!

Kupata hitilafu katika LLVM 8 kwa kutumia kichanganuzi cha PVS-Studio

Ikiwa ungependa kushiriki makala hii na hadhira inayozungumza Kiingereza, tafadhali tumia kiungo cha kutafsiri: Andrey Karpov. Kupata Hitilafu katika LLVM 8 na PVS-Studio.

Chanzo: mapenzi.com

Kuongeza maoni