Otsime vea LLVM 8-s PVS-Studio analĂŒsaatori abil

Leidke vigu LLVM 8-s PVS-Studio analĂŒsaatori abiga
Kaks aastat on möödunud viimati LLVM projekti koodi PVS-Studio analĂŒsaatoriga kontrollimisest. Veendume, et PVS-Studio on endiselt juhtiv tööriist vigade ja potentsiaalsete haavatavuste tuvastamiseks. Uurime ja leiame uusi vigu LLVM 8.0.0 vĂ€ljaandes.

Artikkel, mis peaks olema kirjutatud

Ausalt öeldes, ma ei tahtnud seda artiklit kirjutada. Pole huvitav kirjutada projektist, mida oleme juba korduvalt kontrollinud (1, 2, 3). Parema meelega kirjutaksin millestki uuest, kuid valikut mul pole.

Iga kord, kui ilmub uus LLVM versioon vĂ”i see uuendatakse Clang Static Analyzer, jĂ”uavad meie postkasti sellised kĂŒsimused:

Vaadake, uus Clang Static Analyzer versioon suudab tuvastada uusi vigu! Mul on tunne, et PVS-Studio kasutamise tÀhtsus vÀheneb. Clang leiab rohkem vigu kui varem ja jÔuab PVS-Studio vÔimalustele jÀrele. Mida teie sellest arvate?

Sellele tahaks alati vastata millegagi taolisega:

Me ei istu ka kĂ€ed ristis! Me oleme oluliselt parandanud PVS-Studio analĂŒsaatori vĂ”imalusi. Nii et Ă€rge muretsege, me jĂ€tkame juhtimist nagu alati.

Kahjuks on see halb vastus. Selles pole piisavalt tĂ”endeid. Ja just seetĂ”ttu kirjutan ma nĂŒĂŒd seda artiklit. Seega on projekti LLVM jĂ€rjekordne kontroll viinud hĂ€mmastavate vigadena. Need, mis tundusid mulle huvitavad, demonstreerin hetkel. Need vead ei suuda avastada Clang Static Analyzer (vĂ”i on selle abil ÀÀrmiselt ebamugav neid otsida). Aga me saame. Ja ma leidsin ja kirjutasin ĂŒles kĂ”ik need vead ĂŒhe Ă”htu jooksul.

Aga artikli kirjutamine venis mitme nÀdala peale. Ei saanud end kuidagi sundida, et kÔik see teksti vormi panna : ).

Muide, kui teid huvitab, milliseid tehnoloogiaid kasutatakse PVS-Studio analĂŒsaatoris vigade ja potentsiaalsete haavatavuste tuvastamiseks, siis kutsun teid tutvuma selle mĂ€rkmega.

Uued ja vanad diagnostikad

Nagu juba mainitud, kontrolliti projekti LLVM umbes kaks aastat tagasi ja leitud vead parandati. NĂŒĂŒd esitan selles artiklis uue koguse vigu. Miks leiti uusi vigu? Sellel on 3 pĂ”hjust:

  1. LLVM projekt areneb, vanas koodis tehakse muudatusi ja uut koodi lisandub. Loomulikult on muudetud ja kirjutatud koodis uusi vigu. See demonstreerib hĂ€sti, et staatilist analĂŒĂŒsi tuleks rakendada regulaarselt, mitte juhuslikult. Meie artiklid nĂ€itavad hĂ€sti PVS-Studio analĂŒsaatori vĂ”imalusi, kuid see ei ole seotud koodi kvaliteedi tĂ”stmise ja vigade parandamise kulude vĂ€hendamisega. Kasutage staatilist koodianalĂŒsaatorit regulaarselt!
  2. TĂ€iendame ja tĂ€iustame juba olemasolevaid diagnostikaid. SeetĂ”ttu saab analĂŒsaator tuvastada vigu, mida varasemate kontrollde kĂ€igus ei mĂ€rgatud.
  3. PVS-Studios on ilmunud uusi diagnostikaid, mida 2 aastat tagasi ei olnud. Otsustasin need vÀlja tuua eraldi jaotises, et selgelt nÀidata PVS-Studio arengut.

Defektid, mille tuvastamisega tegeleti 2 aastat tagasi

Fragment N1: Copy-Paste

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

PVS-Studio hoiatamine: V501 [CWE-570] Vasakul ja paremal ‘||’ operaatoril on identseid alamvĂ€ljendeid ‘Name.startswith(«avx512.mask.permvar.»)’. AutoUpgrade.cpp 73

Kontrollitakse kaks korda, et nimi algab alamhulga «avx512.mask.permvar.». Teises kontrollis soovis ilmselt midagi muud kirjutada, kuid unustas kopeeritud teksti muuta.

Fragment N2: TrĂŒkiviga

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 hoiatamine: V501 Vasakul ja paremal ‘|’ operaatoril on identseid alamvĂ€ljendeid ‘CXNameRange_WantQualifier’. CIndex.cpp 7245

TrĂŒkivea tĂ”ttu kasutatakse kaks korda sama nimelist konstanti CXNameRange_WantQualifier.

Fragment N3: Operaatorite prioriteedi segadus

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

PVS-Studio hoiatamine: V502 [CWE-783] VĂ”ib-olla töötab ‘?:’ operaator ootamatult. ‘?:’ operaatori prioriteet on madalam kui ‘==’ operaatori prioriteet. PPCTargetTransformInfo.cpp 404

Minu arvates on see vÀga ilus viga. Jah, ma tean, et mul on kummalised arusaamad ilust :).

Praegu, vastavalt operaatorite prioriteetidele, arvutatakse vÀljend jÀrgmiselt:

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

Praktilise poole pealt ei oma selline tingimus mĂ”tet, kuna seda saab lĂŒhendada jĂ€rgmiseks:

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

See on ilmne viga. TĂ”enĂ€oliselt soovisid 0/1 vĂ”rrelda muutujaga Indeks. Koodi parandamiseks on vajalik lisada sulud ternaarse operaatori ĂŒmber:

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

Üks asi, ternearne operaator on vĂ€ga ohtlik ja kutsub esile loogilisi vigu. Olge selle kasutamisel vĂ€ga ettevaatlik ja Ă€rge olge ahne, et lisada ĂŒmmarguseid sulge. Selle teema olen lĂ€hemalt kĂ€sitlenud siit, peatĂŒkis «Kartke operaatorit ?: ja sulgege see ĂŒmmarguste sulgudega».

Fragment N4, N5: Nullviide

Alg *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("'ei saa cast' ") + LHS->getAsString() +
                    "' string'iks");
    return nullptr;
  }
  ....
}

PVS-Studio hoiatamine: V522 [CWE-476] Null-pointeri ‘LHS’ lahkamine vĂ”ib toimuda. TGParser.cpp 2152

Kui nÀidik LHS osutub nulliks, siis peaks tekkima hoiatus. Kuid selle asemel toimub null-nÀidiku lahkamine: LHS->getAsString().

See on ĂŒsna tavaline olukord, kus viga peidab end veahaldurites, kuna neid ei testita. Statilised analĂŒsaatorid kontrollivad kogu ligipÀÀsetavat koodi, sĂ”ltumata sellest, kui sageli seda kasutatakse. See on vĂ€ga hea nĂ€ide sellest, kuidas staatiline analĂŒĂŒs tĂ€iendab teisi testimise ja vigade vĂ€ltimise meetodeid.

Sarnane nĂ€idiku haldamise viga RHS on tehtud koodi veidi allpool: V522 [CWE-476] Null-pointeri ‘RHS’ lahkamine vĂ”ib toimuda. TGParser.cpp 2186

Fragment N6: NÀidiku kasutamine pÀrast liigutamist

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

PVS-Studio hoiatuse: V522 [CWE-476] Null-viidatud "ProgClone" vÔib juhtuda. Miscompilation.cpp 601

Alguses nutikas nÀitaja ProgClone lakkab objekti omamisest:

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

Tegelikult, nĂŒĂŒd ProgClone on see null-viidatus. Seega peaks allpool toimuma null-viidatuse dereferents:

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

Kuid tegelikult ei juhtu seda! Pange tĂ€hele, et tsĂŒkkel ei toimu.

Alguses konteiner MiscompiledFunctions kustutatakse:

MiscompiledFunctions.clear();

SeejĂ€rel kasutatakse selle konteineri suurust tsĂŒkli tingimuses:

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

On lihtne nĂ€ha, et tsĂŒkkel ei kĂ€ivitu. Arvan, et see on samuti viga ja kood peaks olema kirjutatud muul viisil.

Tundub, et oleme kohanud seda kuulsat vigade paaritust! Üks viga varjab teist :).

Fragmendi N7: NÀidiku kasutamine pÀrast liikumist

static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
                                    std::unique_ptr<Module> Safe) {
  outs() << "  Optimeerimise all olevad funktsioonid: ";
  std::unique_ptr<Module> Optimized =
      BD.runPassesOn(Test.get(), BD.getPassesToRun());
  if (!Optimized) {
    errs() << " Viga selle passide jÀrjestuse kÀitamisel"
           << " sisendprogrammil!n";
    BD.setNewProgram(std::move(Test));                       // <=
    BD.EmitProgressBitcode(*Test, "pass-error", false);      // <=
    if (Error E = BD.debugOptimizerCrash())
      return std::move(E);
    return false;
  }
  ....
}

Hoiatus PVS-Studio: V522 [CWE-476] Null-punkti ‘Test’ dereferentseerimine vĂ”ib toimuda. Miscompilation.cpp 709

Taaskord sama olukord. Alguses liigub objekti sisu ja seejĂ€rel kasutatakse seda nagu poleks midagi juhtunud. Kohtan seda olukorda ĂŒha sagedamini programmikoodis, pĂ€rast seda, kui C++-sse tuli liikumissemantika. Selle pĂ€rast ma armastan C++ keelt! Ilmuvad ĂŒha uusi ja uusi viise endale jalga tulistamiseks. AnalĂŒĂŒsija PVS-Studio'l on alati tööd :).

Fragmendi N8: Null-nÀidik

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

PVS-Studio hoiatus: V522 [CWE-476] Null-viite ‘Type’ dereferentseerimine vĂ”ib toimuda. PrettyFunctionDumper.cpp 233

Lisaks veahalduritele testitakse tavaliselt ka andmete silumisfunktsioone. See on tÀpselt selline juhtum. Funktsioon ootab kasutajat, kes peab oma probleemide lahendamise asemel tegelema selle parandamisega.

Õige:

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

Fragment N9: Null-viide

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

PVS-Studio hoiatus: V522 [CWE-476] Null-viite ‘Ty’ dereferentseerimine vĂ”ib toimuda. SearchableTableEmitter.cpp 614

Ma arvan, et kÔik on selge ja selgitust ei vaja.

Fragment N10: TrĂŒki viga

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 hoiatamine: V570 Muutuja ‘Identifier->Type’ on mÀÀratud iseendale. FormatTokenLexer.cpp 249

Pole mÔtet mÀÀrata muutujat iseendale. TÔenÀoliselt sooviti kirjutada:

Identifier->Type = Question->Type;

Fragment N11: Kahtlane 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 hoiatamine: V622 [CWE-478] Kaaluge ‘switch’ lause uurimist. TĂ”enĂ€oliselt on esimene ‘case’ operaator puudu. SystemZAsmParser.cpp 652

Alguses on vÀga kahtlane operaator break. Kas ei unustatud siia midagi veel kirjutada?

Fragment N12: NÀidiku kontroll pÀrast dereferentsimist

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 hoiatamine: V595 [CWE-476] ‘Callee’ nĂ€idik kasutati enne, kui seda kontrolliti nullptr vastu. Kontrollige ridu: 172, 174. AMDGPUInline.cpp 172

Viit Callee dereferentseeritakse kohe funktsiooni kutsumise hetkel getTTI.

Ja siis selgub, et seda nÀidikut tuleks kontrollida vÔrdsuse osas nullptr:

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

Aga on juba liiga hilja


Fragment N13 — N
: NĂ€idiku kontroll pĂ€rast dereferentsimist

Koodifragmendis kÀsitletud olukord ei ole ainulaadne. See esineb siin:

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 hoiatatakse: V595 [CWE-476] 'CalleeFn' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 1079, 1081. SimplifyLibCalls.cpp 1079

Ja siin:

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 hoiatatakse: V595 [CWE-476] 'ND' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Ja siin:

  • V595 [CWE-476] 'U' nĂ€idiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 404, 407. DWARFFormValue.cpp 404
  • V595 [CWE-476] 'ND' nĂ€idiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Ja jÀrgmisel hetkel muutus mulle V595 numbriga hoiatused uurida vÀhem huvitavaks. Seega ei tea ma, kas siin on veel analoogseid vigu peale nimetatute.

Fragment N17, N18: Kahtlane nihke

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

PVS-Studio hoiatamine: V629 [CWE-190] Kaaluge ‘~(Size — 1) << 1’ vĂ€ljendi kontrollimist. 32-bitise vÀÀrtuse bititasemeline nihutamine, millele jĂ€rgneb laienemine 64-bitise tĂŒĂŒbini. AArch64AddressingModes.h 260

VĂ”ib-olla see ei ole viga, ja kood töötab just nii, nagu plaanitud. Kuid see on selgelt vĂ€ga kahtlane koht ja see tuleb ĂŒle vaadata.

Oletame, et muutuja Suurus on 16, ning koodi autor plaanis, et muutuja NImms saab vÀÀrtuse:

1111111111111111111111111111111111111111111111111111111111100000

Kuid tegelikult tuleb vÀÀrtuseks:

0000000000000000000000000000000011111111111111111111111111100000

Asi on selles, et kĂ”ik arvutused toimuvad 32-bitise unsigned tĂŒĂŒbi kasutamisel. Ja alles pĂ€rast seda laieneb see 32-bitine signaalita tĂŒĂŒp automaatselt uint64_ttĂŒĂŒbiks. Sellega kaasneb see, et kĂ”rgemad bitid on nullid.

Probleemi saab lahendada nii:

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

Sarnane olukord: V629 [CWE-190] Kaaluge ‘Immr << 6’ vĂ€ljendi kontrollimist. 32-bitise vÀÀrtuse bititasemeline nihutamine, millele jĂ€rgneb laienemine 64-bitise tĂŒĂŒbini. AArch64AddressingModes.h 269

Fragment N19: Omandatud mÀrksÔna muud?

void AMDGPUAsmParser::cvtDPP(MCInst & Inst, const OperandVector & Operands) {
  ....
  if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) {
    // VOP2b (v_add_u32, v_sub_u32 ...) dpp kasutab "vcc" mÀrgendit.
    // JĂ€tame vahele.
    continue;
  } if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) {    // <=
    Op.addRegWithFPInputModsOperands(Inst, 2);
  } else if (Op.isDPPCtrl()) {
    Op.addImmOperands(Inst, 1);
  } else if (Op.isImm()) {
    // KĂ€sitleme valikulisi argumendi
    OptionalIdx[Op.getImmTy()] = I;
  } else {
    llvm_unreachable("Kehtetu operanditĂŒĂŒp");
  }
  ....
}

PVS-Studio hoiatamine: V646 [CWE-670] Kaaluge rakenduse loogika kontrollimist. On vÔimalik, et 'else' mÀrksÔna on puudu. AMDGPUAsmParser.cpp 5655

Siin pole vigu. Kuna esimese if then-plokk lÔpeb continue, siis pole oluline, kas mÀrksÔna muud on vÔi ei. Igal juhul töötab kood sama moodi. Siiski, puuduolev muud teeb koodi vÀhem arusaadavaks ja ohtlikuks. Kui hiljem continue kaob, hakkab kood tööle hoopis teistmoodi. Minu arvates on parem lisada muud.

Fragment N20: Neli sarnast trĂŒkiviga

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 hoiatused:

  • V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit ‘Result + Name.str()’. Symbol.cpp 32
  • V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit ‘Result + «(ObjC Class) » + Name.str()’. Symbol.cpp 35
  • V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit ‘Result + «(ObjC Class EH) » + Name.str()’. Symbol.cpp 38
  • V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit ‘Result + «(ObjC IVar) » + Name.str()’. Symbol.cpp 41

Juhuslikult kasutatakse operatori += asemel operatorit +. Tulemuseks on mÔttetu konstruktsioon.

Fragment N21: MÀÀramatu kÀitumine

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 cannot be empty");

    for (auto &Op : Ops) {
      assert(!Op.empty() && "Empty operator");
      if (FeaturesMap.find(Op) == FeaturesMap.end())
        FeaturesMap[Op] = FeaturesMap.size();
    }
  }
}

Proovige iseseisvalt ohtlik kood leida. Ja see pilt on tÀhelepanu hajutamiseks, et te kohe vastust ei vaataks:

Leidke vigu LLVM 8-s PVS-Studio analĂŒsaatori abiga

PVS-Studio hoiatamine: V708 [CWE-758] Ohtlik konstruktsioon on kasutusel: ‘FeaturesMap[Op] = FeaturesMap.size()’, kus ‘FeaturesMap’ on ‘map’ klass. See vĂ”ib viia mÀÀramata kĂ€itumiseni. RISCVCompressInstEmitter.cpp 490

Problemaatiline rida:

FeaturesMap[Op] = FeaturesMap.size();

Kui element Op ei leitud, siis luuakse kaardis uus element ja sinna salvestatakse elementide arv. Ainult et ei ole teada, kas funktsiooni size kutsutakse vÀlja enne vÔi pÀrast uue elemendi lisamist.

Fragment N22-N24: Korduvalt mÀÀramised

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 hoiatamine: V519 [CWE-563] Muutuja ‘NType’ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1663, 1664. MachOObjectFile.cpp 1664

Arvan, et siin pole tegelikult viga. Lihtsalt ĂŒleliigne korduv omistamine. Aga ikka vale.

Sama:

  • V519 [CWE-563] Muutuja ‘B.NDesc’ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Muutuja omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 59, 61. coff2yaml.cpp 61

Fragment N25-N27: Veel korduvad omistamised

NĂŒĂŒd vaatame natuke teistsugust korduva omistamise varianti.

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 hoiatus: V519 [CWE-563] Muutuja ‘Alignment’ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1158, 1160. LoadStoreVectorizer.cpp 1160

See on vĂ€ga kummaline kood, mis ilmselt sisaldab loogilist viga. Alguses omistatakse muutuja Alignment vÀÀrtus sĂ”ltuvalt tingimusest. Siis toimub taas omistamine, kuid nĂŒĂŒd juba ilma igasuguse kontrollita.

Sarnaseid olukordi vÔib nÀha siin:

  • V519 [CWE-563] Muutuja 'Effects' on jĂ€rjestikku mÀÀratud kahesuguseid vÀÀrtusi. VĂ”ib-olla on see viga. Kontrollige ridu: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Muutuja 'ExpectNoDerefChunk' on jĂ€rjestikku mÀÀratud kahesuguseid vÀÀrtusi. VĂ”ib-olla on see viga. Kontrollige ridu: 4970, 4973. SemaType.cpp 4973

Fragment N28: Alati tÔene tingimus

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 juhendi tugi             // <=
      break;
  }
  ....
}

PVS-Studio hoiatamine: V547 [CWE-571] Avalduss 'nextByte != 0x90' on alati tÔene. X86DisassemblerDecoder.cpp 379

Kontroll ei oma mÔtet. Muutuja nextByte on alati erinev vÀÀrtusest 0x90, mis tuleneb eelmisest kontrollist. See on mingi loogiline viga.

Fragment N29 — N
: Alati tĂ”esed/vale tingimused

AnalĂŒsaator vĂ€ljastab palju hoiatusi seoses sellega, et kogu tingimus (V547) vĂ”i selle osa (V560) on alati tĂ”ene vĂ”i vale. Tihti ei ole need tegelikud vead, vaid lihtsalt hoolimatu kood, makrode rakendamise tulemused jne. Siiski on mĂ”istlik vaadata kĂ”iki neid hoiatustega, kuna aeg-ajalt tulenevad tĂ”elised loogilised vead. NĂ€iteks on kahtlane see koodilĂ”ik:

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 hoiatamine: V560 [CWE-570] Üks tingimuslause osa on alati vale: RegNo == 0xe. ARMDisassembler.cpp 939

Konstant 0xE on vÀÀrtus 14 kĂŒmnendsĂŒsteemis. Kontroll RegNo == 0xe pole mĂ”ttekas, kuna kui RegNo > 13, siis lĂ”petab funktsioon oma töötamise.

Oli palju teisi hoiatusi ID-ga V547 ja V560, kuid nagu oli juba selge V595, ei olnud mul nende hoiatuste uurimise vastu huvi. Niigi oli selge, et mul on piisavalt materjali artikli kirjutamiseks :). SeepÀrast ei ole teada, kui palju selliseid vigu vÔiks LLVM-is PVS-Studio abil tuvastada.

Toon nĂ€ide, miks nende hoiatuste Ă”ppimine on igav. AnalĂŒsaator on tĂ€iesti Ă”ige, andes hoiatuse jĂ€rgmise koodi kohta. Kuid see ei ole viga.

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

PVS-Studio hoiatamine: V547 [CWE-570] VĂ€ljend ‘!HasError’ on alati vale. UnwrappedLineParser.cpp 1635

Fragment N30: Kahtlane return

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 hoiatamine: V612 [CWE-670] Tingimusteta ‘return’ tsĂŒkli sees. R600OptimizeVectorRegisters.cpp 63

See on kas viga vÔi spetsiifiline tehnika, mille eesmÀrk on midagi selgitada programmeerijatele, kes koodi loevad. Selline konstruktsioon ei selgita mulle midagi ja nÀeb vÀga kahtlane vÀlja. Paremini ei tasu nii kirjutada :).

VÀsinud? Siis on aeg teed vÔi kohvi keeta.

Leidke vigu LLVM 8-s PVS-Studio analĂŒsaatori abiga

Defektid, mille uued diagnostikad on tuvastanud

Arvan, et 30 vana diagnostika hoiatust on piisavalt. Vaadakem nĂŒĂŒd, mida huvitavat me uute diagnostikatega, mis analĂŒsaatorisse ilmnesid, leida saame. eelnevas kontrollide. Selle aja jooksul on C++ analĂŒsaatorisse lisandunud 66 ĂŒldist diagnostikat.

Fragment N31: JÔudmata kood

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 hoiatamine: V779 [CWE-561] JÔudmata kood tuvastatud. VÔimalik, et viga on olemas. ExecutionUtils.cpp 146

Nagu nĂ€ete, lĂ”petavad mĂ”lemad harud operaatorit if operaatori kutsumisega return. Seega konteiner CtorDtorsByPriority ei tule kunagi tĂŒhjendamiseks.

Fragment N32: JÔudmata kood

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

Hoiatus PVS-Studio: V779 [CWE-561] JÔudmata kood tuvastatud. VÔimalik, et viga on olemas. LLParser.cpp 835

Huvitav olukord. Vaatame esmalt seda kohta:

return ParseTypeIdEntry(SummaryID);
break;

Esmapilgul tundub, et siin pole viga. Tundub, et operaator break siin on ĂŒleliigne osa, ja selle vĂ”ib lihtsalt eemaldada. Kuid mitte kĂ”ik on nii lihtne.

AnalĂŒsaator annab hoiatuse ridade kohta:

Lex.setIgnoreColonInIdentifiers(false);
return false;

Ja tĂ”epoolest, see kood on saavutatav. KĂ”ik juhtumid switch lĂ”pevad kĂ€su kutsumisega return. Ja nĂŒĂŒd ei tundu ĂŒksildane break nii sĂŒĂŒtu! Äkki peaks ĂŒks haru lĂ”ppema break, mitte return?

Fragment N33: Juhuslik kÔrgemate bitide nullimine

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

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

PVS-Studio hoiatamine: V784 Bitmaski suurus on vÀiksem kui esimese operandi suurus. See pÔhjustab kÔrgemate bitide kadumise. RuntimeDyld.cpp 815

Pange tĂ€hele, et funktsioon getStubAlignment tagastab tĂŒĂŒbi unsigned. Arvutame vĂ€ljendi vÀÀrtuse, eeldades, et funktsioon tagastab vÀÀrtuse 8:

~(getStubAlignment() - 1)

~(8u-1)

0xFFFFFFF8‬u

NĂŒĂŒd pange tĂ€hele, et muutuja DataSize omab 64-bit unsigned tĂŒĂŒp. See tĂ€hendab, et DataSize & 0xFFFFFFF8‬u teostamisel nullitakse kĂ”ik kolmkĂŒmmend kaks ĂŒlemist bitti. TĂ”enĂ€oliselt ei olnud see, mida programmeerija soovis. Kahtlustan, et ta tahtis arvutada: DataSize & 0xFFFFFFFFFFFFFFF8‬u.

Vea parandamiseks tuleks kirjutada nii:

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

VÔi nii:

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

Fragment N34: EbaĂ”nnestunud tĂŒĂŒpide konverteerimine

template <typename T>
void scaleShuffleMask(int Scale, ArrayRef<T> Mask,
                      SmallVectorImpl<T> &ScaledMask) {
  assert(0 < Scale && "Ootamatu skaleerimise tegur");
  int NumElts = Mask.size();
  ScaledMask.assign(static_cast<size_t>(NumElts * Scale), -1);
  ....
}

PVS-Studio hoiatamine: V1028 [CWE-190] VĂ”imalik ĂŒlejÀÀgitus. Kaaluge operandide 'NumElts * Scale' operaatori kastmist 'size_t' tĂŒĂŒbiks, mitte tulemust. X86ISelLowering.h 1577

TĂŒĂŒpide konverteerimist kasutatakse, et vĂ€ltida ĂŒlejÀÀgitust muutuja tĂŒĂŒpide korrutamisel. int. Kuid siin ei kaitse tĂŒĂŒpide konverteerimine ĂŒlejÀÀgi eest. Alguses korrutatakse muutujad ja alles seejĂ€rel laiendatakse 32-bitine korrutamise tulemus. size_t.

Fragment N35: EbaÔnnestunud Copy-Paste

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] Leiti sarnased koodi fragmentid. VĂ”ib-olla on see trĂŒkkimisviga ja 'Op1' muutuja peaks olema kasutatud 'Op0' asemel. InstCombineCompares.cpp 5507

See uus huvitav diagnoos tuvastab olukordi, kus koodifragmendi on kopeeritud ja nimesid on hakanud muutma, aga ĂŒhes kohas ei ole neid parandatud.

Pange tĂ€hele, et teises plokis muudeti Op0 jĂ€rgnevaga Op1. Aga ĂŒhes kohas ei ole neid parandatud. TĂ”enĂ€oliselt oleks pidanud kirjutama nii:

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

Fragment N36: Muutujate segadus

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

PVS-Studio hoiatamine: V1001 [CWE-563] Muutujale 'Mode' antakse vÀÀrtus, kuid seda ei kasutata funktsiooni lÔpuks. SIModeRegister.cpp 48

On vÀga ohtlik anda funktsioonide argumentidele samu nimesid kui klassi liikmetele. On vÀga lihtne segadusse sattuda. See on just selline juhtum. See vÀljend ei oma tÀhendust:

Mode &= Mask;

Funktsiooni argument muutub. Ja kÔik. Seda argumenti ei kasutata enam. TÔenÀoliselt pidi olema nii:

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

Fragment N37: Muutuja segadus

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

PVS-Studio hoiatus: V1001 [CWE-563] Muutujale 'Size' antakse vÀÀrtus, kuid funktsiooni lÔpuks ei kasutata seda. Object.cpp 424

Situatsioon on analoogne eelnevale. Peaks olema kirjutatud:

this->Size += this->EntrySize;

Fragment N38-N47: NĂ€idik unustati kontrollida

Varem oleme vaadanud diagnostika aktiveerumise nÀiteid V595. Selle olemus on see, et nÀidik dereferenseeritakse alguses ja alles siis kontrollitakse. Uhiuus diagnostika V1004 on vastupidine, kuid samal ajal avastab vÀga palju vigu. See paljastab olukordi, kus indikaatorit alguses kontrolliti, kuid siis unustati seda teha. Vaadakem selliseid juhtumeid, mis leiti LLVM'is.

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

PVS-Studio hoiatus: V1004 [CWE-476] Pointer 'Ptr' kasutati pÀrast null'i vastu kontrollimist ebaohutult. Kontrollige ridu: 729, 738. TargetTransformInfoImpl.h 738

Muutuja Ptr vÔib olla vÔrdne nullptr, mida nÀitab kontroll:

if (Ptr != nullptr)

Kuid allpool dereferenseeritakse seda pointerit juba eelneva kontrollita:

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

Vaatame teist sarnast juhtumit.

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

PVS-Studio hoiatamine: V1004 [CWE-476] 'FD' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 3228, 3231. CGDebugInfo.cpp 3231

Pange tÀhele pointerit FD. Olen kindel, et probleem on selgelt nÀhtav ja ei vaja erilisi selgitusi.

Ja veel:

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

PVS-Studio hoiatamine: V1004 [CWE-476] 'PtrTy' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 960, 965. InterleavedLoadCombinePass.cpp 965

Kuidas end selliste vigade eest kaitsta? Olge tĂ€helepanelikumad koodi ĂŒlevaatusel ja kasutage regulaarseks koodikontrolliks staatilist analizatorit PVS-Studio.

Muude samasuguste vigadega koodifragmentide toomine pole mÔtet. JÀtan artiklisse ainult hoiatuste nimekirja:

  • V1004 [CWE-476] 'Expr' pointerit kasutati ebaohutult pĂ€rast null-pointeriga kontrollimist. Kontrollige ridu: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] 'PI' pointerit kasutati ebaohutult pĂ€rast null-pointeriga kontrollimist. Kontrollige ridu: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] 'StatepointCall' pointerit kasutati ebaohutult pĂ€rast null-pointeriga kontrollimist. Kontrollige ridu: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] ‘RV’ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] ‘CalleeFn’ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] ‘TC’ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 1819, 1824. Driver.cpp 1824

Fragment N48-N60: Mitte kriitiline, aga defekt (vÔimalik mÀluleke)

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

PVS-Studio hoiatamine: V1023 [CWE-460] Pointer, millel pole omanikku, lisatakse ‘Strategies’ konteinerisse ’emplace_back’ meetodi kaudu. MĂ€luleke toimub juhul, kui tekib erand. llvm-isel-fuzzer.cpp 58

Elemendi lisamiseks konteineri lĂ”ppu, tĂŒĂŒpi std::vector<std::unique_ptr> ei saa lihtsalt kirjutada xxx.push_back(new X), kuna ei toimu varjatud teisendamist X* ĂŒhes std::unique_ptr.

Levinud lahendus on kirjutada xxx.emplace_back(new X), kuna see kompileerub: meetod emplace_back ehitab elemendi otse argumentidest ja seega vÔib kasutada selgeid konstruktorit.

See ei ole ohutu. Kui vektor on tĂ€is, toimub mĂ€lu ĂŒmberjaotamine. MĂ€lu ĂŒmberjaotamise operatsioon vĂ”ib ebaĂ”nnestuda, mille tagajĂ€rjel genereeritakse erand std::bad_alloc. Sel juhul kaob nĂ€idik ja loodud objekti ei saa kunagi kustutada.

Ohutu lahendus on loomine unique_ptr, mis omab nÀidikut kuni vektori katse mÀluruumi uuesti eraldada:

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

Alates C++14-st saab kasutada ‘std::make_unique’:

xxx.push_back(std::make_unique())

Seda tĂŒĂŒpi viga ei ole LLVM jaoks kriitiline. Kui mĂ€luruumi eraldamine ebaĂ”nnestub, peatub kompilaatori töö lihtsalt. Kuid rakenduste jaoks, mille kĂ€ivitusaeg on pikk, mis ei saa lihtsalt lĂ”petada, kui mĂ€luruumi eraldamine ebaĂ”nnestub, vĂ”ib see olla tĂ”eline ebamugavus.

Seega, kuigi see kood ei kujuta endas praktilist ohtu LLVM-ile, leidis ma kasulik rÀÀkida sellest veapatrist ja sellest, kuidas PVS-Studio analĂŒsaator on Ă”ppinud seda tuvastama.

Muud selle tĂŒĂŒpi hoiatustega:

  • V1023 [CWE-460] NĂ€idik, kellel pole omanikku, lisatakse 'Passes' konteinerisse ’emplace_back’ meetodiga. Erakordsuse korral tekib mĂ€luleke. PassManager.h 546
  • V1023 [CWE-460] NĂ€idik, kellel pole omanikku, lisatakse 'AAs' konteinerisse ’emplace_back’ meetodiga. Erakordsuse korral tekib mĂ€luleke. AliasAnalysis.h 324
  • V1023 [CWE-460] Omanikuta omanikuta lisatakse 'Entries' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'AllEdges' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. CFGMST.h 268
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'VMaps' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Records' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. FDRLogBuilder.h 30
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'PendingSubmodules' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. ModuleMap.cpp 810
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Objects' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. DebugMap.cpp 88
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Strategies' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. llvm-stress.cpp 685
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. llvm-stress.cpp 686
  • V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mĂ€luleke. llvm-stress.cpp 688
  • V1023 [CWE-460] Omanik, kellel ei ole omanikku, lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 689
  • V1023 [CWE-460] Omanikuta pointern lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 690
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 691
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 692
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 693
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Modifikaatorite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 694
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Operandide“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Stashi“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Omanikuta pointer lisatakse „Matcherite“ konteinerisse meetodi „emplace_back“ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 2702

KokkuvÔte

Kokku olen koostanud 60 hoiatust, mille jĂ€rel peatusin. Kas PVS-Studio analĂŒsaator tuvastab veel muid Defekte LLVM-s? Jah, tuvastab. Kuid kui ma koostasin artikli jaoks koodilĂ”ike, oli juba hiline Ă”htu, pigem isegi öö, ja otsustasin, et on aeg lĂ”petada.

Loodan, et teile oli huvitav ja soovite proovida PVS-Studio analĂŒsaatorit.

Saate analĂŒsaatori alla laadida ja saada proovivĂ”tmiseks vĂ”tme sellel lehel.

KĂ”ige tĂ€htsam, kasutage staatilist analĂŒĂŒsi regulaarselt. Ühekordsed kontrollid, mida me teeme staatilise analĂŒĂŒsi ja PVS-Studio metodoloogia populariseerimise eesmĂ€rgil, ei ole normaalne stsenaarium.

Edu koodi kvaliteedi ja usaldusvÀÀrsuse parandamisel!

Leidke vigu LLVM 8-s PVS-Studio analĂŒsaatori abiga

Kui soovite seda artiklit jagada ingliskeelse auditooriumiga, siis palun kasutage tÔlke linki: Andrey Karpov. Finding Bugs in LLVM 8 with PVS-Studio.

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster