Vind foute in LLVM 8 met behulp van die PVS-Studio-ontleder

Vind foute in LLVM 8 met behulp van die PVS-Studio-ontleder
Meer as twee jaar het verloop sedert die laaste kodekontrolering van die LLVM-projek met ons PVS-Studio-ontleder. Kom ons maak seker dat die PVS-Studio-ontleder steeds 'n toonaangewende hulpmiddel is om foute en potensiële kwesbaarhede te identifiseer. Om dit te doen, sal ons nuwe foute in die LLVM 8.0.0-vrystelling nagaan en vind.

Artikel wat geskryf moet word

Om eerlik te wees, ek wou nie hierdie artikel skryf nie. Dit is nie interessant om te skryf oor 'n projek wat ons al verskeie kere nagegaan het nie (1, 2, 3). Dit is beter om oor iets nuuts te skryf, maar ek het geen keuse nie.

Elke keer as 'n nuwe weergawe van LLVM vrygestel of opgedateer word Clang statiese ontleder, ontvang ons vrae van die volgende tipe in ons pos:

Kyk, die nuwe weergawe van Clang Static Analyzer het geleer om nuwe foute te vind! Dit lyk vir my dat die relevansie van die gebruik van PVS-Studio afneem. Clang vind meer foute as voorheen en haal die vermoëns van PVS-Studio in. Wat dink jy hiervan?

Hierop wil ek altyd iets antwoord soos:

Ons sit ook nie ledig nie! Ons het die vermoëns van die PVS-Studio-ontleder aansienlik verbeter. So moenie bekommerd wees nie, ons gaan voort om te lei soos voorheen.

Ongelukkig is dit 'n slegte antwoord. Daar is geen bewyse daarin nie. En dit is hoekom ek nou hierdie artikel skryf. So, die LLVM-projek is weereens nagegaan en 'n verskeidenheid foute is daarin gevind. Ek sal nou diegene demonstreer wat vir my interessant gelyk het. Clang Static Analyzer kan nie hierdie foute vind nie (of dit is uiters ongerieflik om dit met sy hulp te doen). Maar ons kan. Boonop het ek al hierdie foute in een aand gevind en neergeskryf.

Maar die skryf van die artikel het etlike weke geneem. Ek kon myself net nie sover kry om dit alles in teks te plaas nie :).

Terloops, as jy belangstel in watter tegnologieë in die PVS-Studio-ontleder gebruik word om foute en potensiële kwesbaarhede te identifiseer, stel ek voor om hiermee kennis te maak let op.

Nuwe en ou diagnostiek

Soos reeds opgemerk, is die LLVM-projek sowat twee jaar gelede weer nagegaan, en die foute wat gevind is, is reggestel. Nou sal hierdie artikel 'n nuwe reeks foute aanbied. Hoekom is nuwe foute gevind? Daar is 3 redes hiervoor:

  1. Die LLVM-projek ontwikkel, verander ou kode en voeg nuwe kode by. Natuurlik is daar nuwe foute in die gewysigde en geskrewe kode. Dit toon duidelik dat statiese analise gereeld gebruik moet word, en nie af en toe nie. Ons artikels wys goed die vermoëns van die PVS-Studio-ontleder, maar dit het niks te doen met die verbetering van kodekwaliteit en die vermindering van die koste om foute reg te stel nie. Gebruik gereeld 'n statiese kode-ontleder!
  2. Ons finaliseer en verbeter bestaande diagnostiek. Daarom kan die ontleder foute identifiseer wat dit nie tydens vorige skanderings opgemerk het nie.
  3. Nuwe diagnostiek het in PVS-Studio verskyn wat 2 jaar gelede nie bestaan ​​het nie. Ek het besluit om hulle in 'n aparte afdeling uit te lig om die ontwikkeling van PVS-Studio duidelik te wys.

Defekte geïdentifiseer deur diagnostiek wat 2 jaar gelede bestaan ​​het

Fragment N1: Copy-Paste

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

PVS-Studio waarskuwing: V501 [CWE-570] Daar is identiese sub-uitdrukkings 'Name.startswith("avx512.mask.permvar.")' links en regs van die '||' operateur. AutoUpgrade.cpp 73

Daar word dubbel gekontroleer dat die naam met die substring "avx512.mask.permvar." begin. In die tweede tjek wou hulle natuurlik iets anders skryf, maar het vergeet om die gekopieerde teks reg te stel.

Fragment N2: Tikfout

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

Waarskuwing PVS-Studio: V501 Daar is identiese sub-uitdrukkings 'CXNameRange_WantQualifier' links en regs van die '|' operateur. CIndex.cpp 7245

As gevolg van 'n tikfout word dieselfde benoemde konstante twee keer gebruik CXNameRange_WantQualifier.

Fragment N3: Verwarring met operateurvoorrang

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

PVS-Studio waarskuwing: V502 [CWE-783] Miskien werk die '?:'-operateur op 'n ander manier as wat verwag is. Die '?:'-operateur het 'n laer prioriteit as die '=='-operateur. PPCTargetTransformInfo.cpp 404

Na my mening is dit 'n baie mooi fout. Ja, ek weet ek het vreemde idees oor skoonheid :).

Nou, volgens operateur prioriteite, word die uitdrukking soos volg geëvalueer:

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

Uit 'n praktiese oogpunt maak so 'n toestand nie sin nie, aangesien dit gereduseer kan word tot:

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

Dit is 'n duidelike fout. Heel waarskynlik wou hulle 0/1 met 'n veranderlike vergelyk indeks. Om die kode reg te stel, moet jy hakies rondom die ternêre operateur byvoeg:

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

Terloops, die ternêre operateur is baie gevaarlik en lok logiese foute uit. Wees baie versigtig daarmee en moenie gulsig wees met hakies nie. Ek het in meer besonderhede na hierdie onderwerp gekyk hier, in die hoofstuk "Pasop vir die ?: Operator en sluit dit tussen hakies."

Fragment N4, N5: Nulwyser

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

PVS-Studio waarskuwing: V522 [CWE-476] Herverwysing van die nulwyser 'LHS' kan moontlik plaasvind. TGParser.cpp 2152

As die wyser LK nul is, moet 'n waarskuwing uitgereik word. In plaas daarvan sal hierdie selfde nulwyser egter herverwys word: LHS->getAsString().

Dit is 'n baie tipiese situasie wanneer 'n fout in 'n fouthanteerder versteek is, aangesien niemand dit toets nie. Statiese ontleders kontroleer alle bereikbare kode, maak nie saak hoe gereeld dit gebruik word nie. Dit is 'n baie goeie voorbeeld van hoe statiese analise ander toets- en foutbeskermingstegnieke aanvul.

Soortgelyke wyserhanteringsfout RHS toegelaat in die kode net hieronder: V522 [CWE-476] Herverwysing van die nulwyser 'RHS' kan moontlik plaasvind. TGParser.cpp 2186

Fragment N6: Gebruik die wyser na beweging

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

PVS-Studio Waarskuwing: V522 [CWE-476] Herverwysing van die nulwyser 'ProgClone' kan dalk plaasvind. Miscompilation.cpp 601

Aan die begin 'n slim wyser ProgClone hou op om die voorwerp te besit:

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

Trouens, nou ProgClone is 'n nulwyser. Daarom moet 'n nulwyser-verwysing net hieronder voorkom:

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

Maar in werklikheid sal dit nie gebeur nie! Let daarop dat die lus nie werklik uitgevoer word nie.

Aan die begin van die houer Verkeerd saamgestelde funksies skoongemaak:

MiscompiledFunctions.clear();

Vervolgens word die grootte van hierdie houer in die lustoestand gebruik:

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

Dit is maklik om te sien dat die lus nie begin nie. Ek dink dit is ook 'n fout en die kode moet anders geskryf word.

Dit blyk dat ons daardie beroemde gelykheid van foute teëgekom het! Een fout verbloem 'n ander :).

Fragment N7: Gebruik die wyser na beweging

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

PVS-Studio waarskuwing: V522 [CWE-476] Herverwysing van die nulwyser 'Toets' kan dalk plaasvind. Miscompilation.cpp 709

Weereens dieselfde situasie. Aanvanklik word die inhoud van die voorwerp geskuif, en dan word dit gebruik asof niks gebeur het nie. Ek sien hierdie situasie meer en meer dikwels in programkode nadat bewegingsemantiek in C++ verskyn het. Dit is hoekom ek van die C++-taal hou! Daar is al hoe meer nuwe maniere om jou eie been af ​​te skiet. Die PVS-Studio-ontleder sal altyd werk hê :).

Fragment N8: Nulwyser

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

PVS-Studio waarskuwing: V522 [CWE-476] Herverwysing van die nulwyser 'Tipe' kan dalk plaasvind. PrettyFunctionDumper.cpp 233

Benewens fouthanteerders, word ontfoutingsuitdrukfunksies gewoonlik nie getoets nie. Ons het net so 'n saak voor ons. Die funksie wag vir die gebruiker, wat, in plaas daarvan om sy probleme op te los, gedwing sal word om dit reg te stel.

reg te stel:

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

Fragment N9: Nulwyser

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

PVS-Studio waarskuwing: V522 [CWE-476] Herverwysing van die nulwyser 'Ty' kan dalk plaasvind. SearchableTableEmitter.cpp 614

Ek dink alles is duidelik en vereis nie verduideliking nie.

Fragment N10: Tikfout

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 waarskuwing: V570 Die 'Identifier->Type' veranderlike word aan homself toegeken. FormatTokenLexer.cpp 249

Daar is geen sin om 'n veranderlike aan homself toe te ken nie. Heel waarskynlik wou hulle skryf:

Identifier->Type = Question->Type;

Fragment N11: Verdagte breuk

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 waarskuwing: V622 [CWE-478] Oorweeg dit om die 'skakel'-stelling te inspekteer. Dit is moontlik dat die eerste 'geval'-operateur ontbreek. SystemZAsmParser.cpp 652

Daar is 'n baie verdagte operateur aan die begin breek. Het jy vergeet om iets anders hier te skryf?

Fragment N12: Kontroleer 'n wyser na afwysing

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 waarskuwing: V595 [CWE-476] Die 'Callee'-wyser is gebruik voordat dit teen nullptr geverifieer is. Kontroleer reëls: 172, 174. AMDGPUInline.cpp 172

Aanwyser Callee aan die begin word herverwys wanneer die funksie opgeroep word kryTTI.

En dan blyk dit dat hierdie wyser vir gelykheid nagegaan moet word nullptr:

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

Maar dis te laat...

Fragment N13 - N...: Kontroleer 'n wyser na afwysing

Die situasie wat in die vorige kodefragment bespreek is, is nie uniek nie. Dit verskyn hier:

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

PVS-Studio waarskuwing: V595 [CWE-476] Die 'CalleeFn'-wyser is gebruik voordat dit teen nullptr geverifieer is. Kontroleer lyne: 1079, 1081. SimplifyLibCalls.cpp 1079

En hier:

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

PVS-Studio waarskuwing: V595 [CWE-476] Die 'ND'-wyser is gebruik voordat dit teen nullptr geverifieer is. Kontroleer reëls: 532, 534. SemaTemplateInstantiateDecl.cpp 532

En hier:

  • V595 [CWE-476] Die 'U'-wyser is gebruik voordat dit teen nullptr geverifieer is. Kontroleer lyne: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] Die 'ND'-wyser is gebruik voordat dit teen nullptr geverifieer is. Kontroleer reëls: 2149, 2151. SemaTemplateInstantiate.cpp 2149

En toe raak ek nie geïnteresseerd om die waarskuwings met nommer V595 te bestudeer nie. So ek weet nie of daar meer soortgelyke foute is behalwe dié wat hier gelys word nie. Heel waarskynlik is daar.

Fragment N17, N18: Verdagte verskuiwing

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

PVS-Studio waarskuwing: V629 [CWE-190] Oorweeg om die '~(Size - 1) << 1'-uitdrukking te inspekteer. Bietjieverskuiwing van die 32-bis-waarde met 'n daaropvolgende uitbreiding na die 64-bis-tipe. AArch64AddressingModes.h 260

Dit is dalk nie 'n fout nie en die kode werk presies soos bedoel. Maar dit is duidelik 'n baie verdagte plek en moet nagegaan word.

Kom ons sê die veranderlike grootte is gelyk aan 16, en dan het die skrywer van die kode beplan om dit in 'n veranderlike te kry NImms waarde:

1111111111111111111111111111111111111111111111111111111111100000

In werklikheid sal die resultaat egter wees:

0000000000000000000000000000000011111111111111111111111111100000

Die feit is dat alle berekeninge plaasvind met behulp van die 32-bis ongetekende tipe. En eers dan sal hierdie 32-bis ongetekende tipe implisiet uitgebrei word na uint64_t. In hierdie geval sal die belangrikste bisse nul wees.

U kan die situasie soos volg regstel:

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

Soortgelyke situasie: V629 [CWE-190] Oorweeg dit om die 'Immr << 6'-uitdrukking te inspekteer. Bietjieverskuiwing van die 32-bis-waarde met 'n daaropvolgende uitbreiding na die 64-bis-tipe. AArch64AddressingModes.h 269

Fragment N19: Ontbrekende sleutelwoord anders?

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

PVS-Studio waarskuwing: V646 [CWE-670] Oorweeg dit om die toepassing se logika te inspekteer. Dit is moontlik dat 'ander' sleutelwoord ontbreek. AMDGPUAsmParser.cpp 5655

Hier is geen fout nie. Sedert die destydse blok van die eerste if eindig met voortgaan, dan maak dit nie saak nie, daar is 'n sleutelwoord anders of nie. In elk geval sal die kode dieselfde werk. Nog steeds gemis anders maak die kode meer onduidelik en gevaarlik. As in die toekoms voortgaan verdwyn, sal die kode heeltemal anders begin werk. Na my mening is dit beter om by te voeg anders.

Fragment N20: Vier tikfoute van dieselfde tipe

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

PVS-Studio waarskuwings:

  • V655 [CWE-480] Die snare is aaneengeskakel, maar word nie gebruik nie. Oorweeg om die 'Result + Name.str()'-uitdrukking te inspekteer. Symbol.cpp 32
  • V655 [CWE-480] Die snare is aaneengeskakel, maar word nie gebruik nie. Oorweeg om die 'Result + "(ObjC Class)" + Name.str()' uitdrukking te inspekteer. Symbol.cpp 35
  • V655 [CWE-480] Die snare is aaneengeskakel, maar word nie gebruik nie. Oorweeg om die 'Resultaat + "(ObjC Klas EH)" + Name.str()' uitdrukking te inspekteer. Symbol.cpp 38
  • V655 [CWE-480] Die snare is aaneengeskakel, maar word nie gebruik nie. Oorweeg om die 'Resultaat + "(ObjC IVar)" + Name.str()' uitdrukking te inspekteer. Symbol.cpp 41

Per ongeluk word die +-operateur gebruik in plaas van die +=-operateur. Die resultaat is ontwerpe wat sonder betekenis is.

Fragment N21: Ongedefinieerde gedrag

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

Probeer self die gevaarlike kode vind. En dit is 'n prentjie om die aandag af te lei om nie dadelik na die antwoord te kyk nie:

Vind foute in LLVM 8 met behulp van die PVS-Studio-ontleder

PVS-Studio waarskuwing: V708 [CWE-758] Gevaarlike konstruksie word gebruik: 'FeaturesMap[Op] = FeaturesMap.size()', waar 'FeaturesMap' van 'kaart'-klas is. Dit kan lei tot ongedefinieerde gedrag. RISCVCompressInstEmitter.cpp 490

Probleemlyn:

FeaturesMap[Op] = FeaturesMap.size();

As element Op gevind word nie, word 'n nuwe element in die kaart geskep en die aantal elemente in hierdie kaart word daar geskryf. Dit is net onbekend of die funksie geroep sal word grootte voor of na die byvoeging van 'n nuwe element.

Fragment N22-N24: Herhaalde opdragte

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

PVS-Studio waarskuwing: V519 [CWE-563] Die 'Ntype'-veranderlike word twee keer agtereenvolgens waardes toegeken. Miskien is dit 'n fout. Kontroleer reëls: 1663, 1664. MachOObjectFile.cpp 1664

Ek dink nie hier is 'n werklike fout nie. Net 'n onnodige herhaalde opdrag. Maar steeds 'n flater.

Net so:

  • V519 [CWE-563] Die 'B.NDesc' veranderlike word twee keer agtereenvolgens aan waardes toegeken. Miskien is dit 'n fout. Kontroleer lyne: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Die veranderlike word twee keer agtereenvolgens waardes toegeken. Miskien is dit 'n fout. Kontroleer reëls: 59, 61. coff2yaml.cpp 61

Fragment N25-N27: Nog hertoewysings

Kom ons kyk nou na 'n effens ander weergawe van hertoewysing.

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

PVS-Studio waarskuwing: V519 [CWE-563] Die 'Alignment'-veranderlike word twee keer agtereenvolgens aan waardes toegeken. Miskien is dit 'n fout. Kontroleer lyne: 1158, 1160. LoadStoreVectorizer.cpp 1160

Dit is baie vreemde kode wat blykbaar 'n logiese fout bevat. Aan die begin, veranderlike Alignment 'n waarde word toegeken na gelang van die toestand. En dan kom die opdrag weer voor, maar nou sonder enige kontrole.

Soortgelyke situasies kan hier gesien word:

  • V519 [CWE-563] Die 'Effekte'-veranderlike word twee keer agtereenvolgens aan waardes toegeken. Miskien is dit 'n fout. Kontroleer reëls: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Die 'ExpectNoDerefChunk'-veranderlike word twee keer agtereenvolgens aan waardes toegeken. Miskien is dit 'n fout. Kontroleer lyne: 4970, 4973. SemaType.cpp 4973

Fragment N28: Altyd ware toestand

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

PVS-Studio waarskuwing: V547 [CWE-571] Uitdrukking 'nextByte != 0x90' is altyd waar. X86DisassemblerDecoder.cpp 379

Om na te gaan maak nie sin nie. Veranderlik volgende Byte altyd nie gelyk aan die waarde nie 0x90, wat uit die vorige kontrole volg. Dit is 'n soort logiese fout.

Fragment N29 - N...: Altyd waar/onwaar toestande

Die ontleder gee baie waarskuwings dat die hele toestand (V547) of deel daarvan (V560) is altyd waar of onwaar. Dikwels is dit nie werklike foute nie, maar bloot slordige kode, die gevolg van makro-uitbreiding, en dies meer. Dit maak egter sin om na al hierdie waarskuwings te kyk, aangesien ware logiese foute wel van tyd tot tyd voorkom. Byvoorbeeld, hierdie gedeelte van die kode is verdag:

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 waarskuwing: V560 [CWE-570] 'n Deel van voorwaardelike uitdrukking is altyd onwaar: RegNo == 0xe. ARMDisassembler.cpp 939

Die konstante 0xE is die waarde 14 in desimale. Eksamen RegNo == 0xe maak nie sin nie, want as RegNo > 13, dan sal die funksie sy uitvoering voltooi.

Daar was baie ander waarskuwings met ID's V547 en V560, maar soos met V595, Ek het nie daarin belang gestel om hierdie waarskuwings te bestudeer nie. Dit was reeds duidelik dat ek genoeg materiaal het om 'n artikel te skryf :). Daarom is dit onbekend hoeveel foute van hierdie tipe in LLVM met behulp van PVS-Studio geïdentifiseer kan word.

Ek sal jou 'n voorbeeld gee van hoekom dit vervelig is om hierdie snellers te bestudeer. Die ontleder is heeltemal reg om 'n waarskuwing vir die volgende kode uit te reik. Maar dit is nie 'n fout nie.

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

PVS-Studio Waarskuwing: V547 [CWE-570] Uitdrukking '!HasError' is altyd onwaar. UnwrappedLineParser.cpp 1635

Fragment N30: ​​Verdagte terugkeer

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 waarskuwing: V612 [CWE-670] 'n Onvoorwaardelike 'terugkeer' binne 'n lus. R600OptimizeVectorRegisters.cpp 63

Dit is óf 'n fout óf 'n spesifieke tegniek wat bedoel is om iets te verduidelik aan programmeerders wat die kode lees. Hierdie ontwerp verduidelik niks aan my nie en lyk baie verdag. Dit is beter om nie so te skryf nie :).

Moeg? Dan is dit tyd om tee of koffie te maak.

Vind foute in LLVM 8 met behulp van die PVS-Studio-ontleder

Defekte geïdentifiseer deur nuwe diagnostiek

Ek dink 30 aktiverings van ou diagnostiek is genoeg. Kom ons kyk nou watter interessante dinge kan gevind word met die nuwe diagnostiek wat daarna in die ontleder verskyn het vorige tjeks. Gedurende hierdie tyd is 'n totaal van 66 algemene doeldiagnostieke by die C++-ontleder gevoeg.

Fragment N31: Onbereikbare kode

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

PVS-Studio waarskuwing: V779 [CWE-561] Onbereikbare kode bespeur. Dit is moontlik dat 'n fout teenwoordig is. ExecutionUtils.cpp 146

Soos jy kan sien, beide takke van die operateur if eindig met 'n oproep na die operateur terugkeer. Gevolglik het die houer Rektor volgens Prioriteit sal nooit skoongemaak word nie.

Fragment N32: Onbereikbare kode

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

PVS-Studio waarskuwing: V779 [CWE-561] Onbereikbare kode bespeur. Dit is moontlik dat 'n fout teenwoordig is. LLParser.cpp 835

Interessante situasie. Kom ons kyk eers na hierdie plek:

return ParseTypeIdEntry(SummaryID);
break;

Met die eerste oogopslag blyk dit dat hier geen fout is nie. Dit lyk soos die operateur breek daar is 'n ekstra een hier, en jy kan dit eenvoudig uitvee. Maar nie alles so eenvoudig nie.

Die ontleder gee 'n waarskuwing op die lyne:

Lex.setIgnoreColonInIdentifiers(false);
return false;

En inderdaad, hierdie kode is onbereikbaar. Alle gevalle in skakel eindig met 'n oproep van die operateur terugkeer. En nou sinneloos alleen breek lyk nie so onskadelik nie! Miskien moet een van die takke eindig met breekmaar nie aan nie terugkeer?

Fragment N33: Willekeurige terugstelling van hoë bisse

unsigned getStubAlignment() override {
  if (Arch == Triple::systemz)
    return 8;
  else
    return 1;
}

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

PVS-Studio waarskuwing: V784 Die grootte van die bitmasker is kleiner as die grootte van die eerste operand. Dit sal die verlies van hoër bisse veroorsaak. RuntimeDyld.cpp 815

Neem asseblief kennis dat die funksie getStubAlignment opbrengs tipe unsigned. Kom ons bereken die waarde van die uitdrukking, met die veronderstelling dat die funksie die waarde 8 gee:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFFF8u

Let nou op dat die veranderlike Datagrootte het 'n 64-bis ongetekende tipe. Dit blyk dat wanneer die DataSize & 0xFFFFFFF8u-bewerking uitgevoer word, al twee en dertig hoë-orde bisse na nul teruggestel sal word. Dit is waarskynlik nie wat die programmeerder wou hê nie. Ek vermoed dat hy wou bereken: DataSize & 0xFFFFFFFFFFFFFFFFF8u.

Om die fout reg te stel, moet jy dit skryf:

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

Of so:

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

Fragment N34: Mislukte eksplisiete tipe cast

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

PVS-Studio waarskuwing: V1028 [CWE-190] Moontlike oorloop. Oorweeg dit om operandes van die 'NumElts * Skaal'-operateur na die 'size_t'-tipe te gooi, nie die resultaat nie. X86ISelLowering.h 1577

Eksplisiete tipe gietwerk word gebruik om oorloop te vermy wanneer tipe veranderlikes vermenigvuldig word int. Eksplisiete tipe gietwerk hier beskerm egter nie teen oorloop nie. Eerstens sal die veranderlikes vermenigvuldig word, en eers dan sal die 32-bis resultaat van die vermenigvuldiging uitgebrei word na die tipe size_t.

Fragment N35: Mislukte kopieer-plak

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] Twee soortgelyke kodefragmente is gevind. Miskien is dit 'n tikfout en 'Op1' veranderlike moet gebruik word in plaas van 'Op0'. InstCombineCompares.cpp 5507

Hierdie nuwe interessante diagnostiek identifiseer situasies waar 'n stukkie kode gekopieer is en sommige name daarin begin verander het, maar op een plek het hulle dit nie reggestel nie.

Neem asseblief kennis dat hulle in die tweede blok verander het Op0 op Op1. Maar op een plek het hulle dit nie reggemaak nie. Heel waarskynlik moes dit so geskryf gewees het:

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

Fragment N36: Veranderlike verwarring

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

PVS-Studio waarskuwing: V1001 [CWE-563] Die 'Mode'-veranderlike word toegeken, maar word nie teen die einde van die funksie gebruik nie. SIModeRegister.cpp 48

Dit is baie gevaarlik om funksie-argumente dieselfde name as klaslede te gee. Dit is baie maklik om deurmekaar te raak. Ons het net so 'n saak voor ons. Hierdie uitdrukking maak nie sin nie:

Mode &= Mask;

Die funksie-argument verander. Dis al. Hierdie argument word nie meer gebruik nie. Heel waarskynlik moes jy dit so geskryf het:

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

Fragment N37: Veranderlike verwarring

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

Waarskuwing PVS-Studio: V1001 [CWE-563] Die 'Size'-veranderlike is toegeken, maar word nie teen die einde van die funksie gebruik nie. Object.cpp 424

Die situasie is soortgelyk aan die vorige een. Dit moet geskryf word:

this->Size += this->EntrySize;

Fragment N38-N47: Hulle het vergeet om die indeks na te gaan

Voorheen het ons gekyk na voorbeelde van diagnostiese snellers V595. Die essensie daarvan is dat die wyser aan die begin afgewys word, en dan eers nagegaan word. Jong diagnostiek V1004 is die teenoorgestelde in betekenis, maar openbaar ook baie foute. Dit identifiseer situasies waar die wyser aan die begin nagegaan is en toe vergeet het om dit te doen. Kom ons kyk na sulke gevalle wat binne LLVM gevind word.

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

PVS-Studio waarskuwing: V1004 [CWE-476] Die 'Ptr'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 729, 738. TargetTransformInfoImpl.h 738

veranderlike ptr gelyk kan wees nullptr, soos blyk uit die tjek:

if (Ptr != nullptr)

Onder hierdie wyser word egter afgewys sonder om vooraf na te gaan:

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

Kom ons kyk na 'n ander soortgelyke geval.

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

PVS-Studio waarskuwing: V1004 [CWE-476] Die 'FD'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 3228, 3231. CGDebugInfo.cpp 3231

Gee aandag aan die teken FD. Ek is seker die probleem is duidelik sigbaar en geen spesiale verduideliking is nodig nie.

En verder:

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

PVS-Studio waarskuwing: V1004 [CWE-476] Die 'PtrTy'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 960, 965. InterleavedLoadCombinePass.cpp 965

Hoe om jouself te beskerm teen sulke foute? Wees meer oplettend oor Code-Review en gebruik die PVS-Studio statiese ontleder om gereeld jou kode na te gaan.

Daar is geen sin om ander kodefragmente met foute van hierdie tipe aan te haal nie. Ek sal slegs 'n lys van waarskuwings in die artikel laat:

  • V1004 [CWE-476] Die 'Expr'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer reëls: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Die 'PI'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Die 'StatepointCall'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Die 'RV'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Die 'CalleeFn'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Die 'TC'-wyser is onveilig gebruik nadat dit teen nullptr geverifieer is. Kontroleer lyne: 1819, 1824. Driver.cpp 1824

Fragment N48-N60: Nie krities nie, maar 'n defek (moontlike geheuelek)

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

PVS-Studio waarskuwing: V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Strategieë'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-isel-fuzzer.cpp 58

Om 'n element aan die einde van 'n houer te voeg soos std::vektor > jy kan nie net skryf nie xxx.push_back(nuwe X), aangesien daar geen implisiete omskakeling van X* в std::unieke_ptr.

'n Algemene oplossing is om te skryf xxx.emplace_back(nuwe X)aangesien dit saamstel: metode plaas_terug konstrueer 'n element direk uit sy argumente en kan dus eksplisiete konstruktors gebruik.

Dit is nie veilig nie. As die vektor vol is, word geheue hertoegewys. Die geheuehertoewysingsbewerking kan moontlik misluk, wat daartoe lei dat 'n uitsondering gegooi word std::bad_alloc. In hierdie geval sal die wyser verlore gaan en die geskepte voorwerp sal nooit uitgevee word nie.

'n Veilige oplossing is om te skep uniek_ptrwat die wyser sal besit voordat die vektor probeer om geheue te hertoewys:

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

Sedert C++14, kan jy 'std::make_unique' gebruik:

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

Hierdie tipe defek is nie krities vir LLVM nie. As geheue nie toegewys kan word nie, sal die samesteller eenvoudig stop. Maar vir toepassings met lang uptyd, wat nie net kan beëindig as geheue toewysing misluk nie, dit kan 'n ware nare fout wees.

Dus, hoewel hierdie kode nie 'n praktiese bedreiging vir LLVM inhou nie, het ek dit nuttig gevind om oor hierdie foutpatroon te praat en dat die PVS-Studio-ontleder geleer het om dit te identifiseer.

Ander waarskuwings van hierdie tipe:

  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Passe'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. PassManager.h 546
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'AAs'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. AliasAnalysis.h 324
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Inskrywings'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'AllEdges'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. CFGMST.h 268
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'VMaps'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. SimpleLoopUswitch.cpp 2012
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Rekords'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. FDRLogBuilder.h 30
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'PendingSubmodules'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. ModuleMap.cpp 810
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Objects'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. DebugMap.cpp 88
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Strategieë'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 685
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 686
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 688
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 689
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 690
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 691
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 692
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 693
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Modifiers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. llvm-stress.cpp 694
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Operande'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Stash'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] 'n Wyser sonder eienaar word by die 'Matchers'-houer gevoeg deur die 'emplace_back'-metode. 'n Geheuelek sal voorkom in die geval van 'n uitsondering. GlobalISelEmitter.cpp 2702

Gevolgtrekking

Ek het altesaam 60 waarskuwings uitgereik en toe opgehou. Is daar ander defekte wat die PVS-Studio-ontleder in LLVM opspoor? Ja ek het. Toe ek egter kodefragmente vir die artikel uitskryf, was dit laataand, of eerder selfs nag, en ek het besluit dis tyd om dit 'n dag te noem.

Ek hoop jy het dit interessant gevind en sal die PVS-Studio-ontleder wil probeer.

Jy kan die ontleder aflaai en die mynveërsleutel kry by Hierdie bladsy.

Belangriker nog, gebruik statiese analise gereeld. Eenmalige tjeks, wat deur ons uitgevoer word om die metodologie van statiese analise en PVS-Studio te populariseer, is nie 'n normale scenario nie.

Sterkte met die verbetering van die kwaliteit en betroubaarheid van jou kode!

Vind foute in LLVM 8 met behulp van die PVS-Studio-ontleder

As jy hierdie artikel met 'n Engelssprekende gehoor wil deel, gebruik asseblief die vertaalskakel: Andrey Karpov. Soek foute in LLVM 8 met PVS-Studio.

Bron: will.com

Voeg 'n opmerking