
Több mint két év telt el azóta, hogy utoljára ellenőriztük az LLVM projekt kódját a PVS-Studio analizátorunkkal. Győződjünk meg róla, hogy a PVS-Studio analizátor továbbra is a vezető eszköz a hibák és potenciális sebezhetőségek feltárásában. Ehhez ellenőrizzük és találjunk új hibákat az LLVM 8.0.0 kiadásában.
Cikk, amit meg kell írni
Őszintén szólva, nem volt kedvem megírni ezt a cikket. Nem izgalmas már egy olyan projektről írni, amit már többször is ellenőriztünk (, , ). Jobb lenne valami új dologról írni, de nincs választásom.
Minden alkalommal, amikor új verzió jelenik meg az LLVM-ből vagy frissül a , kérdések érkeznek az e-mailjeinkbe a következő típusban:
Nézd, az új verzió a Clang Static Analyzer most már új hibákat talál! Szerintem a PVS-Studio használatának aktualitása csökken. A Clang több hibát talál, mint valaha, és közelít a PVS-Studio lehetőségeihez. Mit gondolsz erről?
Erre mindig azt szeretném válaszolni, hogy:
Mi sem ülünk tétlen! Jelentősen javítottuk a PVS-Studio analizátor képességeit. Szóval ne aggódj, továbbra is vezető szerepet játszunk, ahogyan eddig.
Sajnos ez egy rossz válasz. Nincs benne bizonyíték. És éppen ezért írom most ezt a cikket. Tehát az LLVM projektet megint ellenőriztük, és különféle hibákat találtunk. Azokat, amelyek számomra érdekesnek tűntek, most bemutatom. Ezeket a hibákat a Clang Static Analyzer nem tudja észlelni (vagy rendkívül kényelmetlen ezt vele megtenni). De mi képesek vagyunk erre. Ráadásul egy este alatt találtam és jegyeztem fel az összes ilyen hibát.
A cikk írása viszont több hétig elhúzódott. Nem tudtam magam rávenni, hogy mindezt szövegformába öntsem : ).
Egyébként, ha érdekel, milyen technológiákat használnak a PVS-Studio analizátorban a hibák és potenciális sebezhetőségek feltárására, javaslom, ismerkedj meg ezzel a .
Új és régi diagnosztikák
Ahogy már említettem, körülbelül két évvel ezelőtt az LLVM projektet ismételten ellenőrizték, és a talált hibákat javították. Most ebben a cikkben egy új adag hibát fogunk bemutatni. Miért találtunk új hibákat? Három oka van ennek:
- Az LLVM projekt fejlődik, a régi kód megváltozik, és új kód jelenik meg. Természetes, hogy a megváltozott és az újonnan írt kódban új hibák lépnek fel. Ez jól szemlélteti, hogy a statikus elemzést rendszeresen alkalmazni kell, nem csak alkalmanként. Cikkink jól bemutatják a PVS-Studio elemző lehetőségeit, de ez nem kapcsolódik a kód minőségének javításához és a hibák javítási költségeinek csökkentéséhez. Használja a statikus kódellenőrzőt rendszeresen!
- Továbbfejlesztjük és tökéletesítjük a már meglévő diagnosztikákat. Ezért az elemző képes olyan hibákra is rámutatni, amelyeket a korábbi ellenőrzések során nem észlelt.
- A PVS-Studio új diagnosztikákkal bővült, amelyek két évvel ezelőtt még nem voltak. Úgy döntöttem, hogy külön szakaszba emelem őket, hogy jól szemléltethessem a PVS-Studio fejlődését.
A két évvel ezelőtti diagnosztikák által észlelt hibák
1. fragement: Másolás-Beillesztés
static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) {
if (Name == "addcarryx.u32" || // Hozzáadva 8.0-ban
....
Name == "avx512.mask.cvtps2pd.128" || // Hozzáadva 7.0-ban
Name == "avx512.mask.cvtps2pd.256" || // Hozzáadva 7.0-ban
Name == "avx512.cvtusi2sd" || // Hozzáadva 7.0-ban
Name.startswith("avx512.mask.permvar.") || // Hozzáadva 7.0 // <=
Name.startswith("avx512.mask.permvar.") || // Hozzáadva 7.0 // <=
Name == "sse2.pmulu.dq" || // Hozzáadva 7.0
Name == "sse41.pmuldq" || // Hozzáadva 7.0
Name == "avx2.pmulu.dq" || // Hozzáadva 7.0
....
}PVS-Studio figyelmeztetés: [CWE-570] Az ‘Name.startswith(«avx512.mask.permvar.»)’ kifejezés mindkét oldalán az ‘||’ operátor mellett azonos rész-kifejezések találhatók. AutoUpgrade.cpp 73
Kétszer ellenőrizték, hogy a név a «avx512.mask.permvar.» karakterlánccal kezdődik. A második ellenőrzésnél nyilvánvalóan valami mást akartak írni, de elfelejtették kijavítani a másolt szöveget.
2. fragement: Elírás
enum CXNameRefFlags {
CXNameRange_WantQualifier = 0x1,
CXNameRange_WantTemplateArgs = 0x2,
CXNameRange_WantSinglePiece = 0x4
};
void AnnotateTokensWorker::HandlePostPonedChildCursor(
CXCursor Cursor, unsigned StartTokenIndex) {
const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier;
....
}PVS-Studio figyelmeztetés: V501 Az ‘CXNameRange_WantQualifier’ kifejezés mindkét oldalán az ‘|’ operátor mellett azonos rész-kifejezések találhatók. CIndex.cpp 7245
Az elírás miatt kétszer használják ugyanazt a névvel rendelkező konstansot CXNameRange_WantQualifier.
3. fragement: Operátor prioritás zűrzavar
int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
....
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
return 0;
....
}PVS-Studio figyelmeztetés: [CWE-783] Talán a ‘?:’ operátor másképp működik, mint ahogy azt várták. A ‘?:’ operátor prioritása alacsonyabb, mint a ‘==’ operátoré. PPCTargetTransformInfo.cpp 404
Véleményem szerint ez egy nagyon szép hiba. Igen, tudom, hogy nekem furcsa elképzeléseim vannak a szépségről :).
Jelenleg a , a kifejezés a következőképpen számítódik ki:
(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0Gyakorlati szempontból ez a feltétel értelmetlen, mivel leegyszerűsíthető a következőre:
(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())Ez egy nyilvánvaló hiba. Valószínűleg a 0/1-et akarták összehasonlítani a változóval Index. A kód javításához zárójeleket kell hozzáadni a ternáris operátor köré:
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))Egyébként a ternáris operátor nagyon veszélyes, és logikai hibákhoz vezethet. Legyen óvatos vele, és ne sajnálja a zárójeleket használni. Ezt a témát már részletesebben tárgyaltam , a „Féljen a ?: operátortól, és zárja le zárójelek közé” fejezetben.
N4, N5 részlet: Nullpointer
Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
....
TypedInit *LHS = dyn_cast(Result);
....
LHS = dyn_cast(
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
->Fold(CurRec));
if (!LHS) {
Error(PasteLoc, Twine("nem lehet átkonvertálni '") + LHS->getAsString() +
"'-t stringgé");
return nullptr;
}
....
}PVS-Studio figyelmeztetés: [CWE-476] A null pointer ‘LHS’ dereferenciálása megtörténhet. TGParser.cpp 2152
Ha a pointer LHS nulla lesz, figyelmeztetést kellene kiadni. De ahelyett, hogy ez megtörténne, a null pointer dereferenciálása fog történni: LHS->getAsString().
Ez egy tipikus helyzet, amikor a hiba az error handlerben bújik meg, mivel azokat senki sem teszteli. A statikus elemzők az összes elérhető kódot ellenőrzik, függetlenül attól, hogy azt mennyire használják. Ez egy nagyon jó példa arra, hogy a statikus analízis kiegészíti a tesztelési és hibaellenőrzési módszereket.
Hasonló pointer kezelési hiba RHS a kód egy kicsit lejjebb is előfordul: V522 [CWE-476] A null pointer ‘RHS’ dereferenciálása megtörténhet. TGParser.cpp 2186
N6 részlet: Pointer használata a mozgatás után
static Expected
ExtractBlocks(....)
{
....
std::unique_ptr ProgClone = CloneModule(BD.getProgram(), VMap);
....
BD.setNewProgram(std::move(ProgClone)); // getFunction(MisCompFunctions[i].first); // <=
assert(NewF && "Funkció nem található??");
MiscompiledFunctions.push_back(NewF);
}
....
}PVS-Studio figyelmeztetés: V522 [CWE-476] A null pointer ‘ProgClone’ dereferenciálása megtörténhet. Miscompilation.cpp 601
Kezdetben az okos pointer ProgClone megszünteti az objektum feletti rendelkezést:
BD.setNewProgram(std::move(ProgClone));Valójában most már ProgClone — ez egy nulla mutató. Ezért alább nulla mutató kiértékelésének kellene végbemennie:
Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);De valójában ez nem fog megtörténni! Vegye észre, hogy a ciklus valójában nem fut végig.
A konténer elején MiscompiledFunctions ki van ürítve:
MiscompiledFunctions.clear();Ezt követően a konténer mérete az ciklus feltételében kerül felhasználásra:
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {Könnyű észrevenni, hogy a ciklus nem indul el. Azt hiszem, ez is hiba, és a kódnak másképp kellene íródnia.
Úgy tűnik, hogy találkoztunk a híres hiba paritásával! Egy hiba elrejti a másikat :).
Fragment N7: Mutató használata áthelyezés után
static Expected TestOptimizer(BugDriver &BD, std::unique_ptr Test,
std::unique_ptr Safe) {
outs() << " Tesztelt funkciók optimalizálása: ";
std::unique_ptr Optimized =
BD.runPassesOn(Test.get(), BD.getPassesToRun());
if (!Optimized) {
errs() << " Hiba a passzek futtatásakor"
<< " a bemeneti programon!n";
BD.setNewProgram(std::move(Test)); // <=
BD.EmitProgressBitcode(*Test, "pass-error", false); // <=
if (Error E = BD.debugOptimizerCrash())
return std::move(E);
return false;
}
....
}Figyelmeztetés PVS-Studio: V522 [CWE-476] A ‘Test’ nulla mutató kiértékelése megtörténhet. Miscompilation.cpp 709
Ismét ugyanaz a helyzet. Eleinte az objektum tartalma áthelyezésre kerül, majd úgy használják, mintha semmi sem történt volna. Egyre gyakrabban találkozom ezzel a helyzettel a programok kódjában, mióta a C++ tartalmazza az áthelyezési szemantikát. Ezért szeretem a C++ nyelvet! Mindig új módok találkoznak önmaguk lábának megsebesítésére. A PVS-Studio elemzője mindig lesz munkája :).
Fragment N8: Nulla mutató
void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
uint32_t TypeId = Symbol.getTypeId();
auto Type = Symbol.getSession().getSymbolById(TypeId);
if (Type)
Printer << "";
else
Type->dump(*this);
}Figyelmeztetés PVS-Studio: V522 [CWE-476] A ‘Type’ nulla mutató kiértékelése megtörténhet. PrettyFunctionDumper.cpp 233
A hiba kezelők mellett általában a debug adatkiíró funkciókat sem tesztelik. Ez egy tipikus eset. A funkció arra vár, hogy a felhasználó, aki a problémáit akarja megoldani, inkább annak megoldásával kell foglalkoznia.
Helyes:
if (Type)
Type->dump(*this);
else
Printer << "";Fragment N9: Nulla mutató
void SearchableTableEmitter::collectTableEntries(
GenericTable &Table, const std::vector &Items) {
....
RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
if (!Ty) // getAsString() + " vs. " + // getType()->getAsString());
....
}PVS-Studio figyelmeztetés: V522 [CWE-476] A null pointer ‘Ty’ dereferálása előfordulhat. SearchableTableEmitter.cpp 614
Azt hiszem, ez így világos, nem igényel további magyarázatot.
N10 fragment: Elírás
bool FormatTokenLexer::tryMergeCSharpNullConditionals() {
....
auto &Identifier = *(Tokens.end() - 2);
auto &Question = *(Tokens.end() - 1);
....
Identifier->ColumnWidth += Question->ColumnWidth;
Identifier->Type = Identifier->Type; // <=
Tokens.erase(Tokens.end() - 1);
return true;
}PVS-Studio figyelmeztetés: Az ‘Identifier->Type’ változó saját magához van rendelve. FormatTokenLexer.cpp 249
Nincs értelme a változót saját magának rendelve. Valószínűleg ezt akarták írni:
Identifier->Type = Question->Type;N11 fragment: Gyanús break
void SystemZOperand::print(raw_ostream &OS) const {
switch (Kind) {
break;
case KindToken:
OS << "Token:" << getToken();
break;
case KindReg:
OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
break;
....
}PVS-Studio figyelmeztetés: [CWE-478] Érdemes lenne megvizsgálni a ‘switch’ utasítást. Lehet, hogy az első ‘case’ operátor hiányzik. SystemZAsmParser.cpp 652
A kezdetben nagyon gyanús az utasítás break. Nem felejtettünk el valamit ide leírni?
N12 fragment: Mutató ellenőrzése dereferálás után
InlineCost AMDGPUInliner::getInlineCost(CallSite CS) {
Function *Callee = CS.getCalledFunction();
Function *Caller = CS.getCaller();
TargetTransformInfo &TTI = TTIWP->getTTI(*Callee);
if (!Callee || Callee->isDeclaration())
return llvm::InlineCost::getNever("undefined callee");
....
}PVS-Studio figyelmeztetés: [CWE-476] A ‘Callee’ mutatót használták, mielőtt ellenőrizték volna a nullptr értéket. Ellenőrizze a következő sorokat: 172, 174. AMDGPUInline.cpp 172
Pointer Callee a funkcióhívás pillanatában dereferálódik getTTI.
És aztán kiderül, hogy ezt a mutatót nullával való egyenlőség ellenőrzéséhez kellene használni nullptr:
if (!Callee || Callee->isDeclaration())De már késő…
N13 fragment — N…: Mutató ellenőrzése dereferálás után
A korábban tárgyalt kódrészlet nem egyedi. Megjelenik itt is:
static Value *optimizeDoubleFP(CallInst *CI, IRBuilder &B,
bool isBinary, bool isPrecise = false) {
....
Function *CalleeFn = CI->getCalledFunction();
StringRef CalleeNm = CalleeFn->getName(); // getAttributes();
if (CalleeFn && !CalleeFn->isIntrinsic()) { // <=
....
}PVS-Studio figyelmeztetés: V595 [CWE-476] A ‘CalleeFn’ mutatót használták, mielőtt ellenőrizték volna a nullptr értéket. Ellenőrizze a következő sorokat: 1079, 1081. SimplifyLibCalls.cpp 1079
És itt is:
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
....
NamedDecl *ND = dyn_cast(New);
CXXRecordDecl *ThisContext =
dyn_cast_or_null(ND->getDeclContext()); // isCXXInstanceMember()); // <=
....
}PVS-Studio figyelmeztetés: V595 [CWE-476] Az ‘ND’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 532, 534. SemaTemplateInstantiateDecl.cpp 532
És itt is:
- V595 [CWE-476] Az ‘U’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 404, 407. DWARFFormValue.cpp 404
- V595 [CWE-476] Az ‘ND’ mutatót a nullptr ellenőrzése előtt használták. Ellenőrizd a következő sorokat: 2149, 2151. SemaTemplateInstantiate.cpp 2149
Aztán már nem volt kedvem tovább tanulmányozni a V595 számú figyelmeztetéseket. Így nem tudom, van-e még hasonló hiba az itt felsoroltakon kívül. Valószínűleg van.
N17, N18 részlet: Kérdőjeles eltolás
static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
uint64_t &Encoding) {
....
unsigned Size = RegSize;
....
uint64_t NImms = ~(Size-1) << 1;
....
}PVS-Studio figyelmeztetés: [CWE-190] Fontold meg az ‘~(Size — 1) << 1’ kifejezés ellenőrzését. A 32-bites érték biteltolása, majd kiterjesztése 64-bites típussá. AArch64AddressingModes.h 260
Lehet, hogy ez nem hiba, és a kód valóban így működik, ahogy tervezték. De ez nyilvánvalóan nagyon gyanús rész, és ellenőrizni kell.
Tegyük fel, hogy a változó Méret 16, és akkor a kód szerzője azt tervezte, hogy a változóban NImms értékét kapja:
1111111111111111111111111111111111111111111111111111111111100000
De valójában az alábbi értéket fogjuk kapni:
0000000000000000000000000000000011111111111111111111111111100000
Az a helyzet, hogy minden számítás 32-bites unsigned típussal történik. Csak ezt követően ez a 32-bites előjel nélküli típus implicit módon kiterjed a uint64_ttípusra. E közben a magasabb bitek nullásak lesznek.
A helyzet javítása érdekében az alábbiakat tehetjük:
uint64_t NImms = ~static_cast(Size-1) << 1;Hasonló helyzet: V629 [CWE-190] Fontold meg az ‘Immr << 6’ kifejezés ellenőrzését. A 32-bites érték biteltolása, majd kiterjesztése 64-bites típussá. AArch64AddressingModes.h 269
N19 részlet: Kulcsszó kihagyva else?
void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
....
if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) {
// VOP2b (v_add_u32, v_sub_u32 ...) dpp használatnál "vcc" token.
// Ugrás.
continue;
} if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) { // <=
Op.addRegWithFPInputModsOperands(Inst, 2);
} else if (Op.isDPPCtrl()) {
Op.addImmOperands(Inst, 1);
} else if (Op.isImm()) {
// Opcionalis argumentumok kezelése
OptionalIdx[Op.getImmTy()] = I;
} else {
llvm_unreachable("Érvénytelen operandus típus");
}
....
}PVS-Studio figyelmeztetés: [CWE-670] Fontold meg az alkalmazás logikájának ellenőrzését. Lehetséges, hogy az ‘else’ kulcsszó hiányzik. AMDGPUAsmParser.cpp 5655
Itt nincs hiba. Mivel az első 'then' blokk véget ér a if végződik continue, nem számít, hogy van-e kulcsszó else vagy nincs. Mindenesetre a kód ugyanúgy fog működni. Ennek ellenére a hiányzó else a kódot érthetetlenebbé és veszélyesebbé teszi. Ha ez a jövőben continue eltűnik, a kód teljesen másképp fog működni. Véleményem szerint jobb, ha hozzáadunk else.
N20. töredék: Négy azonos típusú elírás
LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const {
std::string Result;
if (isUndefined())
Result += "(undef) ";
if (isWeakDefined())
Result += "(gyenge-def) ";
if (isWeakReferenced())
Result += "(gyenge-ref) ";
if (isThreadLocalValue())
Result += "(tlv) ";
switch (Kind) {
case SymbolKind::GlobalSymbol:
Result + Name.str(); // <=
break;
case SymbolKind::ObjectiveCClass:
Result + "(ObjC Osztály) " + Name.str(); // <=
break;
case SymbolKind::ObjectiveCClassEHType:
Result + "(ObjC Osztály EH) " + Name.str(); // <=
break;
case SymbolKind::ObjectiveCInstanceVariable:
Result + "(ObjC IVar) " + Name.str(); // <=
break;
}
OS << Result;
}PVS-Studio figyelmeztetések:
- V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + Name.str()' kifejezés ellenőrzését. Symbol.cpp 32
- V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC Osztály) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 35
- V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC Osztály EH) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 38
- V655 [CWE-480] A karakterláncokat összefűzték, de nem használják. Fontolja meg a 'Result + "(ObjC IVar) " + Name.str()' kifejezés ellenőrzését. Symbol.cpp 41
Véletlenül a += operátor helyett a + operátort használják. Ennek következtében értelmetlen konstrukciók keletkeznek.
N21. töredék: Meghatározatlan viselkedés
static void getReqFeatures(std::map &FeaturesMap,
const std::vector &ReqFeatures) {
for (auto &R : ReqFeatures) {
StringRef AsmCondString = R->getValueAsString("AssemblerCondString");
SmallVector Ops;
SplitString(AsmCondString, Ops, ",");
assert(!Ops.empty() && "AssemblerCondString nem lehet üres");
for (auto &Op : Ops) {
assert(!Op.empty() && "Üres operátor");
if (FeaturesMap.find(Op) == FeaturesMap.end())
FeaturesMap[Op] = FeaturesMap.size();
}
}
}Próbálja meg saját maga megtalálni a veszélyes kódot. Ez egy kép, ami elvonja a figyelmet, hogy ne nézzünk rá azonnal a válaszra:

PVS-Studio figyelmeztetés: [CWE-758] Veszélyes konstrukciót használnak: 'FeaturesMap[Op] = FeaturesMap.size()', ahol a 'FeaturesMap' a 'map' osztályhoz tartozik. Ez meghatározatlan viselkedéshez vezethet. RISCVCompressInstEmitter.cpp 490
Problémás sor:
FeaturesMap[Op] = FeaturesMap.size();Ha az elem Op nem található, új elemet hoznak létre a térképen, amihez a térkép elemeinek számát írják. Csak az nem ismert, hogy a funkció méret meghívásra kerül-e az új elem hozzáadása előtt vagy után.
N22-N24. töredék: Ismételt hozzárendelések
Hiba MachOObjectFile::checkSymbolTable() const {
....
} else {
MachO::nlist STE = getSymbolTableEntry(SymDRI);
NType = STE.n_type; // <=
NType = STE.n_type; // <=
NSect = STE.n_sect;
NDesc = STE.n_desc;
NStrx = STE.n_strx;
NValue = STE.n_value;
}
....
}PVS-Studio figyelmeztetés: [CWE-563] A ‘NType’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 1663, 1664. MachOObjectFile.cpp 1664
Azt hiszem, itt nincs valódi hiba. Csak egy felesleges ismétlődő hozzárendelés van. De így is ügyetlen.
Hasonlóképpen:
- V519 [CWE-563] A ‘B.NDesc’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 1488, 1489. llvm-nm.cpp 1489
- V519 [CWE-563] A változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 59, 61. coff2yaml.cpp 61
N25-N27 fragment: Még több ismétlődő hozzárendelés
Most egy kicsit más típusú ismétlődő hozzárendelést fogunk megvizsgálni.
bool Vectorizer::vectorizeLoadChain(
ArrayRef Chain,
SmallPtrSet *InstructionsProcessed) {
....
unsigned Alignment = getAlignment(L0);
....
unsigned NewAlign = getOrEnforceKnownAlignment(L0->getPointerOperand(),
StackAdjustedAlignment,
DL, L0, nullptr, &DT);
if (NewAlign != 0)
Alignment = NewAlign;
Alignment = NewAlign;
....
}PVS-Studio figyelmeztetés: V519 [CWE-563] Az ‘Alignment’ változó kétszer egymás után értéket kap. Talán ez hibás. Ellenőrizd a következő sorokat: 1158, 1160. LoadStoreVectorizer.cpp 1160
Ez egy nagyon furcsa kód, amely nyilvánvalóan logikai hibát tartalmaz. Elején a változó Alignment értéket kap egy feltétel alapján. Aztán ismét hozzárendelés történik, de most mindenféle ellenőrzés nélkül.
Hasonló helyzetek találhatók itt:
- V519 [CWE-563] Az ‘Effects’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 152, 165. WebAssemblyRegStackify.cpp 165
- V519 [CWE-563] Az ‘ExpectNoDerefChunk’ változó kétszer egymás után értéket kap. Talán ez egy hiba. Ellenőrizd a következő sorokat: 4970, 4973. SemaType.cpp 4973
N28 fragment: Mindig igaz feltétel
static int readPrefixes(struct InternalInstruction* insn) {
....
uint8_t byte = 0;
uint8_t nextByte;
....
if (byte == 0xf3 && (nextByte == 0x88 || nextByte == 0x89 ||
nextByte == 0xc6 || nextByte == 0xc7)) {
insn->xAcquireRelease = true;
if (nextByte != 0x90) // PAUSE utasítás támogatás // <=
break;
}
....
}PVS-Studio figyelmeztetés: [CWE-571] Az ‘nextByte != 0x90’ kifejezés mindig igaz. X86DisassemblerDecoder.cpp 379
Az ellenőrzésnek nincs értelme. A ‘nextByte’ változó mindig nem egyenlő az értékkel , ami a korábbi ellenőrzésből következik. Ez egy logikai hiba. 0x90N29 - N… fragment: Mindig igaz/hamis feltételek
Az elemző sok figyelmeztetést ad arról, hogy az egész feltétel (
) vagy annak része () vagy annak része () mindig igaz vagy hamis. Gyakran nem igazi hibák, hanem csupán hanyag kód, makrók kibővítésének eredménye és hasonlók. Mindazonáltal érdemes megnézni ezeket a figyelmeztetéseket, mert időnként valódi logikai hibák is előfordulnak. Például gyanús ez a kódrészlet:
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder) {
DecodeStatus S = MCDisassembler::Success;
if (RegNo > 13)
return MCDisassembler::Fail;
if ((RegNo & 1) || RegNo == 0xe)
S = MCDisassembler::SoftFail;
....
}PVS-Studio figyelmeztetés: [CWE-570] A feltételes kifejezés egy része mindig hamis: RegNo == 0xe. ARMDisassembler.cpp 939
A 0xE konstanta a tizedes rendszerben 14-es értéket képvisel. Ellenőrzés RegNo == 0xe nincs értelme, mert ha RegNo > 13, akkor a függvény befejezi a végrehajtást.
Sok más figyelmeztetés is volt V547 és V560 azonosítóval, de akárcsak a , számomra unalmas volt ezeket a figyelmeztetéseket tanulmányozni. Így is egyértelmű volt, hogy elég anyagom van egy cikk írásához :). Ezért nem tudni, hogy összesen mennyi ilyen hibát lehet felfedezni az LLVM-ben a PVS-Studio segítségével.
Megmutatok egy példát, miért unalmas ezeket a figyelmeztetéseket vizsgálni. Az elemző teljesen jogosan ad ki figyelmeztetést a következő kódra. De ez nem is hiba.
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
tok::TokenKind ClosingBraceKind) {
bool HasError = false;
....
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
....
}PVS-Studio figyelmeztetés: V547 [CWE-570] Kifejezés ‘!HasError’ mindig hamis. UnwrappedLineParser.cpp 1635
N30 szakasz: Gyanús visszaadás
static bool
isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
for (MachineRegisterInfo::def_instr_iterator It = MRI.def_instr_begin(Reg),
E = MRI.def_instr_end(); It != E; ++It) {
return (*It).isImplicitDef();
}
....
}PVS-Studio figyelmeztetés: [CWE-670] Egy feltétel nélküli ‘return’ egy cikluson belül. R600OptimizeVectorRegisters.cpp 63
Ez vagy hiba, vagy egy specifikus trükk, amely valamit magyaráz a kódot olvasó programozóknak. Számomra egy ilyen konstrukció semmit sem magyaráz, és nagyon gyanúsan néz ki. Jobb, ha nem így írunk :).
Fáradt vagy? Akkor itt az idő, hogy főzz egy csésze teát vagy kávét.

Az új diagnosztikák által felfedezett hibák
Azt hiszem, a 30 régi diagnosztika elég. Nézzük tehát meg, hogy milyen érdekes dolgokat találhatunk új diagnosztikák segítségével, amelyek már az elemzőbe kerültek a ellenőrzés után. Ez idő alatt összesen 66 általános diagnosztika került be a C++ elemzőbe.
N31 szakasz: Elérhetetlen kód
Hiba CtorDtorRunner::run() {
....
ha auto CtorDtorMap =
ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names),
NoDependenciesToRegister, true))
{
....
vissza Error::success();
} máskülönben
vissza CtorDtorMap.takeError();
CtorDtorsByPriority.clear();
vissza Error::success();
}PVS-Studio figyelmeztetés: [CWE-561] Elérhetetlen kód észlelve. Lehetséges, hogy hiba áll fenn. ExecutionUtils.cpp 146
Ahogy látja, az operátor mindkét ága if a hívás végén ér véget return. Ennek megfelelően a tároló CtorDtorsByPriority soha nem lesz törölve.
N32 szakasz: Elérhetetlen kód
bool LLParser::ParseSummaryEntry() {
....
switch (Lex.getKind()) {
case lltok::kw_gv:
vissza ParseGVEntry(SummaryID);
case lltok::kw_module:
vissza ParseModuleEntry(SummaryID);
case lltok::kw_typeid:
vissza ParseTypeIdEntry(SummaryID);
break;
default:
vissza Error(Lex.getLoc(), "váratlan összegzés típusa");
}
Lex.setIgnoreColonInIdentifiers(false);
vissza false;
}PVS-Studio figyelmeztetés: V779 [CWE-561] Elérhetetlen kód észlelve. Lehetséges, hogy hiba áll fenn. LLParser.cpp 835
Érdekes helyzet. Nézzük meg először ezt a részt:
vissza ParseTypeIdEntry(SummaryID);
break;Első pillantásra úgy tűnik, hogy itt nincs hiba. Úgy tűnik, hogy az operátor break itt felesleges, és egyszerűen eltávolítható. Azonban nem minden olyan egyszerű.
Az elemző figyelmeztetést ad a következő sorokra:
Lex.setIgnoreColonInIdentifiers(false);
vissza false;És valóban, ez a kód elérhetetlen. Minden eset a switch az operátor hívásával ér véget. returnÉs most az értelmetlen magányos break nem tűnik oly ártalmatlannak! Talán az egyik ágnak azzal kellene végződnie, break, nem pedig return?
N33 szakasz: Véletlenszerű magasabb bitek nullázása
unsigned getStubAlignment() felülírva {
ha (Arch == Triple::systemz)
vissza 8;
else
vissza 1;
}
Expected
RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
const SectionRef &Section,
bool IsCode) {
....
uint64_t DataSize = Section.getSize();
....
ha (StubBufSize > 0)
DataSize &= ~(getStubAlignment() - 1);
....
}PVS-Studio figyelmeztetés: A bitmaszk mérete kisebb, mint az első operandus mérete. Ez a magasabb bitek elvesztését okozza. RuntimeDyld.cpp 815
Vegye figyelembe, hogy a funkció getStubAlignment visszatér a típussal unsigned. Számoljuk ki a kifejezés értékét, ha feltételezzük, hogy a funkció 8-at ad vissza:
~(getStubAlignment() - 1)
~(8u-1)
0xFFFFFFF8u
Most vegye figyelembe, hogy a változó DataSize 64-bites előjeltelen típussal rendelkezik. Így amikor a DataSize & 0xFFFFFFF8u műveletet végezzük, a harminckét magasabb bit nullázódik. Valószínűleg nem ez volt a programozó szándéka. Gyanítom, hogy azt akarta számolni: DataSize & 0xFFFFFFFFFFFFFFF8u.
A hiba kijavításához így kell írni:
DataSize &= ~(static_cast(getStubAlignment()) - 1);Vagy így:
Adatméret &= ~(getStubAlignment() - 1ULL);N34. sz. töredék: Hibás típus átkonvertálás
sablon <typename T>
visszaad void scaleShuffleMask(int Scale, ArrayRef<T> Mask,
SmallVectorImpl<T> &ScaledMask) {
assert(0 < Scale && "Váratlan méretezési tényező");
int NumElts = Mask.size();
ScaledMask.assign(static_cast<size_t>(NumElts * Scale), -1);
....
}PVS-Studio figyelmeztetés: [CWE-190] Lehetséges túlfolyás. Fontolja meg, hogy az 'NumElts * Scale' operátor operandusait a 'size_t' típusra konvertálja, ne az eredményt. X86ISelLowering.h 1577
A típus explicit átkonvertálása azért szükséges, hogy elkerüljük a túlfolyást a változók szorzása során. egész. Azonban itt az explicit átkonvertálás nem véd meg a túlfolyástól. Először a változók szorzódnak, és csak aztán a 32 bites szorzat kiterjesztésre kerül a típusra. .
N35. sz. töredék: Hibás másolás-beillesztés
Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) {
....
if (!match(Op0, m_PosZeroFP()) && isKnownNeverNaN(Op0, &TLI)) {
I.setOperand(0, ConstantFP::getNullValue(Op0->getType()));
return &I;
}
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op0->getType()));
return &I;
}
....
}[CWE-682] Két hasonló kódtöredéket találtak. Talán elírás történt, és az 'Op1' változót kellene használni az 'Op0' helyett. InstCombineCompares.cpp 5507
Ez az új, érdekes diagnózis feltárja azokat a helyzeteket, amikor a kódtöredék másolásra került, és kezdték megváltoztatni a neveket, de egy helyen nem módosították.
Ne feledje, hogy a második blokkban megváltoztatták Op0 Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata Op1. De egy helyen nem módosították. Valószínűleg így kellett volna írni:
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
return &I;
}N36. sz. töredék: Zavar a változókban
struct Status {
unsigned Mask;
unsigned Mode;
Status() : Mask(0), Mode(0){};
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
Mode &= Mask;
};
....
};PVS-Studio figyelmeztetés: [CWE-563] A 'Mode' változó értéket kap, de a funkció végéig nem használják. SIModeRegister.cpp 48
Nagyon veszélyes az, ha a funkciók argumentumai ugyanazt a nevet kapják, mint az osztály tagjai. Nagyon könnyen zavarba ejtő lehet. Ez éppen ilyen eset.
Mode &= Mask;Megváltozik a funkció argumentuma. És ennyi. Ez az argumentum másfelé nem kerül felhasználásra. Valószínűleg így kellett volna írni:
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
this->Mode &= Mask;
};N37. sz. töredék: Zavar a változókban
class SectionBase {
....
uint64_t Size = 0;
....
};
class SymbolTableSection : public SectionBase {
....
};
void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value,
uint8_t Visibility, uint16_t Shndx,
uint64_t Size) {
....
Sym.Value = Value;
Sym.Visibility = Visibility;
Sym.Size = Size;
Sym.Index = Symbols.size();
Symbols.emplace_back(llvm::make_unique(Sym));
Size += this->EntrySize;
}Figyelmeztetés PVS-Studio: V1001 [CWE-563] A ‘Size’ változó értéket kap, de a függvény végére nem használják fel. Object.cpp 424
A helyzet hasonló az előzőhöz. Így kellene írni:
this->Size += this->EntrySize;N38-N47 szakasz: A mutatót elfelejtették ellenőrizni
Korábban már tárgyaltuk a diagnosztika működésének példáit . Lényege, hogy a mutatót először dereferálják, majd csak ezután ellenőrzik. Új diagnosztika az ellentéte a fentieknek, de szintén sok hibát észlel. Ezekben az esetekben a mutatót először ellenőrizték, majd elfelejtették ezt megtenni. Tekintsünk meg ilyen eseteket, amelyeket az LLVM-ben találtak.
int getGEPCost(Type *PointeeType, const Value *Ptr,
ArrayRef Operands) {
....
if (Ptr != nullptr) { // <=
assert(....);
BaseGV = dyn_cast(Ptr->stripPointerCasts());
}
bool HasBaseReg = (BaseGV == nullptr);
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType()); // <=
....
}Figyelmeztetés PVS-Studio: V1004 [CWE-476] A ‘Ptr’ mutatót biztonságtalanul használták, miután ellenőrizték, hogy nem nullptr. Ellenőrizze a sorokat: 729, 738. TargetTransformInfoImpl.h 738
Változó Ptr lehet egyenlő nullptr, amire az ellenőrzés utal:
if (Ptr != nullptr)Azonban alább ez a mutató már ellenőrzés nélkül van dereferálva:
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());Nézzük meg egy másik hasonló esetet.
llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
bool Stub) {
....
auto *FD = dyn_cast(GD.getDecl());
SmallVector ArgTypes;
if (FD) // parameters())
ArgTypes.push_back(Parm->getType());
CallingConv CC = FD->getType()->castAs()->getCallConv(); // <=
....
}Figyelmeztetés PVS-Studio: V1004 [CWE-476] A ‘FD’ mutatót biztonságtalanul használták, miután ellenőrizték, hogy nem nullptr. Ellenőrizze a sorokat: 3228, 3231. CGDebugInfo.cpp 3231
Figyeljen a mutatóra FD. Biztos vagyok benne, hogy a probléma jól látható, és nincs szükség külön magyarázatra.
És még:
static void computePolynomialFromPointer(Value &Ptr, Polynomial &Result,
Value *&BasePtr,
const DataLayout &DL) {
PointerType *PtrTy = dyn_cast(Ptr.getType());
if (!PtrTy) { // getPointerAddressSpace()); // <=
....
}PVS-Studio figyelmeztetés: V1004 [CWE-476] A 'PtrTy' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 960, 965. InterleavedLoadCombinePass.cpp 965
Hogyan védekezhetünk az ilyen hibák ellen? Legyen figyelmes a kódellenőrzésnél, és használjon statikus kódelemzőt, mint a PVS-Studio.
Nincs értelme a hasonló típusú hibákkal rendelkező egyéb kódszeletek bemutatásának. Csak a figyelmeztetések listáját hagyom meg a cikkben:
- V1004 [CWE-476] Az 'Expr' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1049, 1078. DebugInfoMetadata.cpp 1078
- V1004 [CWE-476] A 'PI' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 733, 753. LegacyPassManager.cpp 753
- V1004 [CWE-476] A 'StatepointCall' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 4371, 4379. Verifier.cpp 4379
- V1004 [CWE-476] Az 'RV' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 2263, 2268. TGParser.cpp 2268
- V1004 [CWE-476] A 'CalleeFn' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1081, 1096. SimplifyLibCalls.cpp 1096
- V1004 [CWE-476] A 'TC' pointert biztonságtalanul használták a nullptr ellenőrzése után. Ellenőrizze a következő sorokat: 1819, 1824. Driver.cpp 1824
N48-N60 szakasz: Nem kritikus, de hiba (memóriaszivárgás előfordulhat)
std::unique_ptr createISelMutator() {
....
std::vector<std::unique_ptr> Strategies;
Strategies.emplace_back(
new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
....
}PVS-Studio figyelmeztetés: [CWE-460] Egy tulajdonos nélküli pointer került a ‘Strategies’ tárolóba az ’emplace_back’ metódussal. Memóriaszivárgás fog bekövetkezni, ha kivétel történik. llvm-isel-fuzzer.cpp 58
Elem hozzáadása a következő típusú tárolóhoz std::vector<std::unique_ptr> nem lehet egyszerűen megírni xxx.push_back(new X), mivel nincs implicit konvertálás a X* be. std::unique_ptr.
Általános megoldás az, hogy megírjuk xxx.emplace_back(new X), mivel ez fordítható: az 'emplace_back' metódus az elemet közvetlenül az argumentumból építi fel, így használhatja az explicit konstruktőröket. Ez nem biztonságos. Ha a vektor tele van, memóriaújralokás történik. A memóriaújralokás művelete kudarcot vallhat, ami kivétel generálását eredményezheti.
std::bad_alloc . Ebben az esetben a pointer elveszik, és a létrehozott objektum soha nem lesz törölve.A biztonságos megoldás az, hogy létrehozunk egy
unique_ptr , amely birtokolja a pointert, mielőtt a vektor megpróbálná újraallokálni a memóriát:, amely a mutatót birtokolja, mielőtt a vektor megpróbálja újraallokálni a memóriát:
xxx.push_back(std::unique_ptr(new X))A C++14-től használhatjuk a 'std::make_unique' használatát:
xxx.push_back(std::make_unique())Ez a hibafajta nem kritikus az LLVM számára. Ha nem sikerül memóriát allokálni, a fordító működése egyszerűen leáll. Azonban, ha egy alkalmazás hosszú , amely nem tud egyszerűen leállni, ha nem sikerül memóriát allokálni, ez valódi kellemetlen hibát okozhat.
Tehát, bár ez a kód nem jelent gyakorlati veszélyt az LLVM számára, hasznosnak találtam beszámolni erről a hiba mintáról, és arról, hogy a PVS-Studio elemzője képes azt észlelni.
Egyéb, hasonló figyelmeztetések:
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Passes' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. PassManager.h 546
- V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'AAs' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. AliasAnalysis.h 324
- V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'Entries' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. DWARFDebugFrame.cpp 519
- V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'AllEdges' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. CFGMST.h 268
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'VMaps' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. SimpleLoopUnswitch.cpp 2012
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Records' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. FDRLogBuilder.h 30
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'PendingSubmodules' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. ModuleMap.cpp 810
- V1023 [CWE-460] Egy tulajdon nélküli pointer került az 'Objects' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. DebugMap.cpp 88
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Strategies' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-isel-fuzzer.cpp 60
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 685
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 686
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 688
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 689
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 690
- V1023 [CWE-460] Egy tulajdon nélküli pointer került a 'Modifiers' tárolóba az 'emplace_back' metódus által. Memóriaszivárgás fog bekövetkezni, ha kivétel lép fel. llvm-stress.cpp 691
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 692
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 693
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Modifiers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. llvm-stress.cpp 694
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra az 'Operands' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 1911
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Stash' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 2100
- V1023 [CWE-460] Egy tulajdonos nélküli mutató kerül hozzáadásra a 'Matchers' tárolóhoz az 'emplace_back' metódus által. Memória szivárgás lép fel, ha kivétel történik. GlobalISelEmitter.cpp 2702
Zárás
Összesen 60 figyelmeztetést írtam ki, majd leálltam. Vannak más hibák is, amelyeket az LLVM PVS-Studio elemzője felfedez? Igen, vannak. Azonban, amikor a cikkhez a kód részleteit írtam, késő este, sőt, már éjszaka volt, és úgy döntöttem, hogy itt az ideje befejezni.
Remélem, érdekesnek találta, és ki szeretné próbálni a PVS-Studio elemzőt.
Le tudja tölteni az elemzőt és kaphat egy ideiglenes kulcsot a következő címen .
A legfontosabb, hogy rendszeresen használja a statikus elemzést. Egyszeri ellenőrzések, amelyeket az általunk a statikus elemzés és a PVS-Studio népszerűsítése érdekében végzünk, nem számít normális forgatókönyvnek.
Sok sikert a kód minőségének és megbízhatóságának javításához!
Ha meg szeretné osztani ezt a cikket angol nyelvű közönséggel, kérjük, használja a fordítás hivatkozását: Andrey Karpov. .
Forrás: habr.com
