Suchen von Fehlern in LLVM 8 mit PVS-Studio

PVS-Studio und LLVM 8.0.0

Es ist zwei Jahre her, seit wir den Code des LLVM-Projekts das letzte Mal mit PVS-Studio überprüft haben. Lassen Sie uns also sehen, ob PVS-Studio immer noch führend unter den Tools zur Erkennung von Fehlern und Sicherheitslücken ist. Dazu scannen wir die Version LLVM 8.0.0 nach neuen Fehlern.

Der Artikel, der geschrieben werden muss


Ehrlich gesagt hatte ich keine Lust, diesen Artikel zu schreiben. Es macht nicht viel Spaß, über das Projekt zu sprechen, das wir bereits mehrmals überprüft haben ( 1 , 2 , 3 ). Ich würde stattdessen etwas Neues bevorzugen, aber ich hatte keine Wahl.

Jedes Mal, wenn eine neue Version von LLVM veröffentlicht oder der Clang Static Analyzer aktualisiert wird, erhalten wir E-Mails in dieser Richtung:

Hey, die neue Version von Clang Static Analyzer hat eine neue Diagnose bekommen! PVS-Studio scheint weniger relevant zu werden. Clang kann mehr Fehler als zuvor erkennen und holt jetzt PVS-Studio ein. Was hast du gesagt

Darauf würde ich gerne antworten:

Wir haben auch nicht faulenzen! Wir haben die Fähigkeiten von PVS-Studio erheblich verbessert, also keine Sorge - wir sind immer noch die Besten.

Aber das ist leider eine schlechte Antwort. Es bietet keine Beweise, und das ist der Grund, warum ich diesen Artikel schreibe. Also habe ich LLVM noch einmal überprüft und Tonnen von Fehlern aller Art gefunden. Diejenigen, die mir am besten gefallen haben, werden weiter besprochen. Clang Static Analyzer kann diese Fehler nicht erkennen (oder macht den Prozess sehr mühsam) - und wir können. Übrigens habe ich nur einen Abend gebraucht, um all diese Fehler aufzuschreiben.

Die Fertigstellung des Artikels dauerte jedoch mehrere Wochen. Ich konnte mich einfach nicht dazu bringen, das gesammelte Material in Text zu schreiben :).

Wenn Sie sich fragen, welche Techniken PVS-Studio verwendet, um Fehler und Schwachstellen zu erkennen, lesen Sie diesen Beitrag .

Neue und bestehende Diagnose


Wie ich bereits sagte, wurde die letzte der vielen LLVM-Überprüfungen vor zwei Jahren durchgeführt, und die damals gefundenen Fehler wurden von den Autoren behoben. Dieser Artikel zeigt einen neuen Teil der Fehler. Wie kommt es, dass es überhaupt neue Fehler gibt? Es gibt drei Gründe:

  1. Das LLVM-Projekt entwickelt sich weiter. Die Autoren ändern vorhandenen Code und fügen neuen Code hinzu. Sowohl modifizierte als auch neue Teile haben natürlich neue Fehler. Diese Tatsache ist ein starkes Argument dafür, regelmäßig statische Analysen durchzuführen und nicht ab und zu. Das Format unserer Artikel ist perfekt, um die Funktionen von PVS-Studio zu demonstrieren, hat jedoch nichts damit zu tun, die Codequalität zu verbessern oder die Fehlerbehebung kostengünstiger zu gestalten. Verwenden Sie regelmäßig statische Analysen!
  2. Wir modifizieren und verbessern vorhandene Diagnosen, sodass der Analysator Fehler erkennen kann, die er zuvor nicht erkennen konnte.
  3. PVS-Studio wurde um eine neue Diagnose erweitert, die es vor zwei Jahren noch nicht gab. Ich habe solche Warnungen in einem separaten Abschnitt zusammengefasst, damit der Fortschritt von PVS-Studio deutlicher sichtbar wird.

Durch vorhandene Diagnose festgestellte Mängel


Snippet Nr. 1: Kopieren-Einfügen

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-Diagnosemeldung: V501 [CWE-570] Es gibt identische Unterausdrücke 'Name.startswith ("avx512.mask.permvar.")' Links und rechts von '||' Betreiber. AutoUpgrade.cpp 73

Das Auftreten der "avx512.mask.permvar". Teilzeichenfolge wird zweimal überprüft. Die zweite Bedingung war offensichtlich, etwas anderes zu überprüfen, aber der Programmierer vergaß, die kopierte Zeile zu ändern.

Snippet Nr. 2: Tippfehler

 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-Diagnosemeldung: V501 Links und rechts vom '|' befinden sich identische Unterausdrücke 'CXNameRange_WantQualifier'. Betreiber. CIndex.cpp 7245

Die benannte Konstante CXNameRange_WantQualifier wird aufgrund eines Tippfehlers zweimal verwendet.

Snippet Nr. 3: Verwirrung über den Vorrang des Bedieners

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

PVS-Studio-Diagnosemeldung: V502 [CWE-783] Möglicherweise funktioniert der Operator '?:' Anders als erwartet. Der Operator '?:' Hat eine niedrigere Priorität als der Operator '=='. PPCTargetTransformInfo.cpp 404

Ich finde diesen Bug sehr süß. Ja, ich weiß, dass ich einen seltsamen Geschmack habe :).

Gemäß der Priorität des Operators wird der ursprüngliche Ausdruck wie folgt ausgewertet:

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

Aus praktischer Sicht ist diese Bedingung jedoch nicht sinnvoll, da sie reduziert werden kann auf:

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

Dies ist offensichtlich ein Fehler. Es muss die Indexvariable gewesen sein , die der Programmierer auf 0/1 prüfen wollte. Um den Code zu korrigieren, sollte der ternäre Operator in Klammern gesetzt werden:

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

Der ternäre Operator ist tatsächlich sehr knifflig und kann zu logischen Fehlern führen. Gehen Sie vorsichtig damit um und zögern Sie nicht, zusätzliche Klammern zu setzen. Dieses Thema wird hier im Abschnitt "Vorsicht vor dem Operator?: Operator und in Klammern setzen" ausführlicher behandelt.

Schnipsel Nr. 4, 5: Nullzeiger

 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-Diagnosemeldung: V522 [CWE-476] Möglicherweise findet eine Dereferenzierung des Nullzeigers 'LHS' statt. TGParser.cpp 2152

Wenn der LHS- Zeiger zufällig null ist, wird erwartet, dass das Programm eine Warnung generiert. Stattdessen wird dieser Nullzeiger dereferenziert: LHS-> getAsString () .

Es ist eine typische Situation für Fehlerbehandler, Fehler zu enthalten, da Entwickler sie nicht richtig testen. Statische Analysatoren überprüfen den gesamten erreichbaren Code, unabhängig davon, wie oft er tatsächlich ausgeführt wird. Dies ist ein gutes Beispiel dafür, wie die statische Analyse andere Codetest- und Schutzmittel ergänzt.

Ein ähnlicher fehlerhafter Handler für den RHS- Zeiger befindet sich etwas weiter entfernt: V522 [CWE-476] Eine Dereferenzierung des Nullzeigers 'RHS' kann stattfinden. TGParser.cpp 2186

Snippet Nr. 6: Verwenden eines Zeigers nach einer Bewegung

 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-Diagnosemeldung: V522 [CWE-476] Möglicherweise findet eine Dereferenzierung des Nullzeigers 'ProgClone' statt. Miscompilation.cpp 601

Der Smart Pointer ProgClone gibt zuerst den Objektbesitz frei:

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

Tatsächlich ist ProgClone zu einem Nullzeiger geworden. Technisch gesehen wird ein Nullzeiger also etwas weiter dereferenziert:

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

Das wird aber nicht passieren! Beachten Sie, dass die Schleife überhaupt nicht ausgeführt wird.

Der MiscompiledFunctions- Container wird zuerst gelöscht:

 MiscompiledFunctions.clear(); 

Und dann wird seine Größe in der Schleifenbedingung verwendet:

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

Offensichtlich startet die Schleife einfach nicht. Ich denke, es ist auch ein Fehler, und der Code sollte irgendwie anders aussehen.

Ich denke, was wir hier sehen, ist diese berüchtigte Fehlerparität, bei der ein Fehler als Verkleidung für einen anderen fungiert :).

Snippet Nr. 7: Verwenden eines Zeigers nach einer Bewegung

 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-Diagnosemeldung: V522 [CWE-476] Möglicherweise findet eine Dereferenzierung des Nullzeigers 'Test' statt. Miscompilation.cpp 709

Dieser ist dem vorherigen Fall ähnlich. Der Inhalt des Objekts wird zuerst verschoben und dann so verwendet, als wäre nichts passiert. Dieser Fehler tritt immer häufiger auf, nachdem C ++ eine Verschiebungssemantik hinzugefügt wurde. Das gefällt mir an dieser Sprache! Sie erhalten neue Möglichkeiten, sich in den Fuß zu schießen, was bedeutet, dass PVS-Studio immer Arbeit zu erledigen hat :).

Snippet Nr. 8: Nullzeiger

 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-Diagnosemeldung: V522 [CWE-476] Möglicherweise findet eine Dereferenzierung des Nullzeigers 'Typ' statt. PrettyFunctionDumper.cpp 233

Genau wie Fehlerbehandler erhalten Testfunktionen, die Debug-Daten drucken, normalerweise auch keine ausreichende Testabdeckung, und dies ist ein Beispiel dafür. Anstatt dem Benutzer bei der Lösung seiner Probleme zu helfen, wartet die Funktion darauf, dass er sie behebt.

Fester Code:

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

Snippet Nr. 9: Nullzeiger

 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-Diagnosemeldung: V522 [CWE-476] Möglicherweise findet eine Dereferenzierung des Nullzeigers 'Ty' statt. SearchableTableEmitter.cpp 614

Ich glaube nicht, dass Sie dazu Kommentare benötigen.

Snippet Nr. 10: Tippfehler

 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-Diagnosemeldung: V570 Die Variable 'Identifier-> Type' wird sich selbst zugewiesen. FormatTokenLexer.cpp 249

Das Zuweisen einer Variablen zu sich selbst ist eine bedeutungslose Operation. Der Programmierer muss Folgendes beabsichtigt haben:

 Identifier->Type = Question->Type; 

Snippet Nr. 11: Verdächtige Pause

 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-Diagnosemeldung: V622 [CWE-478] Überprüfen Sie die Anweisung 'switch'. Möglicherweise fehlt der erste 'case'-Operator. SystemZAsmParser.cpp 652

Am Anfang steht eine sehr verdächtige Unterbrechungserklärung . Sollte es hier nicht noch etwas geben?

Snippet Nr. 12: Überprüfen eines Zeigers nach der Dereferenzierung

 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-Diagnosemeldung: V595 [CWE-476] Der Zeiger 'Callee' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 172, 174. AMDGPUInline.cpp 172

Der Callee- Zeiger wird zuerst dereferenziert, wenn die Funktion getTTI aufgerufen wird.

Und dann stellt sich heraus, dass der Zeiger auf nullptr überprüft werden sollte :

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

Zu spät ...

Schnipsel Nr. 13 - Nein ....: Überprüfen eines Zeigers nach der Dereferenzierung

Das vorherige Beispiel ist nicht eindeutig. Das gleiche Problem findet sich in diesem Snippet:

 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-Diagnosemeldung: V595 [CWE-476] Der Zeiger 'CalleeFn' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1079, 1081. SimplifyLibCalls.cpp 1079

Und dieser:

 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-Diagnosemeldung: V595 [CWE-476] Der Zeiger 'ND' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Und hier:

  • V595 [CWE-476] Der 'U'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 404, 407. DWARFFormValue.cpp 404
  • V595 [CWE-476] Der 'ND'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Dann habe ich das Interesse an der Verfolgung von V595-Warnungen verloren, sodass ich Ihnen nicht sagen kann, ob es neben den oben gezeigten noch andere Fehler dieses Typs gibt. Ich wette, es gibt.

Schnipsel Nr. 17, 18: Verdächtige Verschiebung

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

PVS-Studio-Diagnosemeldung: V629 [CWE-190] Überprüfen Sie den Ausdruck '~ (Größe - 1) << 1'. Bitverschiebung des 32-Bit-Werts mit anschließender Erweiterung auf den 64-Bit-Typ. AArch64AddressingModes.h 260

Dieser Code mag tatsächlich korrekt sein, sieht aber seltsam aus und muss überprüft werden.

Angenommen, die Variable Size hat den Wert 16. Dann wird erwartet, dass die NImms- Variable den folgenden Wert erhält:

1111111111111111111111111111111111111111111111111111111111111100000000

Aber in Wirklichkeit wird es den Wert bekommen:

000000000000000000000000000000000000111111111111111111111111111111000000

Dies geschieht, weil alle Berechnungen für den 32-Bit-Typ ohne Vorzeichen durchgeführt werden und erst dann implizit auf uint64_t hochgestuft wird , wobei die höchstwertigen Bits auf Null gesetzt werden.

Das Problem kann wie folgt behoben werden:

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

Ein weiterer Fehler dieses Typs: V629 [CWE-190] Überprüfen Sie den Ausdruck 'Immr << 6'. Bitverschiebung des 32-Bit-Werts mit anschließender Erweiterung auf den 64-Bit-Typ. AArch64AddressingModes.h 269

Snippet Nr. 19: Fehlt sonst noch ein Keyword ?

 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-Diagnosemeldung: V646 [CWE-670] Überprüfen Sie die Logik der Anwendung. Möglicherweise fehlt das Schlüsselwort "else". AMDGPUAsmParser.cpp 5655

Dieser ist kein Fehler. Da der then- Block der ersten if- Anweisung mit continue endet, spielt es keine Rolle, ob er das Schlüsselwort else enthält oder nicht. Das Verhalten ist in jedem Fall das gleiche. Das fehlende Sonst macht den Code jedoch weniger lesbar und daher potenziell gefährlich. Wenn die Fortsetzung eines Tages verschwindet, ändert sich das Verhalten drastisch. Ich empfehle dringend, etwas anderes hinzuzufügen.

Snippet Nr. 20: Vier identische Tippfehler

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

  • V655 [CWE-480] Die Zeichenfolgen wurden verkettet, aber nicht verwendet. Überprüfen Sie den Ausdruck 'Ergebnis + Name.str ()'. Symbol.cpp 32
  • V655 [CWE-480] Die Zeichenfolgen wurden verkettet, aber nicht verwendet. Überprüfen Sie den Ausdruck 'Ergebnis + "(ObjC-Klasse)" + Name.str ()'. Symbol.cpp 35
  • V655 [CWE-480] Die Zeichenfolgen wurden verkettet, aber nicht verwendet. Überprüfen Sie den Ausdruck 'Ergebnis + "(ObjC-Klasse EH)" + Name.str ()'. Symbol.cpp 38
  • V655 [CWE-480] Die Zeichenfolgen wurden verkettet, aber nicht verwendet. Überprüfen Sie den Ausdruck 'Ergebnis + "(ObjC IVar)" + Name.str ()'. Symbol.cpp 41

Der Programmierer hat versehentlich den Operator + anstelle von + = verwendet und am Ende vier bedeutungslose Konstrukte erhalten.

Snippet Nr. 21: Undefiniertes Verhalten

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

Versuchen Sie zuerst, den Fehler selbst zu erkennen. Ich habe das Bild hinzugefügt, damit Sie nicht sofort auf die Antwort schauen:

???


PVS-Studio-Diagnosemeldung: V708 [CWE-758] Es wird eine gefährliche Konstruktion verwendet: 'FeaturesMap [Op] = FeaturesMap.size ()', wobei 'FeaturesMap' der Klasse 'map' entspricht. Dies kann zu undefiniertem Verhalten führen. RISCVCompressInstEmitter.cpp 490

Die fehlerhafte Leitung ist diese:

 FeaturesMap[Op] = FeaturesMap.size(); 

Wenn das Op- Element nicht gefunden wurde, erstellt das Programm ein neues Element in der Karte und weist ihm die Gesamtzahl der Elemente in dieser Karte zu. Sie wissen nur nicht, ob die Größenfunktion vor oder nach dem Hinzufügen des neuen Elements aufgerufen wird.

Schnipsel Nr. 22 - Nein. 24: doppelte Zuordnungen

 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-Diagnosemeldung: V519 [CWE-563] Der Variablen 'NType' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 1663, 1664. MachOObjectFile.cpp 1664

Ich denke nicht, dass es ein wahrer Fehler ist - eher eine doppelte Zuordnung. Aber es ist immer noch ein Defekt.

Zwei weitere Fälle:

  • V519 [CWE-563] Der Variablen 'B.NDesc' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Prüflinien: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Der Variablen werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 59, 61. coff2yaml.cpp 61

Schnipsel Nr. 25 - Nein. 27: Mehr doppelte Zuordnungen

Diese befassen sich mit leicht unterschiedlichen Versionen doppelter Zuweisungen.

 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-Diagnosemeldung: V519 [CWE-563] Der Variablen 'Alignment' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 1158, 1160. LoadStoreVectorizer.cpp 1160

Dies ist ein sehr seltsamer Ausschnitt, der wahrscheinlich einen logischen Fehler enthält. Der Ausrichtungsvariablen wird zuerst der Wert basierend auf der Bedingung zugewiesen, und dann wird der Wert erneut zugewiesen, jedoch ohne vorherige Überprüfung.

Ähnliche Mängel:

  • V519 [CWE-563] Der Variablen 'Effekte' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Der Variablen 'ExpectNoDerefChunk' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 4970, 4973. SemaType.cpp 4973

Snippet Nr. 28: Immer wahrer Zustand

 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-Diagnosemeldung: V547 [CWE-571] Der Ausdruck 'nextByte! = 0x90' ist immer wahr. X86DisassemblerDecoder.cpp 379

Die Prüfung macht keinen Sinn. Die nextByte- Variable ist niemals gleich 0x90 : Sie folgt nur logisch aus der vorherigen Prüfung. Dies muss ein logischer Fehler sein.

Schnipsel Nr. 29 - Nein ....: Immer wahre / falsche Bedingungen

Es gibt viele Warnungen, dass eine ganze Bedingung ( V547 ) oder ein Teil einer Bedingung ( V560 ) immer wahr oder falsch ist. Anstelle von echten Fehlern handelt es sich häufig nur um schlechten Code, die Auswirkungen der Makroerweiterung usw. Trotzdem sollten alle derartigen Warnungen überprüft werden, da einige von ihnen auf echte Logikfehler hinweisen können. Das folgende Snippet sieht beispielsweise nicht richtig aus:

 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-Diagnosemeldung: V560 [CWE-570] Ein Teil des bedingten Ausdrucks ist immer falsch: RegNo == 0xe. ARMDisassembler.cpp 939

Die 0xE- Konstante ist die Dezimalzahl 14. Die Prüfung RegNo == 0xe ist nicht sinnvoll, da die Funktion zurückgegeben wird, wenn RegNo> 13 ist.

Ich habe viele andere V547- und V560-Warnungen gesehen, aber wie bei V595 war ich nicht begeistert, sie zu überprüfen, da ich bereits genug Material für einen Artikel hatte :). Also keine Zahlen für die Gesamtzahl der Fehler dieses Typs in LLVM.

Hier ist ein Beispiel, um zu veranschaulichen, warum das Überprüfen dieser Warnungen langweilig ist. Der Analysator ist völlig korrekt, wenn eine Warnung zum folgenden Code ausgegeben wird. Aber es ist immer noch kein Fehler.

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

PVS-Studio-Diagnosemeldung: V547 [CWE-570] Der Ausdruck '! HasError' ist immer falsch. UnwrappedLineParser.cpp 1635

Snippet Nr. 30: Verdächtige Rückkehr

 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-Diagnosemeldung: V612 [CWE-670] Eine bedingungslose 'Rückgabe' innerhalb einer Schleife. R600OptimizeVectorRegisters.cpp 63

Es ist entweder ein Fehler oder eine bestimmte Codierungstechnik, die anderen Programmierern eine Idee vermitteln soll. Für mich sagt es nichts aus, außer dass es ein sehr verdächtiger Code ist. Bitte schreibe keinen solchen Code :).

Fühlen Sie sich müde? OK, es ist Zeit, Tee oder Kaffee zu kochen.

Kaffee


Durch neue Diagnose festgestellte Mängel


Ich denke, 30 Beispiele reichen für die bestehende Diagnose. Lassen Sie uns nun sehen, ob wir mit der neuen Diagnose, die nach der vorherigen Überprüfung hinzugefügt wurde, etwas Interessantes finden können. In den letzten zwei Jahren wurde das C ++ - Analysatormodul um 66 neue Diagnosen erweitert.

Snippet Nr. 31: Nicht erreichbarer Code

 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-Diagnosemeldung: V779 [CWE-561] Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. ExecutionUtils.cpp 146

Wie Sie sehen können, enden beide Zweige der if- Anweisung mit einer return- Anweisung, was bedeutet, dass der CtorDtorsByPriority- Container niemals gelöscht wird.

Snippet Nr. 32: Nicht erreichbarer Code

 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-Diagnosemeldung: V779 [CWE-561] Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. LLParser.cpp 835

Dieser ist interessant. Schauen Sie sich zuerst diesen Teil an:

 return ParseTypeIdEntry(SummaryID); break; 

An diesem Code scheint nichts Seltsames zu sein. Die break- Anweisung ist nicht erforderlich und kann sicher entfernt werden. Aber so einfach ist das nicht.

Die Warnung wird durch folgende Zeilen ausgelöst:

 Lex.setIgnoreColonInIdentifiers(false); return false; 

In der Tat ist dieser Code nicht erreichbar. Alle Fallbezeichnungen der switch- Anweisung enden mit einer Rückgabe , und die bedeutungslose Einzelpause sieht nicht mehr so ​​harmlos aus! Was wäre, wenn einer der Zweige eher mit einer Pause als mit einer Rückkehr enden sollte?

Snippet Nr. 33: Versehentliches Löschen der höchstwertigen Bits

 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-Diagnosemeldung: V784 Die Größe der Bitmaske ist kleiner als die Größe des ersten Operanden. Dies führt zum Verlust höherer Bits. RuntimeDyld.cpp 815

Beachten Sie, dass die Funktion getStubAlignment einen vorzeichenlosen Wert zurückgibt. Mal sehen, wie der Ausdruck ausgewertet wird, vorausgesetzt, die Funktion gibt den Wert 8 zurück:

~ (getStubAlignment () - 1)

~ (8u-1)

0xFFFFFFF8u

Beachten Sie jetzt, dass der Typ der DataSize- Variablen 64-Bit ohne Vorzeichen ist. Es stellt sich also heraus, dass das Ausführen der Operation DataSize & 0xFFFFFFF8 dazu führt, dass alle 32 höchstwertigen Bits des Werts gelöscht werden. Ich glaube nicht, dass der Programmierer das wollte. Vielleicht meinten sie es DataSize & 0xFFFFFFFFFFFFFFFFF8u.

Um den Fehler zu beheben, sollte der Code folgendermaßen umgeschrieben werden:

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

Oder so:

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

Snippet Nr. 34: Schlechte explizite Typkonvertierung

 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-Diagnosemeldung: V1028 [CWE-190] Möglicher Überlauf. Ziehen Sie in Betracht, Operanden des Operators 'NumElts * Scale' in den Typ 'size_t' umzuwandeln, nicht in das Ergebnis. X86ISelLowering.h 1577

Die explizite Typkonvertierung wird verwendet, um einen Überlauf beim Multiplizieren von Variablen vom Typ int zu vermeiden. In diesem Fall funktioniert dies jedoch nicht, da die Multiplikation zuerst erfolgt und erst dann das 32-Bit-Ergebnis auf den Typ size_t hochgestuft wird .

Snippet Nr. 35: Schlechtes Kopieren und Einfügen

 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] Es wurden zwei ähnliche Codefragmente gefunden. Möglicherweise ist dies ein Tippfehler und die Variable 'Op1' sollte anstelle von 'Op0' verwendet werden. InstCombineCompares.cpp 5507

Diese neue coole Diagnose erkennt Situationen, in denen ein Codefragment mithilfe von Copy-Paste geschrieben wird, wobei alle Namen bis auf einen geändert werden.

Beachten Sie, dass alle Op0s außer einem im zweiten Block in Op1 geändert wurden. Der Code sollte wahrscheinlich so aussehen:

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

Snippet Nr. 36: Variablen verwechselt

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

PVS-Studio-Diagnosemeldung: V1001 [CWE-563] Die Variable 'Mode' wird zugewiesen, aber am Ende der Funktion nicht verwendet. SIModeRegister.cpp 48

Es ist sehr gefährlich, für Funktionsargumente dieselben Namen zu haben wie für Klassenmitglieder, da Sie das Risiko haben, sie zu verwechseln. Was Sie hier sehen, ist ein Beispiel dafür. Der folgende Ausdruck ist bedeutungslos:

 Mode &= Mask; 

Das Argument wird geändert, aber danach nie mehr verwendet. Dieses Snippet sollte wahrscheinlich so aussehen:

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

Snippet Nr. 37: Variablen verwechselt

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

PVS-Studio-Diagnosemeldung: V1001 [CWE-563] Die Variable 'Größe' wird zugewiesen, aber am Ende der Funktion nicht verwendet. Object.cpp 424

Dieser ähnelt dem vorherigen Beispiel. Richtige Version:

 this->Size += this->EntrySize; 

Schnipsel Nr. 38 - Nein. 47: Fehlende Zeigerprüfung

Wir haben uns einige Beispiele für die V595- Warnung etwas früher angesehen. Was es erkennt, ist eine Situation, in der ein Zeiger zuerst dereferenziert und erst dann überprüft wird. Die neue Diagnose V1004 ist das Gegenteil davon und erkennt auch Unmengen von Fehlern. Es wird nach bereits getesteten Zeigern gesucht, die bei Bedarf nicht erneut getestet werden. Hier sind einige Fehler dieses Typs im LLVM-Code.

 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-Diagnosemeldung: V1004 [CWE-476] Der 'Ptr'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 729, 738. TargetTransformInfoImpl.h 738

Ptr kann nullptr sein , was durch die Prüfung angezeigt wird:

 if (Ptr != nullptr) 

Derselbe Zeiger wird jedoch ohne eine solche Prüfung etwas weiter dereferenziert:

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

Ein weiterer ähnlicher Fall.

 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-Diagnosemeldung: V1004 [CWE-476] Der 'FD'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 3228, 3231. CGDebugInfo.cpp 3231

Beachten Sie den FD- Zeiger. Dieser Fehler ist unkompliziert, daher keine Kommentare zu diesem.

Noch eine hier:

 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-Diagnosemeldung: V1004 [CWE-476] Der Zeiger 'PtrTy' wurde unsicher verwendet, nachdem er gegen nullptr überprüft wurde. Überprüfen Sie die Zeilen: 960, 965. InterleavedLoadCombinePass.cpp 965

Wie vermeidet man solche Fehler? Seien Sie sehr vorsichtig, wenn Sie Ihren Code überprüfen, und überprüfen Sie ihn regelmäßig mit PVS-Studio.

Ich denke nicht, dass wir andere Beispiele dieses Typs untersuchen sollten, daher hier nur eine Liste der Warnungen:
  • V1004 [CWE-476] Der Zeiger 'Expr' wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Der 'PI'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Der Zeiger 'StatepointCall' wurde unsicher verwendet, nachdem er gegen nullptr überprüft wurde. Überprüfen Sie die Zeilen: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Der 'RV'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Der 'CalleeFn'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Der 'TC'-Zeiger wurde unsicher verwendet, nachdem er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1819, 1824. Driver.cpp 1824

Schnipsel Nr. 48 - Nein. 60: Nicht kritisch, aber immer noch ein Defekt (möglicher Speicherverlust)

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

PVS-Studio-Diagnosemeldung: V1023 [CWE-460] Ein Zeiger ohne Eigentümer wird durch die Methode 'emplace_back' zum Container 'Strategies' hinzugefügt. Im Ausnahmefall tritt ein Speicherverlust auf. llvm-isel-fuzzer.cpp 58

Sie können nicht einfach xxx.push_back (neues X) schreiben, um ein Element an einen Container vom Typ std :: vector <std :: unique_ptr <X>> anzuhängen, da keine implizite Umwandlung von X * in std :: unique_ptr <erfolgt X> .

Die beliebte Lösung besteht darin, xxx.emplace_back (neues X) zu schreiben, da es kompilierbar ist: Die Methode emplace_back erstellt das Element direkt aus den Argumenten und kann daher explizite Konstruktoren verwenden.

Diese Lösung ist jedoch nicht sicher. Wenn der Vektor voll ist, wird der Speicher neu zugewiesen. Dieser Vorgang kann fehlschlagen und eine std :: bad_alloc- Ausnahme auslösen . In diesem Fall geht der Zeiger verloren und das Programm kann das erstellte Objekt nicht löschen.

Eine sicherere Lösung besteht darin, ein unique_ptr zu erstellen, das den Zeiger beibehält , bis der Vektor versucht, den Speicher neu zuzuweisen:

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

Mit dem C ++ 14-Standard können Sie 'std :: make_unique' verwenden:

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

Diese Art von Defekt hat keine Auswirkung auf LLVM. Die Kompilierung wird einfach beendet, wenn die Speicherzuordnung fehlschlägt. Dies kann jedoch bei Anwendungen mit langer Betriebszeit sehr kritisch sein, die nicht einfach beendet werden können, wenn ein Speicherzuordnungsfehler auftritt.

Obwohl dieser Code für LLVM nicht gefährlich ist, dachte ich, ich sollte Ihnen dennoch etwas über dieses Fehlermuster und die Tatsache erzählen, dass PVS-Studio es jetzt erkennen kann.

Andere ähnliche Fälle:

  • V1023 [CWE-460] Ein Zeiger ohne Eigentümer wird dem Container 'Passes' durch die Methode 'emplace_back' hinzugefügt. Im Ausnahmefall tritt ein Speicherverlust auf. PassManager.h 546
  • V1023 [CWE-460] A pointer without owner is added to the 'AAs' container by the 'emplace_back' method. A memory leak will occur in case of an exception. AliasAnalysis.h 324
  • V1023 [CWE-460] A pointer without owner is added to the 'Entries' container by the 'emplace_back' method. A memory leak will occur in case of an exception. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] A pointer without owner is added to the 'AllEdges' container by the 'emplace_back' method. A memory leak will occur in case of an exception. CFGMST.h 268
  • V1023 [CWE-460] A pointer without owner is added to the 'VMaps' container by the 'emplace_back' method. A memory leak will occur in case of an exception. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] A pointer without owner is added to the 'Records' container by the 'emplace_back' method. A memory leak will occur in case of an exception. FDRLogBuilder.h 30
  • V1023 [CWE-460] A pointer without owner is added to the 'PendingSubmodules' container by the 'emplace_back' method. A memory leak will occur in case of an exception. ModuleMap.cpp 810
  • V1023 [CWE-460] A pointer without owner is added to the 'Objects' container by the 'emplace_back' method. A memory leak will occur in case of an exception. DebugMap.cpp 88
  • V1023 [CWE-460] A pointer without owner is added to the 'Strategies' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 685
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 686
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 688
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 689
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 690
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 691
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 692
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 693
  • V1023 [CWE-460] A pointer without owner is added to the 'Modifiers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. llvm-stress.cpp 694
  • V1023 [CWE-460] A pointer without owner is added to the 'Operands' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] A pointer without owner is added to the 'Stash' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] A pointer without owner is added to the 'Matchers' container by the 'emplace_back' method. A memory leak will occur in case of an exception. GlobalISelEmitter.cpp 2702

Fazit


Ich schrieb 60 Warnungen auf und hörte damit auf. Hat PVS-Studio andere Fehler in LLVM gefunden? Ja, das hat es getan. Aber als ich die Beispiele aufschrieb, brach die Nacht herein und ich beschloss, aufzuhören.

Ich hoffe, Ihnen hat das Lesen dieses Artikels gefallen und es hat Sie ermutigt, den PVS-Studio-Analysator selbst auszuprobieren.

Besuchen Sie diese Seite , um den Analysator herunterzuladen und einen Testschlüssel zu erhalten.

Verwenden Sie vor allem regelmäßig statische Analysen. Einmalige Überprüfungen , wie sie zur Popularisierung der statischen Analyse und zur Förderung von PVS-Studio durchgeführt werden, sind nicht das normale Szenario.

Viel Glück bei der Verbesserung der Qualität und Zuverlässigkeit Ihres Codes!

Source: https://habr.com/ru/post/de450002/


All Articles