Hibákat keresünk az LLVM 8-ban a PVS-Studio elemző segítségével.

Buggokat találunk az LLVM 8-ban a PVS-Studio elemző segítségével
Több mint két év telt el azóta, hogy utoljára ellenőriztük az LLVM projekt kódját a PVS-Studio analizátorunkkal. Győződjünk meg róla, hogy a PVS-Studio analizátor továbbra is a vezető eszköz a hibák és potenciális sebezhetőségek feltárásában. Ehhez ellenőrizzük és találjunk új hibákat az LLVM 8.0.0 kiadásában.

Cikk, amit meg kell írni

Őszintén szólva, nem volt kedvem megírni ezt a cikket. Nem izgalmas már egy olyan projektről írni, amit már többször is ellenőriztünk (1, 2, 3). Jobb lenne valami új dologról írni, de nincs választásom.

Minden alkalommal, amikor új verzió jelenik meg az LLVM-ből vagy frissül a Clang Static Analyzer, kérdések érkeznek az e-mailjeinkbe a következő típusban:

Nézd, az új verzió a Clang Static Analyzer most már új hibákat talál! Szerintem a PVS-Studio használatának aktualitása csökken. A Clang több hibát talál, mint valaha, és közelít a PVS-Studio lehetőségeihez. Mit gondolsz erről?

Erre mindig azt szeretném válaszolni, hogy:

Mi sem ülünk tétlen! Jelentősen javítottuk a PVS-Studio analizátor képességeit. Szóval ne aggódj, továbbra is vezető szerepet játszunk, ahogyan eddig.

Sajnos ez egy rossz válasz. Nincs benne bizonyíték. És éppen ezért írom most ezt a cikket. Tehát az LLVM projektet megint ellenőriztük, és különféle hibákat találtunk. Azokat, amelyek számomra érdekesnek tűntek, most bemutatom. Ezeket a hibákat a Clang Static Analyzer nem tudja észlelni (vagy rendkívül kényelmetlen ezt vele megtenni). De mi képesek vagyunk erre. Ráadásul egy este alatt találtam és jegyeztem fel az összes ilyen hibát.

A cikk írása viszont több hétig elhúzódott. Nem tudtam magam rávenni, hogy mindezt szövegformába öntsem : ).

Egyébként, ha érdekel, milyen technológiákat használnak a PVS-Studio analizátorban a hibák és potenciális sebezhetőségek feltárására, javaslom, ismerkedj meg ezzel a jegyzettel..

Új és régi diagnosztikák

Ahogy már említettem, körülbelül két évvel ezelőtt az LLVM projektet ismételten ellenőrizték, és a talált hibákat javították. Most ebben a cikkben egy új adag hibát fogunk bemutatni. Miért találtunk új hibákat? Három oka van ennek:

  1. Az LLVM projekt fejlődik, a régi kód megváltozik, és új kód jelenik meg. Természetes, hogy a megváltozott és az újonnan írt kódban új hibák lépnek fel. Ez jól szemlélteti, hogy a statikus elemzést rendszeresen alkalmazni kell, nem csak alkalmanként. Cikkink jól bemutatják a PVS-Studio elemző lehetőségeit, de ez nem kapcsolódik a kód minőségének javításához és a hibák javítási költségeinek csökkentéséhez. Használja a statikus kódellenőrzőt rendszeresen!
  2. Továbbfejlesztjük és tökéletesítjük a már meglévő diagnosztikákat. Ezért az elemző képes olyan hibákra is rámutatni, amelyeket a korábbi ellenőrzések során nem észlelt.
  3. A PVS-Studio új diagnosztikákkal bővült, amelyek két évvel ezelőtt még nem voltak. Úgy döntöttem, hogy külön szakaszba emelem őket, hogy jól szemléltethessem a PVS-Studio fejlődését.

A két évvel ezelőtti diagnosztikák által észlelt hibák

1. fragement: Másolás-Beillesztés

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

PVS-Studio figyelmeztetés: V501 [CWE-570] Az ‘Name.startswith(«avx512.mask.permvar.»)’ kifejezés mindkét oldalán az ‘||’ operátor mellett azonos rész-kifejezések találhatók. AutoUpgrade.cpp 73

Kétszer ellenőrizték, hogy a név a «avx512.mask.permvar.» karakterlánccal kezdődik. A második ellenőrzésnél nyilvánvalóan valami mást akartak írni, de elfelejtették kijavítani a másolt szöveget.

2. fragement: Elírás

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

PVS-Studio figyelmeztetés: V501 Az ‘CXNameRange_WantQualifier’ kifejezés mindkét oldalán az ‘|’ operátor mellett azonos rész-kifejezések találhatók. CIndex.cpp 7245

Az elírás miatt kétszer használják ugyanazt a névvel rendelkező konstansot CXNameRange_WantQualifier.

3. fragement: Operátor prioritás zűrzavar

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

PVS-Studio figyelmeztetés: V502 [CWE-783] Talán a ‘?:’ operátor másképp működik, mint ahogy azt várták. A ‘?:’ operátor prioritása alacsonyabb, mint a ‘==’ operátoré. PPCTargetTransformInfo.cpp 404

Véleményem szerint ez egy nagyon szép hiba. Igen, tudom, hogy nekem furcsa elképzeléseim vannak a szépségről :).

Jelenleg a szolgáltatók prioritásainak megfelelően, a kifejezés a következőképpen számítódik ki:

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

Gyakorlati szempontból ez a feltétel értelmetlen, mivel leegyszerűsíthető a következőre:

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

Ez egy nyilvánvaló hiba. Valószínűleg a 0/1-et akarták összehasonlítani a változóval Index. A kód javításához zárójeleket kell hozzáadni a ternáris operátor köré:

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

Egyébként a ternáris operátor nagyon veszélyes, és logikai hibákhoz vezethet. Legyen óvatos vele, és ne sajnálja a zárójeleket használni. Ezt a témát már részletesebben tárgyaltam itt, a „Féljen a ?: operátortól, és zárja le zárójelek közé” fejezetben.

N4, N5 részlet: Nullpointer

Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
  ....
  TypedInit *LHS = dyn_cast(Result);
  ....
  LHS = dyn_cast(
    UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
      ->Fold(CurRec));
  if (!LHS) {
    Error(PasteLoc, Twine("nem lehet átkonvertálni '") + LHS->getAsString() +
                    "'-t stringgé");
    return nullptr;
  }
  ....
}

PVS-Studio figyelmeztetés: V522 [CWE-476] A null pointer ‘LHS’ dereferenciálása megtörténhet. TGParser.cpp 2152

Ha a pointer LHS nulla lesz, figyelmeztetést kellene kiadni. De ahelyett, hogy ez megtörténne, a null pointer dereferenciálása fog történni: LHS->getAsString().

Ez egy tipikus helyzet, amikor a hiba az error handlerben bújik meg, mivel azokat senki sem teszteli. A statikus elemzők az összes elérhető kódot ellenőrzik, függetlenül attól, hogy azt mennyire használják. Ez egy nagyon jó példa arra, hogy a statikus analízis kiegészíti a tesztelési és hibaellenőrzési módszereket.

Hasonló pointer kezelési hiba RHS a kód egy kicsit lejjebb is előfordul: V522 [CWE-476] A null pointer ‘RHS’ dereferenciálása megtörténhet. TGParser.cpp 2186

N6 részlet: Pointer használata a mozgatás után

static Expected
ExtractBlocks(....)
{
  ....
  std::unique_ptr ProgClone = CloneModule(BD.getProgram(), VMap);
  ....
  BD.setNewProgram(std::move(ProgClone));                                // getFunction(MisCompFunctions[i].first);  // <=
    assert(NewF && "Funkció nem található??");
    MiscompiledFunctions.push_back(NewF);
  }
  ....
}

PVS-Studio figyelmeztetés: V522 [CWE-476] A null pointer ‘ProgClone’ dereferenciálása megtörténhet. Miscompilation.cpp 601

Kezdetben az okos pointer ProgClone megszünteti az objektum feletti rendelkezést:

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

Valójában most már ProgClone — ez egy nulla mutató. Ezért alább nulla mutató kiértékelésének kellene végbemennie:

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

De valójában ez nem fog megtörténni! Vegye észre, hogy a ciklus valójában nem fut végig.

A konténer elején MiscompiledFunctions ki van ürítve:

MiscompiledFunctions.clear();

Ezt követően a konténer mérete az ciklus feltételében kerül felhasználásra:

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

Könnyű észrevenni, hogy a ciklus nem indul el. Azt hiszem, ez is hiba, és a kódnak másképp kellene íródnia.

Úgy tűnik, hogy találkoztunk a híres hiba paritásával! Egy hiba elrejti a másikat :).

Fragment N7: Mutató használata áthelyezés után

static Expected TestOptimizer(BugDriver &BD, std::unique_ptr Test,
                                    std::unique_ptr Safe) {
  outs() << "  Tesztelt funkciók optimalizálása: ";
  std::unique_ptr Optimized =
      BD.runPassesOn(Test.get(), BD.getPassesToRun());
  if (!Optimized) {
    errs() << " Hiba a passzek futtatásakor"
           << " a bemeneti programon!n";
    BD.setNewProgram(std::move(Test));                       // <=
    BD.EmitProgressBitcode(*Test, "pass-error", false);      // <=
    if (Error E = BD.debugOptimizerCrash())
      return std::move(E);
    return false;
  }
  ....
}

Figyelmeztetés PVS-Studio: V522 [CWE-476] A ‘Test’ nulla mutató kiértékelése megtörténhet. Miscompilation.cpp 709

Ismét ugyanaz a helyzet. Eleinte az objektum tartalma áthelyezésre kerül, majd úgy használják, mintha semmi sem történt volna. Egyre gyakrabban találkozom ezzel a helyzettel a programok kódjában, mióta a C++ tartalmazza az áthelyezési szemantikát. Ezért szeretem a C++ nyelvet! Mindig új módok találkoznak önmaguk lábának megsebesítésére. A PVS-Studio elemzője mindig lesz munkája :).

Fragment N8: Nulla mutató

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

Figyelmeztetés PVS-Studio: V522 [CWE-476] A ‘Type’ nulla mutató kiértékelése megtörténhet. PrettyFunctionDumper.cpp 233

A hiba kezelők mellett általában a debug adatkiíró funkciókat sem tesztelik. Ez egy tipikus eset. A funkció arra vár, hogy a felhasználó, aki a problémáit akarja megoldani, inkább annak megoldásával kell foglalkoznia.

Helyes:

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

Fragment N9: Nulla mutató

void SearchableTableEmitter::collectTableEntries(
    GenericTable &Table, const std::vector &Items) {
  ....
  RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
  if (!Ty)                                                              // getAsString() + " vs. " +                       // getType()->getAsString());
   ....
}

PVS-Studio figyelmeztetés: V522 [CWE-476] A null pointer ‘Ty’ dereferálása előfordulhat. SearchableTableEmitter.cpp 614

Azt hiszem, ez így világos, nem igényel további magyarázatot.

N10 fragment: Elírás

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

PVS-Studio figyelmeztetés: V570 Az ‘Identifier->Type’ változó saját magához van rendelve. FormatTokenLexer.cpp 249

Nincs értelme a változót saját magának rendelve. Valószínűleg ezt akarták írni:

Identifier->Type = Question->Type;

N11 fragment: Gyanús break

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

PVS-Studio figyelmeztetés: V622 [CWE-478] Érdemes lenne megvizsgálni a ‘switch’ utasítást. Lehet, hogy az első ‘case’ operátor hiányzik. SystemZAsmParser.cpp 652

A kezdetben nagyon gyanús az utasítás break. Nem felejtettünk el valamit ide leírni?

N12 fragment: Mutató ellenőrzése dereferálás után

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

PVS-Studio figyelmeztetés: V595 [CWE-476] A ‘Callee’ mutatót használták, mielőtt ellenőrizték volna a nullptr értéket. Ellenőrizze a következő sorokat: 172, 174. AMDGPUInline.cpp 172

Pointer Callee a funkcióhívás pillanatában dereferálódik getTTI.

És aztán kiderül, hogy ezt a mutatót nullával való egyenlőség ellenőrzéséhez kellene használni nullptr:

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

De már késő…

N13 fragment — N…: Mutató ellenőrzése dereferálás után

A korábban tárgyalt kódrészlet nem egyedi. Megjelenik itt is:

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

PVS-Studio figyelmeztetés: V595 [CWE-476] A ‘CalleeFn’ mutatót használták, mielőtt ellenőrizték volna a nullptr értéket. Ellenőrizze a következő sorokat: 1079, 1081. SimplifyLibCalls.cpp 1079

És itt is:

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

PVS-Studio figyelmeztetés: V595 [CWE-476] Az ‘ND’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 532, 534. SemaTemplateInstantiateDecl.cpp 532

És itt is:

  • V595 [CWE-476] Az ‘U’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 404, 407. DWARFFormValue.cpp 404
  • V595 [CWE-476] Az ‘ND’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Aztán már nem volt kedvem tovább tanulmányozni a V595 számú figyelmeztetéseket. Így nem tudom, van-e még hasonló hiba az itt felsoroltakon kívül. Valószínűleg van.

N17, N18 részlet: Kérdőjeles eltolás

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

PVS-Studio figyelmeztetés: V629 [CWE-190] Fontold meg az ‘~(Size — 1) << 1’ kifejezés ellenőrzését. A 32-bites érték biteltolása, majd kiterjesztése 64-bites típussá. AArch64AddressingModes.h 260

Lehet, hogy ez nem hiba, és a kód valóban így működik, ahogy tervezték. De ez nyilvánvalóan nagyon gyanús rész, és ellenőrizni kell.

Tegyük fel, hogy a változó Méret 16, és akkor a kód szerzője azt tervezte, hogy a változóban NImms értékét kapja:

1111111111111111111111111111111111111111111111111111111111100000

De valójában az alábbi értéket fogjuk kapni:

0000000000000000000000000000000011111111111111111111111111100000

Az a helyzet, hogy minden számítás 32-bites unsigned típussal történik. Csak ezt követően ez a 32-bites előjel nélküli típus implicit módon kiterjed a uint64_ttípusra. E közben a magasabb bitek nullásak lesznek.

A helyzet javítása érdekében az alábbiakat tehetjük:

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

Hasonló helyzet: V629 [CWE-190] Fontold meg az ‘Immr << 6’ kifejezés ellenőrzését. A 32-bites érték biteltolása, majd kiterjesztése 64-bites típussá. AArch64AddressingModes.h 269

N19 részlet: Kulcsszó kihagyva else?

void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
  ....
  if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) {
    // VOP2b (v_add_u32, v_sub_u32 ...) dpp használatnál "vcc" token.
    // Ugrás.
    continue;
  } if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) {    // <=
    Op.addRegWithFPInputModsOperands(Inst, 2);
  } else if (Op.isDPPCtrl()) {
    Op.addImmOperands(Inst, 1);
  } else if (Op.isImm()) {
    // Opcionalis argumentumok kezelése
    OptionalIdx[Op.getImmTy()] = I;
  } else {
    llvm_unreachable("Érvénytelen operandus típus");
  }
  ....
}

PVS-Studio figyelmeztetés: V646 [CWE-670] Fontold meg az alkalmazás logikájának ellenőrzését. Lehetséges, hogy az ‘else’ kulcsszó hiányzik. AMDGPUAsmParser.cpp 5655

Itt nincs hiba. Mivel az első 'then' blokk véget ér a if végződik continue, nem számít, hogy van-e kulcsszó else vagy nincs. Mindenesetre a kód ugyanúgy fog működni. Ennek ellenére a hiányzó else a kódot érthetetlenebbé és veszélyesebbé teszi. Ha ez a jövőben continue eltűnik, a kód teljesen másképp fog működni. Véleményem szerint jobb, ha hozzáadunk else.

N20. töredék: Négy azonos típusú elírás

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

PVS-Studio figyelmeztetések:

  • V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + Name.str()' kifejezés ellenőrzését. Symbol.cpp 32
  • V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC Osztály) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 35
  • V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC Osztály EH) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 38
  • V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC IVar) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 41

Véletlenül a += operátor helyett a + operátort használják. Ennek következtében értelmetlen konstrukciók keletkeznek.

N21. töredék: Meghatározatlan viselkedés

static void getReqFeatures(std::map &FeaturesMap,
                           const std::vector &ReqFeatures) {
  for (auto &R : ReqFeatures) {
    StringRef AsmCondString = R->getValueAsString("AssemblerCondString");

    SmallVector Ops;
    SplitString(AsmCondString, Ops, ",");
    assert(!Ops.empty() && "AssemblerCondString nem lehet üres");

    for (auto &Op : Ops) {
      assert(!Op.empty() && "Üres operátor");
      if (FeaturesMap.find(Op) == FeaturesMap.end())
        FeaturesMap[Op] = FeaturesMap.size();
    }
  }
}

Próbálja meg saját maga megtalálni a veszélyes kódot. Ez egy kép, ami elvonja a figyelmet, hogy ne nézzünk rá azonnal a válaszra:

Buggokat találunk az LLVM 8-ban a PVS-Studio elemző segítségével

PVS-Studio figyelmeztetés: V708 [CWE-758] Veszélyes konstrukciót használnak: 'FeaturesMap[Op] = FeaturesMap.size()', ahol a 'FeaturesMap' a 'map' osztályhoz tartozik. Ez meghatározatlan viselkedéshez vezethet. RISCVCompressInstEmitter.cpp 490

Problémás sor:

FeaturesMap[Op] = FeaturesMap.size();

Ha az elem Op nem található, új elemet hoznak létre a térképen, amihez a térkép elemeinek számát írják. Csak az nem ismert, hogy a funkció méret meghívásra kerül-e az új elem hozzáadása előtt vagy után.

N22-N24. töredék: Ismételt hozzárendelések

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

PVS-Studio figyelmeztetés: V519 [CWE-563] A ‘NType’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 1663, 1664. MachOObjectFile.cpp 1664

Azt hiszem, itt nincs valódi hiba. Csak egy felesleges ismétlődő hozzárendelés van. De így is ügyetlen.

Hasonlóképpen:

  • V519 [CWE-563] A ‘B.NDesc’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] A változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 59, 61. coff2yaml.cpp 61

N25-N27 fragment: Még több ismétlődő hozzárendelés

Most egy kicsit más típusú ismétlődő hozzárendelést fogunk megvizsgálni.

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

PVS-Studio figyelmeztetés: V519 [CWE-563] Az ‘Alignment’ változó kétszer egymás után értéket kap. Talán ez hibás. Ellenőrizd a következő sorokat: 1158, 1160. LoadStoreVectorizer.cpp 1160

Ez egy nagyon furcsa kód, amely nyilvánvalóan logikai hibát tartalmaz. Elején a változó Alignment értéket kap egy feltétel alapján. Aztán ismét hozzárendelés történik, de most mindenféle ellenőrzés nélkül.

Hasonló helyzetek találhatók itt:

  • V519 [CWE-563] Az ‘Effects’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Az ‘ExpectNoDerefChunk’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 4970, 4973. SemaType.cpp 4973

N28 fragment: Mindig igaz feltétel

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 utasítás támogatás // <=
      break;
  }
  ....
}

PVS-Studio figyelmeztetés: V547 [CWE-571] Az ‘nextByte != 0x90’ kifejezés mindig igaz. X86DisassemblerDecoder.cpp 379

Az ellenőrzésnek nincs értelme. A ‘nextByte’ változó mindig nem egyenlő az értékkel , ami a korábbi ellenőrzésből következik. Ez egy logikai hiba. 0x90N29 - N… fragment: Mindig igaz/hamis feltételek

Az elemző sok figyelmeztetést ad arról, hogy az egész feltétel (

) vagy annak része (V547) vagy annak része (V560) mindig igaz vagy hamis. Gyakran nem igazi hibák, hanem csupán hanyag kód, makrók kibővítésének eredménye és hasonlók. Mindazonáltal érdemes megnézni ezeket a figyelmeztetéseket, mert időnként valódi logikai hibák is előfordulnak. Például gyanús ez a kódrészlet:

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

PVS-Studio figyelmeztetés: V560 [CWE-570] A feltételes kifejezés egy része mindig hamis: RegNo == 0xe. ARMDisassembler.cpp 939

A 0xE konstanta a tizedes rendszerben 14-es értéket képvisel. Ellenőrzés RegNo == 0xe nincs értelme, mert ha RegNo > 13, akkor a függvény befejezi a végrehajtást.

Sok más figyelmeztetés is volt V547 és V560 azonosítóval, de akárcsak a V595, számomra unalmas volt ezeket a figyelmeztetéseket tanulmányozni. Így is egyértelmű volt, hogy elég anyagom van egy cikk írásához :). Ezért nem tudni, hogy összesen mennyi ilyen hibát lehet felfedezni az LLVM-ben a PVS-Studio segítségével.

Megmutatok egy példát, miért unalmas ezeket a figyelmeztetéseket vizsgálni. Az elemző teljesen jogosan ad ki figyelmeztetést a következő kódra. De ez nem is hiba.

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

PVS-Studio figyelmeztetés: V547 [CWE-570] Kifejezés ‘!HasError’ mindig hamis. UnwrappedLineParser.cpp 1635

N30 szakasz: Gyanús visszaadás

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

PVS-Studio figyelmeztetés: V612 [CWE-670] Egy feltétel nélküli ‘return’ egy cikluson belül. R600OptimizeVectorRegisters.cpp 63

Ez vagy hiba, vagy egy specifikus trükk, amely valamit magyaráz a kódot olvasó programozóknak. Számomra egy ilyen konstrukció semmit sem magyaráz, és nagyon gyanúsan néz ki. Jobb, ha nem így írunk :).

Fáradt vagy? Akkor itt az idő, hogy főzz egy csésze teát vagy kávét.

Buggokat találunk az LLVM 8-ban a PVS-Studio elemző segítségével

Az új diagnosztikák által felfedezett hibák

Azt hiszem, a 30 régi diagnosztika elég. Nézzük tehát meg, hogy milyen érdekes dolgokat találhatunk új diagnosztikák segítségével, amelyek már az elemzőbe kerültek a korábbi ellenőrzés után. Ez idő alatt összesen 66 általános diagnosztika került be a C++ elemzőbe.

N31 szakasz: Elérhetetlen kód

Hiba CtorDtorRunner::run() {
  ....
  ha auto CtorDtorMap =
          ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names),
                    NoDependenciesToRegister, true))
  {
    ....
    vissza Error::success();
  } máskülönben
    vissza CtorDtorMap.takeError();

  CtorDtorsByPriority.clear();

  vissza Error::success();
}

PVS-Studio figyelmeztetés: V779 [CWE-561] Elérhetetlen kód észlelve. Lehetséges, hogy hiba áll fenn. ExecutionUtils.cpp 146

Ahogy látja, az operátor mindkét ága if a hívás végén ér véget return. Ennek megfelelően a tároló CtorDtorsByPriority soha nem lesz törölve.

N32 szakasz: Elérhetetlen kód

bool LLParser::ParseSummaryEntry() {
  ....
  switch (Lex.getKind()) {
  case lltok::kw_gv:
    vissza ParseGVEntry(SummaryID);
  case lltok::kw_module:
    vissza ParseModuleEntry(SummaryID);
  case lltok::kw_typeid:
    vissza ParseTypeIdEntry(SummaryID);                        
    break;                                                     
  default:
    vissza Error(Lex.getLoc(), "váratlan összegzés típusa");
  }
  Lex.setIgnoreColonInIdentifiers(false);                      
  vissza false;
}

PVS-Studio figyelmeztetés: V779 [CWE-561] Elérhetetlen kód észlelve. Lehetséges, hogy hiba áll fenn. LLParser.cpp 835

Érdekes helyzet. Nézzük meg először ezt a részt:

vissza ParseTypeIdEntry(SummaryID);
break;

Első pillantásra úgy tűnik, hogy itt nincs hiba. Úgy tűnik, hogy az operátor break itt felesleges, és egyszerűen eltávolítható. Azonban nem minden olyan egyszerű.

Az elemző figyelmeztetést ad a következő sorokra:

Lex.setIgnoreColonInIdentifiers(false);
vissza false;

És valóban, ez a kód elérhetetlen. Minden eset a switch az operátor hívásával ér véget. returnÉs most az értelmetlen magányos break nem tűnik oly ártalmatlannak! Talán az egyik ágnak azzal kellene végződnie, break, nem pedig return?

N33 szakasz: Véletlenszerű magasabb bitek nullázása

unsigned getStubAlignment() felülírva {
  ha (Arch == Triple::systemz)
    vissza 8;
  else
    vissza 1;
}

Expected
RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
                             const SectionRef &Section,
                             bool IsCode) {
  ....
  uint64_t DataSize = Section.getSize();
  ....
  ha (StubBufSize > 0)
    DataSize &= ~(getStubAlignment() - 1);
  ....
}

PVS-Studio figyelmeztetés: V784 A bitmaszk mérete kisebb, mint az első operandus mérete. Ez a magasabb bitek elvesztését okozza. RuntimeDyld.cpp 815

Vegye figyelembe, hogy a funkció getStubAlignment visszatér a típussal unsigned. Számoljuk ki a kifejezés értékét, ha feltételezzük, hogy a funkció 8-at ad vissza:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFF8‬u

Most vegye figyelembe, hogy a változó DataSize 64-bites előjeltelen típussal rendelkezik. Így amikor a DataSize & 0xFFFFFFF8‬u műveletet végezzük, a harminckét magasabb bit nullázódik. Valószínűleg nem ez volt a programozó szándéka. Gyanítom, hogy azt akarta számolni: DataSize & 0xFFFFFFFFFFFFFFF8‬u.

A hiba kijavításához így kell írni:

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

Vagy így:

Adatméret &= ~(getStubAlignment() - 1ULL);

N34. sz. töredék: Hibás típus átkonvertálás

sablon <typename T>
visszaad void scaleShuffleMask(int Scale, ArrayRef<T> Mask,
                      SmallVectorImpl<T> &ScaledMask) {
  assert(0 < Scale && "Váratlan méretezési tényező");
  int NumElts = Mask.size();
  ScaledMask.assign(static_cast<size_t>(NumElts * Scale), -1);
  ....
}

PVS-Studio figyelmeztetés: V1028 [CWE-190] Lehetséges túlfolyás. Fontolja meg, hogy az 'NumElts * Scale' operátor operandusait a 'size_t' típusra konvertálja, ne az eredményt. X86ISelLowering.h 1577

A típus explicit átkonvertálása azért szükséges, hogy elkerüljük a túlfolyást a változók szorzása során. egész. Azonban itt az explicit átkonvertálás nem véd meg a túlfolyástól. Először a változók szorzódnak, és csak aztán a 32 bites szorzat kiterjesztésre kerül a típusra. size_t.

N35. sz. töredék: Hibás másolás-beillesztés

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] Két hasonló kódtöredéket találtak. Talán elírás történt, és az 'Op1' változót kellene használni az 'Op0' helyett. InstCombineCompares.cpp 5507

Ez az új, érdekes diagnózis feltárja azokat a helyzeteket, amikor a kódtöredék másolásra került, és kezdték megváltoztatni a neveket, de egy helyen nem módosították.

Ne feledje, hogy a második blokkban megváltoztatták Op0 Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata Op1. De egy helyen nem módosították. Valószínűleg így kellett volna írni:

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

N36. sz. töredék: Zavar a változókban

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

PVS-Studio figyelmeztetés: V1001 [CWE-563] A 'Mode' változó értéket kap, de a funkció végéig nem használják. SIModeRegister.cpp 48

Nagyon veszélyes az, ha a funkciók argumentumai ugyanazt a nevet kapják, mint az osztály tagjai. Nagyon könnyen zavarba ejtő lehet. Ez éppen ilyen eset.

Mode &= Mask;

Megváltozik a funkció argumentuma. És ennyi. Ez az argumentum másfelé nem kerül felhasználásra. Valószínűleg így kellett volna írni:

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

N37. sz. töredék: Zavar a változókban

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(Sym));
  Size += this->EntrySize;
}

Figyelmeztetés PVS-Studio: V1001 [CWE-563] A ‘Size’ változó értéket kap, de a függvény végére nem használják fel. Object.cpp 424

A helyzet hasonló az előzőhöz. Így kellene írni:

this->Size += this->EntrySize;

N38-N47 szakasz: A mutatót elfelejtették ellenőrizni

Korábban már tárgyaltuk a diagnosztika működésének példáit V595. Lényege, hogy a mutatót először dereferálják, majd csak ezután ellenőrzik. Új diagnosztika V1004 az ellentéte a fentieknek, de szintén sok hibát észlel. Ezekben az esetekben a mutatót először ellenőrizték, majd elfelejtették ezt megtenni. Tekintsünk meg ilyen eseteket, amelyeket az LLVM-ben találtak.

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

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

Figyelmeztetés PVS-Studio: V1004 [CWE-476] A ‘Ptr’ mutatót biztonságtalanul használták, miután ellenőrizték, hogy nem nullptr. Ellenőrizze a sorokat: 729, 738. TargetTransformInfoImpl.h 738

Változó Ptr lehet egyenlő nullptr, amire az ellenőrzés utal:

if (Ptr != nullptr)

Azonban alább ez a mutató már ellenőrzés nélkül van dereferálva:

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

Nézzük meg egy másik hasonló esetet.

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

Figyelmeztetés PVS-Studio: V1004 [CWE-476] A ‘FD’ mutatót biztonságtalanul használták, miután ellenőrizték, hogy nem nullptr. Ellenőrizze a sorokat: 3228, 3231. CGDebugInfo.cpp 3231

Figyeljen a mutatóra FD. Biztos vagyok benne, hogy a probléma jól látható, és nincs szükség külön magyarázatra.

És még:

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

PVS-Studio figyelmeztetés: V1004 [CWE-476] A 'PtrTy' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 960, 965. InterleavedLoadCombinePass.cpp 965

Hogyan védekezhetünk az ilyen hibák ellen? Legyen figyelmes a kódellenőrzésnél, és használjon statikus kódelemzőt, mint a PVS-Studio.

Nincs értelme a hasonló típusú hibákkal rendelkező egyéb kódszeletek bemutatásának. Csak a figyelmeztetések listáját hagyom meg a cikkben:

  • V1004 [CWE-476] Az 'Expr' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] A 'PI' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] A 'StatepointCall' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Az 'RV' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] A 'CalleeFn' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] A 'TC' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1819, 1824. Driver.cpp 1824

N48-N60 szakasz: Nem kritikus, de hiba (memóriaszivárgás előfordulhat)

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

PVS-Studio figyelmeztetés: V1023 [CWE-460] Egy tulajdonos nélküli pointer került a ‘Strategies’ tárolóba az ’emplace_back’ metódussal. Memóriaszivárgás fog bekövetkezni, ha kivétel történik. llvm-isel-fuzzer.cpp 58

Elem hozzáadása a következő típusú tárolóhoz std::vector<std::unique_ptr> nem lehet egyszerűen megírni xxx.push_back(new X), mivel nincs implicit konvertálás a X* be. std::unique_ptr.

Általános megoldás az, hogy megírjuk xxx.emplace_back(new X), mivel ez fordítható: az 'emplace_back' metódus az elemet közvetlenül az argumentumból építi fel, így használhatja az explicit konstruktőröket. Ez nem biztonságos. Ha a vektor tele van, memóriaújralokás történik. A memóriaújralokás művelete kudarcot vallhat, ami kivétel generálását eredményezheti.

std::bad_alloc . Ebben az esetben a pointer elveszik, és a létrehozott objektum soha nem lesz törölve.A biztonságos megoldás az, hogy létrehozunk egy

unique_ptr , amely birtokolja a pointert, mielőtt a vektor megpróbálná újraallokálni a memóriát:, amely a mutatót birtokolja, mielőtt a vektor megpróbálja újraallokálni a memóriát:

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

A C++14-től használhatjuk a 'std::make_unique' használatát:

xxx.push_back(std::make_unique())

Ez a hibafajta nem kritikus az LLVM számára. Ha nem sikerül memóriát allokálni, a fordító működése egyszerűen leáll. Azonban, ha egy alkalmazás hosszú futási idővel rendelkezik, amely nem tud egyszerűen leállni, ha nem sikerül memóriát allokálni, ez valódi kellemetlen hibát okozhat.

Tehát, bár ez a kód nem jelent gyakorlati veszélyt az LLVM számára, hasznosnak találtam beszámolni erről a hiba mintáról, és arról, hogy a PVS-Studio elemzője képes azt észlelni.

Egyéb, hasonló figyelmeztetések:

  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Passes' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. PassManager.h 546
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'AAs' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. AliasAnalysis.h 324
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'Entries' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'AllEdges' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. CFGMST.h 268
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'VMaps' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Records' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. FDRLogBuilder.h 30
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'PendingSubmodules' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. ModuleMap.cpp 810
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'Objects' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. DebugMap.cpp 88
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Strategies' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 685
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 686
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 688
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 689
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 690
  • V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 691
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 692
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 693
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 694
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra az 'Operands' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Stash' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Matchers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 2702

Zárás

Összesen 60 figyelmeztetést írtam ki, majd leálltam. Vannak más hibák is, amelyeket az LLVM PVS-Studio elemzője felfedez? Igen, vannak. Azonban, amikor a cikkhez a kód részleteit írtam, késő este, sőt, már éjszaka volt, és úgy döntöttem, hogy itt az ideje befejezni.

Remélem, érdekesnek találta, és ki szeretné próbálni a PVS-Studio elemzőt.

Le tudja tölteni az elemzőt és kaphat egy ideiglenes kulcsot a következő címen az oldalon.

A legfontosabb, hogy rendszeresen használja a statikus elemzést. Egyszeri ellenőrzések, amelyeket az általunk a statikus elemzés és a PVS-Studio népszerűsítése érdekében végzünk, nem számít normális forgatókönyvnek.

Sok sikert a kód minőségének és megbízhatóságának javításához!

Buggokat találunk az LLVM 8-ban a PVS-Studio elemző segítségével

Ha meg szeretné osztani ezt a cikket angol nyelvű közönséggel, kérjük, használja a fordítás hivatkozását: Andrey Karpov. Bugs keresése az LLVM 8-ban a PVS-Studio segítségével.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster