Truvà bug in LLVM 8 utilizendu l'analizzatore PVS-Studio

Truvà bug in LLVM 8 utilizendu l'analizzatore PVS-Studio
Più di dui anni sò passati da l'ultima verificazione di codice di u prughjettu LLVM utilizendu u nostru analizzatore PVS-Studio. Fighjemu chì l'analizzatore PVS-Studio hè sempre un strumentu di punta per identificà errori è vulnerabili potenziali. Per fà questu, avemu da verificà è truvà novi errori in a versione LLVM 8.0.0.

Articulu da esse scrittu

Per esse onestu, ùn vulia micca scrive stu articulu. Ùn hè micca interessante di scrive nantu à un prughjettu chì avemu digià verificatu parechje volte (1, 2, 3). Hè megliu di scrive qualcosa di novu, ma ùn aghju micca scelta.

Ogni volta chì una nova versione di LLVM hè liberata o aghjurnata Analizzatore staticu Clang, ricevemu dumande di u tipu seguente in u nostru mail:

Fighjate, a nova versione di Clang Static Analyzer hà amparatu à truvà novi errori! Mi pare chì a pertinenza di l'usu di PVS-Studio hè in diminuzione. Clang trova più errori ch'è prima è ritrova cù e capacità di PVS-Studio. Chì ne pensate di questu?

À questu vogliu sempre risponde à qualcosa cum'è:

Ùn ci simu à piantà nè ! Avemu migliuratu significativamente e capacità di l'analizzatore PVS-Studio. Allora ùn vi preoccupate, cuntinuemu à guidà cum'è prima.

Sfurtunatamente, questa hè una mala risposta. Ùn ci sò micca prove in questu. È hè per quessa ch'e aghju scrittu issa articulu. Dunque, u prughjettu LLVM hè statu verificatu di novu è una varietà di errori sò stati truvati in questu. Avà dimustraraghju quelli chì mi parevanu interessanti. Clang Static Analyzer ùn pò micca truvà questi errori (o hè estremamente inconveniente per fà cusì cù u so aiutu). Ma pudemu. Inoltre, aghju trovu è scrivite tutti questi errori in una sera.

Ma a scrittura di l'articulu hà pigliatu parechje settimane. Ùn aghju micca pussutu mette tuttu questu in testu :).

A propositu, se site interessatu in quali tecnulugia sò aduprate in l'analizzatore PVS-Studio per identificà l'errori è e vulnerabilità potenziali, allora vi suggeriu di cunnosce questu. nota.

Diagnosi novi è vechji

Cum'è digià nutatu, circa dui anni fà u prughjettu LLVM hè statu una volta verificatu, è l'errori truvati sò stati curretti. Avà stu articulu hà da prisentà un novu batch di errori. Perchè sò stati truvati novi bug? Ci hè 3 motivi per questu:

  1. U prughjettu LLVM hè in evoluzione, cambiendu u vechju codice è aghjunghjendu novu codice. Naturalmente, ci sò novi errori in u codice mudificatu è scrittu. Questu dimustra chjaramente chì l'analisi statica deve esse usata regularmente, è micca occasionalmente. I nostri articuli mostranu bè e capacità di l'analizzatore PVS-Studio, ma questu ùn hà nunda di fà cù a migliurà a qualità di u codice è a riduzzione di u costu di riparà errori. Aduprate regularmente un analizzatore di codice staticu!
  2. Finalizemu è migliurà i diagnostichi esistenti. Dunque, l'analizzatore pò identificà errori chì ùn hà micca avvistu durante i scans precedenti.
  3. Novi diagnostichi sò apparsu in PVS-Studio chì ùn esiste micca 2 anni fà. Aghju decisu di mette in risaltu in una sezione separata per vede chjaramente u sviluppu di PVS-Studio.

I difetti identificati da diagnostichi chì esistevanu 2 anni fà

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

Avvisu di PVS-Studio: V501 [CWE-570] Ci sò subespressioni idèntiche 'Name.startswith("avx512.mask.permvar.")' à manca è à diritta di u '||' operatore. AutoUpgrade.cpp 73

Hè doppiu verificatu chì u nome cumencia cù a substringa "avx512.mask.permvar.". In a seconda verificazione, ovviamente vulianu scrive qualcosa d'altru, ma si scurdavanu di curregà u testu copiatu.

Fragment N2: Typo

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

Avvertimentu PVS-Studio: V501 Ci sò subespressioni idèntici 'CXNameRange_WantQualifier' à a manca è à a diritta di u '|' operatore. CIndex.cpp 7245

A causa di un typo, a listessa constante chjamata hè aduprata duie volte CXNameRange_WantQualifier.

Fragment N3: Cunfusione cù a precedenza di l'operatore

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

Avvisu di PVS-Studio: V502 [CWE-783] Forse l'operatore '?:' funziona in una manera diversa da ciò chì era previstu. L'operatore '?:' hà una priorità più bassa cà l'operatore '=='. PPCTargetTransformInfo.cpp 404

In u mo parè, questu hè un sbagliu assai bellu. Iè, sò chì aghju idee strane nantu à a bellezza :).

Avà, secondu priorità di l'operatore, l'espressione hè valutata cusì:

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

Da un puntu di vista praticu, una tale cundizione ùn hè micca sensu, postu chì pò esse ridutta à:

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

Questu hè un sbagliu chjaru. Probabilmente, vulianu paragunà 0/1 cù una variàbile Index. Per riparà u codice, avete bisognu di aghjunghje parentesi intornu à l'operatore ternariu:

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

In modu, l'operatore ternariu hè assai periculosu è provoca errori lògichi. Attentu assai cun ellu è ùn esse avidità cù parentesi. Aghju guardatu stu tema in più detail ccà, in u capitulu "Attenzione à u ?: Operatore è aghjunghje in parentesi".

Fragment N4, N5: Pointer null

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

Avvisu di PVS-Studio: V522 [CWE-476] U dereferencing di u puntatore nulu "LHS" puderia esse fattu. TGParser.cpp 2152

Se u puntatore LHS hè nulla, deve esse emessu un avvisu. Tuttavia, invece, stu stissu punteru nulu serà dereferenziatu: LHS->getAsString().

Questa hè una situazione assai tipica quandu un errore hè oculatu in un gestore d'errore, postu chì nimu li prova. L'analizzatori statici cuntrollanu tuttu u codice accessibile, ùn importa quante volte hè utilizatu. Questu hè un bon esempiu di cumu l'analisi statica cumplementa altre tecniche di teste è di prutezzione di l'errore.

Errore di gestione di puntatore simile RHS permessu in u codice ghjustu sottu: V522 [CWE-476] Dereferencing di u puntatore nulu 'RHS' puderia esse. TGParser.cpp 2186

Fragment N6: Utilizà u puntatore dopu a mossa

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

Avvisu PVS-Studio: V522 [CWE-476] Dereference di u puntatore nulu 'ProgClone' puderia esse. Miscompilation.cpp 601

À u principiu un puntatore intelligente ProgClone cessa di pussede l'ughjettu:

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

In fatti, avà ProgClone hè un puntatore nulu. Dunque, una dereferenza di puntatore nulla deve esse ghjustu sottu:

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

Ma, in realità, questu ùn succede micca! Nota chì u ciclu ùn hè micca veramente eseguitu.

À u principiu di u cuntinuu Funzioni miscompiled sbulicatu:

MiscompiledFunctions.clear();

Dopu, a dimensione di stu cuntinuu hè aduprata in a cundizione di ciclu:

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

Hè faciule per vede chì u ciclu ùn principia micca. Pensu chì questu hè ancu un bug è u codice deve esse scrittu in modu diversu.

Sembra chì avemu scontru cù quella famosa parità di errori ! Un sbagliu maschera un altru :).

Fragment N7: Utilizà u puntatore dopu a mossa

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

Avvisu PVS-Studio: V522 [CWE-476] Dereference di u puntatore nulu "Test" puderia esse realizatu. Miscompilation.cpp 709

A stessa situazione torna. À u primu, u cuntenutu di l'ughjettu hè spustatu, è dopu hè adupratu cum'è s'ellu ùn era nunda. Vecu sta situazione più è più spessu in u codice di u prugramma dopu chì a semantica di u muvimentu apparsu in C++. Hè per quessa chì mi piace a lingua C++! Ci sò sempre più novi modi per sparà a vostra propria gamba. L'analizzatore PVS-Studio averà sempre u travagliu :).

Frammentu N8: puntatore nulu

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

Avvisu PVS-Studio: V522 [CWE-476] Dereference di u puntatore nulu "Tipu" puderia esse. PrettyFunctionDumper.cpp 233

In più di i gestori di errore, e funzioni di stampa di debugging sò generalmente micca pruvati. Avemu ghjustu un tali casu davanti à noi. A funzione hè aspittendu per l'utilizatore, chì invece di risolve i so prublemi, serà custrettu à riparà.

Correfica:

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

Frammentu N9: puntatore nulu

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

Avvisu PVS-Studio: V522 [CWE-476] Dereference di u puntatore nulu 'Ty' pò esse fattu. SearchableTableEmitter.cpp 614

Pensu chì tuttu hè chjaru è ùn hà micca bisognu di spiegazione.

Fragment N10: Typo

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

Avvisu di PVS-Studio: V570 A variabile "Identificatore->Tipu" hè assignatu à ellu stessu. FormatTokenLexer.cpp 249

Ùn ci hè nunda di assignà una variabile à sè stessu. Probabilmente anu vulsutu scrive:

Identifier->Type = Question->Type;

Fragment N11: Ruttura suspettuosa

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

Avvisu di PVS-Studio: V622 [CWE-478] Cunsiderate inspeccionà a dichjarazione "switch". Hè pussibule chì u primu operatore "casu" manca. SystemZAsmParser.cpp 652

Ci hè un operatore assai suspettu à u principiu ruttura. Avete scurdatu di scrive qualcosa d'altru quì ?

Fragment N12: Cuntrolla di puntatore dopu a dereferenza

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

Avvisu di PVS-Studio: V595 [CWE-476] L'indicatore "Callee" hè statu utilizatu prima di esse verificatu contru nullptr. Verificate e linee: 172, 174. AMDGPUInline.cpp 172

Puntatore Callee à u principiu hè dereferenced à u mumentu chì a funzione hè chjamata getTTI.

E poi si trova chì stu puntatore deve esse verificatu per l'ugualità nullptr:

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

Ma hè troppu tardi...

Fragment N13 - N...: Verificazione di un puntatore dopu a dereferenza

A situazione discussa in u frammentu di codice precedente ùn hè micca unica. Si vede quì:

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

Avvisu PVS-Studio: V595 [CWE-476] L'indicatore 'CalleeFn' hè statu utilizatu prima di esse verificatu contru nullptr. Verificate e linee: 1079, 1081. SimplifyLibCalls.cpp 1079

È quì:

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

Avvisu PVS-Studio: V595 [CWE-476] U puntatore "ND" hè statu utilizatu prima ch'ellu sia verificatu contru nullptr. Verificate e linee: 532, 534. SemaTemplateInstantiateDecl.cpp 532

È quì:

  • V595 [CWE-476] U puntatore "U" hè statu utilizatu prima di esse verificatu contru nullptr. Verificate e linee: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] L'indicatore "ND" hè statu utilizatu prima di esse verificatu contru nullptr. Verificate e linee: 2149, 2151. SemaTemplateInstantiate.cpp 2149

È dopu ùn sò micca interessatu à studià l'avvirtimenti cù u numeru V595. Allora ùn sò micca sapè s'ellu ci sò più errori simili in più di quelli elencati quì. Probabilmente ci hè.

Fragment N17, N18: Sposta suspettuosa

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

Avvisu di PVS-Studio: V629 [CWE-190] Cunsiderate inspeccionà l'espressione '~(Size - 1) << 1'. Bit shifting di u valore 32-bit cun una espansione sussegwente à u tipu 64-bit. AArch64AddressingModes.h 260

Pò esse micca un bug è u codice funziona esattamente cum'è previstu. Ma questu hè chjaramente un locu assai suspettu è deve esse verificatu.

Dicemu a variabile Size hè uguali à 16, è dopu l'autore di u codice hà previstu di ottene in una variabile NImms valore:

1111111111111111111111111111111111111111111111111111111111100000

Tuttavia, in realtà, u risultatu serà:

0000000000000000000000000000000011111111111111111111111111100000

U fattu hè chì tutti i calculi accadenu cù u tipu 32-bit unsigned. È solu allora, stu tipu di 32-bit unsigned serà implicitamente allargatu à uint64_t. In questu casu, i bits più significati seranu zero.

Pudete riparà a situazione cusì:

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

Situazione simile: V629 [CWE-190] Cunsiderate inspeccionà l'espressione "Immr << 6". Bit shifting di u valore 32-bit cun una espansione sussegwente à u tipu 64-bit. AArch64AddressingModes.h 269

Fragment N19: Chjave mancante altru?

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

Avvisu di PVS-Studio: V646 [CWE-670] Cunsiderate inspeccionà a logica di l'applicazione. Hè pussibule chì a chjave "altri" manca. AMDGPUAsmParser.cpp 5655

Ùn ci hè micca sbagliu quì. Dapoi u bloccu di u primu if finisce cù continuà, allora ùn importa micca, ci hè una keyword altru o micca. In ogni modu, u codice hà da travaglià u listessu. Mancu ancora altru rende u codice più chjaru è periculosu. Se in u futuru continuà sparisce, u codice hà da cumincià à travaglià in modu completamente diversu. In u mo parè hè megliu aghjunghje altru.

Fragment N20: Quattru typos di u listessu tipu

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

Avvisi di PVS-Studio:

  • V655 [CWE-480] I cordi sò stati cuncatenati ma ùn sò micca usati. Cunsiderate inspeccionà l'espressione "Result + Name.str()". Simbulu.cpp 32
  • V655 [CWE-480] I cordi sò stati cuncatenati ma ùn sò micca usati. Cunsiderate inspeccionà l'espressione "Result + "(ObjC Class)" + Name.str()'. Simbulu.cpp 35
  • V655 [CWE-480] I cordi sò stati cuncatenati ma ùn sò micca usati. Cunsiderate inspeccionà l'espressione "Result + "(ObjC Class EH)" + Name.str()'. Simbulu.cpp 38
  • V655 [CWE-480] I cordi sò stati cuncatenati ma ùn sò micca usati. Cunsiderate inspeccionà l'espressione "Result + "(ObjC IVar)" + Name.str()'. Simbulu.cpp 41

Per accidenti, l'operatore + hè utilizatu invece di l'operatore +=. U risultatu hè disinni chì sò senza significatu.

Fragment N21: Cumportamentu indefinitu

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

Pruvate à truvà u codice periculosa sè stessu. È questu hè un ritrattu per distractà l'attenzione per ùn vede immediatamente a risposta:

Truvà bug in LLVM 8 utilizendu l'analizzatore PVS-Studio

Avvisu di PVS-Studio: V708 [CWE-758] A custruzzione periculosa hè aduprata: 'FeaturesMap[Op] = FeaturesMap.size()', induve 'FeaturesMap' hè di classa 'mappa'. Questu pò purtà à un cumpurtamentu indefinitu. RISCVCompressInstEmitter.cpp 490

Linea di prublema:

FeaturesMap[Op] = FeaturesMap.size();

Se l'elementu Op ùn hè micca truvatu, allura un novu elementu hè creatu in a mappa è u numeru di elementi in questa mappa hè scrittu quì. Hè scunnisciutu solu se a funzione serà chjamata grannizza prima o dopu à aghjunghje un novu elementu.

Fragment N22-N24: Assegnazione ripetuta

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

Avvisu di PVS-Studio: V519 [CWE-563] A variabile "NType" hè attribuita valori duie volte in successione. Forse questu hè un sbagliu. Verificate e linee: 1663, 1664. MachOObjectFile.cpp 1664

Ùn pensu micca chì ci hè un veru sbagliu quì. Solu una assignazione ripetuta inutile. Ma sempre un sbagliu.

In listessu modu:

  • V519 [CWE-563] A variabile 'B.NDesc' hè attribuita valori duie volte in successione. Forse questu hè un sbagliu. Verificate e linee: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] A variàbile hè attribuita valori duie volte in successione. Forse questu hè un sbagliu. Verificate e linee: 59, 61. coff2yaml.cpp 61

Fragment N25-N27: Più riassegnazioni

Avà fighjemu una versione ligeramente sfarente di riassignazione.

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

Avvisu PVS-Studio: V519 [CWE-563] A variabile "Alignment" hè attribuita valori duie volte consecutivamente. Forse questu hè un sbagliu. Verificate e linee: 1158, 1160. LoadStoreVectorizer.cpp 1160

Questu hè un codice assai stranu chì apparentemente cuntene un errore logicu. À u principiu, variabile infilarata di un valore hè attribuitu secondu a cundizione. E poi l'assignazione si ritrova, ma avà senza nisun cuntrollu.

Situazioni simili ponu esse vistu quì:

  • V519 [CWE-563] A variabile "Effetti" hè attribuita valori duie volte in successione. Forse questu hè un sbagliu. Verificate e linee: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] A variabile "ExpectNoDerefChunk" hè attribuita valori duie volte in successione. Forse questu hè un sbagliu. Verificate e linee: 4970, 4973. SemaType.cpp 4973

Fragment N28: Sempre vera cundizione

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

Avvisu di PVS-Studio: V547 [CWE-571] L'espressione 'nextByte != 0x90' hè sempre vera. X86DisassemblerDecoder.cpp 379

Cuntrollà ùn hà micca sensu. Variabile Next Byte micca sempre uguali à u valore 0x90, chì seguita da a verificazione precedente. Questu hè un tipu d'errore logicu.

Fragment N29 - N... : Cundizioni sempre veri/falsi

L'analizzatore emette assai avvisi chì tutta a cundizione (V547) o parte di questu (V560) hè sempre veru o falsu. Spessu questi ùn sò micca veri errori, ma solu codice sloppy, u risultatu di l'espansione macro, è simili. Tuttavia, hè sensu di guardà tutti questi avvirtimenti, postu chì i veri errori lògichi si verificanu di tantu in tantu. Per esempiu, sta sezione di codice hè suspettuosa:

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

Avvisu di PVS-Studio: V560 [CWE-570] Una parte di l'espressione cundizionale hè sempre falsa: RegNo == 0xe. ARMDisassembler.cpp 939

A constante 0xE hè u valore 14 in decimali. Esame RegNo == 0xe ùn hà micca sensu perchè se RegNo > 13, allura a funzione compie a so esecuzione.

Ci era parechje altre avvirtimenti cù ID V547 è V560, ma cum'è cù V595, Ùn era micca interessatu à studià questi avvirtimenti. Era digià chjaru chì avia abbastanza materiale per scrive un articulu :). Dunque, ùn hè micca cunnisciutu quanti errori di stu tipu ponu esse identificati in LLVM cù PVS-Studio.

Vi daraghju un esempiu di perchè studià sti triggers hè noioso. L'analizzatore hè assolutamente ghjustu à emette un avvisu per u codice seguente. Ma questu ùn hè micca un sbagliu.

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

Avvisu PVS-Studio: V547 [CWE-570] L'espressione '!HasError' hè sempre falsa. UnwrappedLineParser.cpp 1635

Fragment N30: ​​​​Return suspicious

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

Avvisu di PVS-Studio: V612 [CWE-670] Un "ritornu" incondizionatu in un ciclu. R600OptimizeVectorRegisters.cpp 63

Questu hè un errore o una tecnica specifica chì hè destinata à spiegà qualcosa à i programatori chì leghjenu u codice. Stu disignu ùn mi spiegà nunda è mi pare assai suspettu. Hè megliu ùn scrive cusì :).

Stancu ? Allora hè u tempu di fà tè o caffè.

Truvà bug in LLVM 8 utilizendu l'analizzatore PVS-Studio

I difetti identificati da novi diagnostichi

Pensu chì 30 attivazioni di vechji diagnostichi sò abbastanza. Videmu avà chì cose interessanti ponu esse truvate cù i novi diagnostichi chì apparsu in l'analizzatore dopu precedente cuntrolli. Duranti stu tempu, un totale di 66 diagnostichi di u scopu generale sò stati aghjuntu à l'analizzatore C++.

Fragment N31: Codice inaccessibile

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

Avvisu di PVS-Studio: V779 [CWE-561] Codice inaccessibile rilevatu. Hè pussibule chì un errore hè presente. ExecutionUtils.cpp 146

Comu pudete vede, i dui rami di l'operatore if finisce cù una chjama à l'operatore ritornu. Per quessa, u cuntinuu CtorDtorsByPriority ùn sarà mai sbulicatu.

Fragment N32: Codice inaccessibile

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

Avvisu PVS-Studio: V779 [CWE-561] Codice inaccessibile rilevatu. Hè pussibule chì un errore hè presente. LLParser.cpp 835

Situazione interessante. Fighjemu prima stu locu:

return ParseTypeIdEntry(SummaryID);
break;

À u primu sguardu, pare chì ùn ci hè micca errore quì. Sembra l'operatore ruttura ci hè un extra quì, è pudete solu sguassà. Tuttavia, micca tutti cusì sèmplice.

L'analizzatore emette un avvisu nantu à e linee:

Lex.setIgnoreColonInIdentifiers(false);
return false;

È veramente, stu codice hè inaccessibile. Tutti i casi in connard finisce cù una chjama da l'operatore ritornu. È avà senza sensu solu ruttura ùn pare micca cusì innocu ! Forsi unu di i rami duveria finisce cù ruttura, micca nantu ritornu?

Fragment N33: Reset casuale di bit alti

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

Avvisu di PVS-Studio: V784 A dimensione di a maschera di bit hè menu di a dimensione di u primu operandu. Questu pruvucarà a perdita di bit più altu. RuntimeDyld.cpp 815

Per piacè nutate chì a funzione getStubAlignment torna tipu senza firma. Calculemu u valore di l'espressione, assumendu chì a funzione torna u valore 8:

~(getStubAlignment() - 1)

~ (8u-1)

0xFFFFFFFF8u

Avà nutate chì a variabile DataSize hà un tipu 64-bit senza firmatu. Ci hè chì quandu eseguisce l'operazione DataSize & 0xFFFFFFF8u, tutti i trenta-dui bits d'altu ordine seranu resettati à zero. Probabilmente, questu ùn hè micca ciò chì u programatore vulia. Sospettate ch'ellu vulia calculà: DataSize & 0xFFFFFFFFFFFFFFF8u.

Per risolve l'errore, duvete scrive questu:

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

Or so:

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

Fragment N34: Cast di tipu esplicitu fallutu

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

Avvisu di PVS-Studio: V1028 [CWE-190] Possibile overflow. Cunsiderate u casting operandi di l'operatore 'NumElts * Scale' à u tipu 'size_t', micca u risultatu. X86ISelLowering.h 1577

U casting di tipu esplicitu hè utilizatu per evità l'overflow quandu multiplicate variàbili di tipu tram. Tuttavia, u casting di tipu esplicitu quì ùn pruteghja micca da u overflow. Prima, i variàbili seranu multiplicati, è solu allora u risultatu di 32-bit di a multiplicazione serà allargatu à u tipu. taglia_t.

Fragment N35: Copy-Paste fallutu

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] Dui frammenti di codice simili sò stati truvati. Forsi, questu hè un typo è a variabile "Op1" deve esse usata invece di "Op0". InstCombineCompares.cpp 5507

Stu novu diagnosticu interessante identifica situazioni induve un pezzu di codice hè statu copiatu è certi nomi anu cuminciatu à esse cambiatu in questu, ma in un locu ùn anu micca currettu.

Per piacè nutate chì in u sicondu bloccu anu cambiatu Op 0 nantu Op 1. Ma in un locu ùn anu micca riparatu. Hè assai prubabile chì duveria esse scrittu cusì:

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

Fragment N36: Variable Confusion

struct Status {
  unsigned Mask;
  unsigned Mode;

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

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

Avvisu di PVS-Studio: V1001 [CWE-563] A variabile "Mode" hè assignatu ma ùn hè micca utilizatu da a fine di a funzione. SIModeRegister.cpp 48

Hè assai periculosu di dà à l'argumenti di funzione i stessi nomi di i membri di a classe. Hè assai faciule per esse cunfusu. Avemu ghjustu un tali casu davanti à noi. Questa espressione ùn hà micca sensu:

Mode &= Mask;

L'argumentu di a funzione cambia. Eccu tuttu. Stu argumentu ùn hè più usatu. Probabilmente avete da esse scrittu cusì:

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

Fragment N37: Variable Confusion

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

Avvisu PVS-Studio: V1001 [CWE-563] A variabile 'Size' hè assignata ma ùn hè micca utilizata da a fine di a funzione. Object.cpp 424

A situazione hè simile à a precedente. Si deve esse scrittu:

this->Size += this->EntrySize;

Fragment N38-N47: Anu scurdatu di verificà l'indici

Nanzu, avemu vistu esempi di triggering diagnosticu V595. A so essenza hè chì u puntatore hè dereferenced à u principiu, è solu dopu verificatu. Young diagnostics V1004 hè u cuntrariu in u significatu, ma revela ancu assai errori. Identifica situazioni induve l'indicatore hè stata verificata à u principiu è dopu scurdatu di fà. Fighjemu tali casi truvati in LLVM.

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

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

Avvisu PVS-Studio: V1004 [CWE-476] U puntatore "Ptr" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 729, 738. TargetTransformInfoImpl.h 738

Variable Ptr pò esse uguali nullptr, cum'è pruvucatu da u cuntrollu:

if (Ptr != nullptr)

Tuttavia, sottu à questu punteru hè dereferenziatu senza verificazione preliminare:

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

Fighjemu un altru casu simili.

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

Avvisu PVS-Studio: V1004 [CWE-476] U puntatore "FD" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 3228, 3231. CGDebugInfo.cpp 3231

Attenti à u signu FD. Sò sicuru chì u prublema hè chjaramente visibile è ùn hè micca necessariu una spiegazione speciale.

È in più:

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

Avvisu PVS-Studio: V1004 [CWE-476] U puntatore "PtrTy" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 960, 965. InterleavedLoadCombinePass.cpp 965

Cumu prutezzione di tali errori? Siate più attenti à Code-Review è utilizate l'analizzatore staticu PVS-Studio per verificà regularmente u vostru codice.

Ùn ci hè nunda di cità altri frammenti di codice cù errori di stu tipu. Lasceraghju solu una lista di avvisi in l'articulu:

  • V1004 [CWE-476] U puntatore "Expr" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] L'indicatore "PI" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] U puntatore "StatepointCall" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] U puntatore "RV" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] U puntatore "CalleeFn" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] U puntatore "TC" hè statu utilizatu in modu inseguru dopu chì hè statu verificatu contru nullptr. Verificate e linee: 1819, 1824. Driver.cpp 1824

Fragment N48-N60: Ùn hè micca criticu, ma un difettu (possibile fuga di memoria)

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

Avvisu di PVS-Studio: V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Strategies" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-isel-fuzzer.cpp 58

Per aghjunghje un elementu à a fine di un containeru cum'è std::vector > ùn pudete micca scrive solu xxx.push_back (nova X), postu chì ùn ci hè micca cunversione implicita da X* в std::unique_ptr.

Una suluzione cumuni hè di scrive xxx.emplace_back (nova X)postu ch’ellu compie : mètudu emplace_back custruisce un elementu direttamente da i so argumenti è ponu dunque aduprà constructori espliciti.

Ùn hè micca sicuru. Se u vettore hè pienu, allora a memoria hè riassignata. L'operazione di riallocazione di a memoria pò fallu, risultandu in un'eccezione chì hè ghjittata std::bad_alloc. In questu casu, u puntatore serà persu è l'ughjettu creatu ùn serà mai sguassatu.

Una suluzione sicura hè di creà unicu_ptrchì pussederà u puntatore prima chì u vettore prova di riallocà a memoria:

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

Dapoi C ++ 14, pudete aduprà 'std::make_unique':

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

Stu tipu di difettu ùn hè micca criticu per LLVM. Se a memoria ùn pò micca esse attribuita, u compilatore si ferma solu. Tuttavia, per applicazioni cù longu uptime, chì ùn pò micca solu finisce se l'allocazione di memoria falla, questu pò esse un veru bug.

Allora, ancu s'ellu ùn hè micca una minaccia pratica per LLVM, aghju trovu utile per parlà di stu mudellu d'errore è chì l'analizzatore PVS-Studio hà amparatu à identificà.

Altri avvisi di stu tipu:

  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Passi" cù u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. PassManager.h 546
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "AAs" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. AliasAnalysis.h 324
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Entries" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "AllEdges" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. CFGMST.h 268
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "VMaps" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Records" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. FDRLogBuilder.h 30
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "PendingSubmodules" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. ModuleMap.cpp 810
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Objects" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. DebugMap.cpp 88
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u cuntinuu "Strategies" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 685
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 686
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 688
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 689
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 690
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 691
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 692
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 693
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Modificatori" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. llvm-stress.cpp 694
  • V1023 [CWE-460] Un punteru senza pruprietariu hè aghjuntu à u containeru "Operandi" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Stash" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Un puntatore senza pruprietariu hè aghjuntu à u containeru "Matchers" da u metudu "emplace_back". Una fuga di memoria si verifica in casu d'eccezzioni. GlobalISelEmitter.cpp 2702

cunchiusioni

Aghju emessu 60 avvisi in totale è poi si fermò. Ci sò altri difetti chì l'analizzatore PVS-Studio detecta in LLVM? Iè, aghju. In ogni casu, quandu scriveva frammenti di codice per l'articulu, era a sera tardi, o piuttostu ancu a notte, è decisu chì era ora di chjamà un ghjornu.

Spergu chì avete trovu interessante è vulete pruvà l'analizzatore PVS-Studio.

Pudete scaricà l'analizzatore è uttene a chjave di a caccia di mine à sta pagina.

U più impurtante, aduprate l'analisi statica regularmente. Cuntrolli una volta, realizatu da noi per popularizà a metodulugia di l'analisi statica è PVS-Studio ùn sò micca un scenariu normale.

Bona furtuna à migliurà a qualità è a affidabilità di u vostru codice!

Truvà bug in LLVM 8 utilizendu l'analizzatore PVS-Studio

Se vulete sparte stu articulu cù un publicu anglofonu, per piacè utilizate u ligame di traduzzione: Andrey Karpov. Truvà Bugs in LLVM 8 cù PVS-Studio.

Source: www.habr.com

Add a comment