
Kaks aastat on möödunud viimati LLVM projekti koodi PVS-Studio analĂŒsaatoriga kontrollimisest. Veendume, et PVS-Studio on endiselt juhtiv tööriist vigade ja potentsiaalsete haavatavuste tuvastamiseks. Uurime ja leiame uusi vigu LLVM 8.0.0 vĂ€ljaandes.
Artikkel, mis peaks olema kirjutatud
Ausalt öeldes, ma ei tahtnud seda artiklit kirjutada. Pole huvitav kirjutada projektist, mida oleme juba korduvalt kontrollinud (, , ). Parema meelega kirjutaksin millestki uuest, kuid valikut mul pole.
Iga kord, kui ilmub uus LLVM versioon vĂ”i see uuendatakse , jĂ”uavad meie postkasti sellised kĂŒsimused:
Vaadake, uus Clang Static Analyzer versioon suudab tuvastada uusi vigu! Mul on tunne, et PVS-Studio kasutamise tÀhtsus vÀheneb. Clang leiab rohkem vigu kui varem ja jÔuab PVS-Studio vÔimalustele jÀrele. Mida teie sellest arvate?
Sellele tahaks alati vastata millegagi taolisega:
Me ei istu ka kĂ€ed ristis! Me oleme oluliselt parandanud PVS-Studio analĂŒsaatori vĂ”imalusi. Nii et Ă€rge muretsege, me jĂ€tkame juhtimist nagu alati.
Kahjuks on see halb vastus. Selles pole piisavalt tĂ”endeid. Ja just seetĂ”ttu kirjutan ma nĂŒĂŒd seda artiklit. Seega on projekti LLVM jĂ€rjekordne kontroll viinud hĂ€mmastavate vigadena. Need, mis tundusid mulle huvitavad, demonstreerin hetkel. Need vead ei suuda avastada Clang Static Analyzer (vĂ”i on selle abil ÀÀrmiselt ebamugav neid otsida). Aga me saame. Ja ma leidsin ja kirjutasin ĂŒles kĂ”ik need vead ĂŒhe Ă”htu jooksul.
Aga artikli kirjutamine venis mitme nÀdala peale. Ei saanud end kuidagi sundida, et kÔik see teksti vormi panna : ).
Muide, kui teid huvitab, milliseid tehnoloogiaid kasutatakse PVS-Studio analĂŒsaatoris vigade ja potentsiaalsete haavatavuste tuvastamiseks, siis kutsun teid tutvuma selle .
Uued ja vanad diagnostikad
Nagu juba mainitud, kontrolliti projekti LLVM umbes kaks aastat tagasi ja leitud vead parandati. NĂŒĂŒd esitan selles artiklis uue koguse vigu. Miks leiti uusi vigu? Sellel on 3 pĂ”hjust:
- LLVM projekt areneb, vanas koodis tehakse muudatusi ja uut koodi lisandub. Loomulikult on muudetud ja kirjutatud koodis uusi vigu. See demonstreerib hĂ€sti, et staatilist analĂŒĂŒsi tuleks rakendada regulaarselt, mitte juhuslikult. Meie artiklid nĂ€itavad hĂ€sti PVS-Studio analĂŒsaatori vĂ”imalusi, kuid see ei ole seotud koodi kvaliteedi tĂ”stmise ja vigade parandamise kulude vĂ€hendamisega. Kasutage staatilist koodianalĂŒsaatorit regulaarselt!
- TĂ€iendame ja tĂ€iustame juba olemasolevaid diagnostikaid. SeetĂ”ttu saab analĂŒsaator tuvastada vigu, mida varasemate kontrollde kĂ€igus ei mĂ€rgatud.
- PVS-Studios on ilmunud uusi diagnostikaid, mida 2 aastat tagasi ei olnud. Otsustasin need vÀlja tuua eraldi jaotises, et selgelt nÀidata PVS-Studio arengut.
Defektid, mille tuvastamisega tegeleti 2 aastat tagasi
Fragment N1: Copy-Paste
static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) {
if (Name == "addcarryx.u32" || // Lisatud 8.0
....
Name == "avx512.mask.cvtps2pd.128" || // Lisatud 7.0
Name == "avx512.mask.cvtps2pd.256" || // Lisatud 7.0
Name == "avx512.cvtusi2sd" || // Lisatud 7.0
Name.startswith("avx512.mask.permvar.") || // Lisatud 7.0 // <=
Name.startswith("avx512.mask.permvar.") || // Lisatud 7.0 // <=
Name == "sse2.pmulu.dq" || // Lisatud 7.0
Name == "sse41.pmuldq" || // Lisatud 7.0
Name == "avx2.pmulu.dq" || // Lisatud 7.0
....
}PVS-Studio hoiatamine: [CWE-570] Vasakul ja paremal â||â operaatoril on identseid alamvĂ€ljendeid âName.startswith(«avx512.mask.permvar.»)â. AutoUpgrade.cpp 73
Kontrollitakse kaks korda, et nimi algab alamhulga «avx512.mask.permvar.». Teises kontrollis soovis ilmselt midagi muud kirjutada, kuid unustas kopeeritud teksti muuta.
Fragment N2: TrĂŒkiviga
enum CXNameRefFlags {
CXNameRange_WantQualifier = 0x1,
CXNameRange_WantTemplateArgs = 0x2,
CXNameRange_WantSinglePiece = 0x4
};
void AnnotateTokensWorker::HandlePostPonedChildCursor(
CXCursor Cursor, unsigned StartTokenIndex) {
const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier;
....
}PVS-Studio hoiatamine: V501 Vasakul ja paremal â|â operaatoril on identseid alamvĂ€ljendeid âCXNameRange_WantQualifierâ. CIndex.cpp 7245
TrĂŒkivea tĂ”ttu kasutatakse kaks korda sama nimelist konstanti CXNameRange_WantQualifier.
Fragment N3: Operaatorite prioriteedi segadus
int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
....
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
return 0;
....
}PVS-Studio hoiatamine: [CWE-783] VĂ”ib-olla töötab â?:â operaator ootamatult. â?:â operaatori prioriteet on madalam kui â==â operaatori prioriteet. PPCTargetTransformInfo.cpp 404
Minu arvates on see vÀga ilus viga. Jah, ma tean, et mul on kummalised arusaamad ilust :).
Praegu, vastavalt , arvutatakse vÀljend jÀrgmiselt:
(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0Praktilise poole pealt ei oma selline tingimus mĂ”tet, kuna seda saab lĂŒhendada jĂ€rgmiseks:
(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())See on ilmne viga. TĂ”enĂ€oliselt soovisid 0/1 vĂ”rrelda muutujaga Indeks. Koodi parandamiseks on vajalik lisada sulud ternaarse operaatori ĂŒmber:
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))Ăks asi, ternearne operaator on vĂ€ga ohtlik ja kutsub esile loogilisi vigu. Olge selle kasutamisel vĂ€ga ettevaatlik ja Ă€rge olge ahne, et lisada ĂŒmmarguseid sulge. Selle teema olen lĂ€hemalt kĂ€sitlenud , peatĂŒkis «Kartke operaatorit ?: ja sulgege see ĂŒmmarguste sulgudega».
Fragment N4, N5: Nullviide
Alg *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
....
TypedInit *LHS = dyn_cast(Result);
....
LHS = dyn_cast(
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
->Fold(CurRec));
if (!LHS) {
Error(PasteLoc, Twine("'ei saa cast' ") + LHS->getAsString() +
"' string'iks");
return nullptr;
}
....
}PVS-Studio hoiatamine: [CWE-476] Null-pointeri âLHSâ lahkamine vĂ”ib toimuda. TGParser.cpp 2152
Kui nÀidik LHS osutub nulliks, siis peaks tekkima hoiatus. Kuid selle asemel toimub null-nÀidiku lahkamine: LHS->getAsString().
See on ĂŒsna tavaline olukord, kus viga peidab end veahaldurites, kuna neid ei testita. Statilised analĂŒsaatorid kontrollivad kogu ligipÀÀsetavat koodi, sĂ”ltumata sellest, kui sageli seda kasutatakse. See on vĂ€ga hea nĂ€ide sellest, kuidas staatiline analĂŒĂŒs tĂ€iendab teisi testimise ja vigade vĂ€ltimise meetodeid.
Sarnane nĂ€idiku haldamise viga RHS on tehtud koodi veidi allpool: V522 [CWE-476] Null-pointeri âRHSâ lahkamine vĂ”ib toimuda. TGParser.cpp 2186
Fragment N6: NÀidiku kasutamine pÀrast liigutamist
static Expected
ExtractBlocks(....)
{
....
std::unique_ptr ProgClone = CloneModule(BD.getProgram(), VMap);
....
BD.setNewProgram(std::move(ProgClone)); // getFunction(MisCompFunctions[i].first); // <=
assert(NewF && "Function not found??");
MiscompiledFunctions.push_back(NewF);
}
....
}PVS-Studio hoiatuse: V522 [CWE-476] Null-viidatud "ProgClone" vÔib juhtuda. Miscompilation.cpp 601
Alguses nutikas nÀitaja ProgClone lakkab objekti omamisest:
BD.setNewProgram(std::move(ProgClone));Tegelikult, nĂŒĂŒd ProgClone on see null-viidatus. Seega peaks allpool toimuma null-viidatuse dereferents:
Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);Kuid tegelikult ei juhtu seda! Pange tĂ€hele, et tsĂŒkkel ei toimu.
Alguses konteiner MiscompiledFunctions kustutatakse:
MiscompiledFunctions.clear();SeejĂ€rel kasutatakse selle konteineri suurust tsĂŒkli tingimuses:
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {On lihtne nĂ€ha, et tsĂŒkkel ei kĂ€ivitu. Arvan, et see on samuti viga ja kood peaks olema kirjutatud muul viisil.
Tundub, et oleme kohanud seda kuulsat vigade paaritust! Ăks viga varjab teist :).
Fragmendi N7: NÀidiku kasutamine pÀrast liikumist
static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
std::unique_ptr<Module> Safe) {
outs() << " Optimeerimise all olevad funktsioonid: ";
std::unique_ptr<Module> Optimized =
BD.runPassesOn(Test.get(), BD.getPassesToRun());
if (!Optimized) {
errs() << " Viga selle passide jÀrjestuse kÀitamisel"
<< " sisendprogrammil!n";
BD.setNewProgram(std::move(Test)); // <=
BD.EmitProgressBitcode(*Test, "pass-error", false); // <=
if (Error E = BD.debugOptimizerCrash())
return std::move(E);
return false;
}
....
}Hoiatus PVS-Studio: V522 [CWE-476] Null-punkti âTestâ dereferentseerimine vĂ”ib toimuda. Miscompilation.cpp 709
Taaskord sama olukord. Alguses liigub objekti sisu ja seejĂ€rel kasutatakse seda nagu poleks midagi juhtunud. Kohtan seda olukorda ĂŒha sagedamini programmikoodis, pĂ€rast seda, kui C++-sse tuli liikumissemantika. Selle pĂ€rast ma armastan C++ keelt! Ilmuvad ĂŒha uusi ja uusi viise endale jalga tulistamiseks. AnalĂŒĂŒsija PVS-Studio'l on alati tööd :).
Fragmendi N8: Null-nÀidik
void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
uint32_t TypeId = Symbol.getTypeId();
auto Type = Symbol.getSession().getSymbolById(TypeId);
if (Type)
Printer << "<tundmatu-tĂŒĂŒp>";
else
Type->dump(*this);
}PVS-Studio hoiatus: V522 [CWE-476] Null-viite âTypeâ dereferentseerimine vĂ”ib toimuda. PrettyFunctionDumper.cpp 233
Lisaks veahalduritele testitakse tavaliselt ka andmete silumisfunktsioone. See on tÀpselt selline juhtum. Funktsioon ootab kasutajat, kes peab oma probleemide lahendamise asemel tegelema selle parandamisega.
Ăige:
if (Type)
Type->dump(*this);
else
Printer << "";Fragment N9: Null-viide
void SearchableTableEmitter::collectTableEntries(
GenericTable &Table, const std::vector &Items) {
....
RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
if (!Ty) // getAsString() + " vs. " + // getType()->getAsString());
....
}PVS-Studio hoiatus: V522 [CWE-476] Null-viite âTyâ dereferentseerimine vĂ”ib toimuda. SearchableTableEmitter.cpp 614
Ma arvan, et kÔik on selge ja selgitust ei vaja.
Fragment N10: TrĂŒki viga
bool FormatTokenLexer::tryMergeCSharpNullConditionals() {
....
auto &Identifier = *(Tokens.end() - 2);
auto &Question = *(Tokens.end() - 1);
....
Identifier->ColumnWidth += Question->ColumnWidth;
Identifier->Type = Identifier->Type; // <=
Tokens.erase(Tokens.end() - 1);
return true;
}PVS-Studio hoiatamine: Muutuja âIdentifier->Typeâ on mÀÀratud iseendale. FormatTokenLexer.cpp 249
Pole mÔtet mÀÀrata muutujat iseendale. TÔenÀoliselt sooviti kirjutada:
Identifier->Type = Question->Type;Fragment N11: Kahtlane break
void SystemZOperand::print(raw_ostream &OS) const {
switch (Kind) {
break;
case KindToken:
OS << "Token:" << getToken();
break;
case KindReg:
OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
break;
....
}PVS-Studio hoiatamine: [CWE-478] Kaaluge âswitchâ lause uurimist. TĂ”enĂ€oliselt on esimene âcaseâ operaator puudu. SystemZAsmParser.cpp 652
Alguses on vÀga kahtlane operaator break. Kas ei unustatud siia midagi veel kirjutada?
Fragment N12: NÀidiku kontroll pÀrast dereferentsimist
InlineCost AMDGPUInliner::getInlineCost(CallSite CS) {
Function *Callee = CS.getCalledFunction();
Function *Caller = CS.getCaller();
TargetTransformInfo &TTI = TTIWP->getTTI(*Callee);
if (!Callee || Callee->isDeclaration())
return llvm::InlineCost::getNever("undefined callee");
....
}PVS-Studio hoiatamine: [CWE-476] âCalleeâ nĂ€idik kasutati enne, kui seda kontrolliti nullptr vastu. Kontrollige ridu: 172, 174. AMDGPUInline.cpp 172
Viit Callee dereferentseeritakse kohe funktsiooni kutsumise hetkel getTTI.
Ja siis selgub, et seda nÀidikut tuleks kontrollida vÔrdsuse osas nullptr:
if (!Callee || Callee->isDeclaration())Aga on juba liiga hiljaâŠ
Fragment N13 â NâŠ: NĂ€idiku kontroll pĂ€rast dereferentsimist
Koodifragmendis kÀsitletud olukord ei ole ainulaadne. See esineb siin:
static Value *optimizeDoubleFP(CallInst *CI, IRBuilder &B,
bool isBinary, bool isPrecise = false) {
....
Function *CalleeFn = CI->getCalledFunction();
StringRef CalleeNm = CalleeFn->getName(); // <=
AttributeList CalleeAt = CalleeFn->getAttributes();
if (CalleeFn && !CalleeFn->isIntrinsic()) { // <=
....
}PVS-Studio hoiatatakse: V595 [CWE-476] 'CalleeFn' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 1079, 1081. SimplifyLibCalls.cpp 1079
Ja siin:
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
....
NamedDecl *ND = dyn_cast<NamedDecl>(New);
CXXRecordDecl *ThisContext =
dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); // <=
CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
ND && ND->isCXXInstanceMember()); // <=
....
}PVS-Studio hoiatatakse: V595 [CWE-476] 'ND' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 532, 534. SemaTemplateInstantiateDecl.cpp 532
Ja siin:
- V595 [CWE-476] 'U' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 404, 407. DWARFFormValue.cpp 404
- V595 [CWE-476] 'ND' nÀidiku kasutamine enne, kui see on kontrollitud nullptr vastu. Kontrollige ridu: 2149, 2151. SemaTemplateInstantiate.cpp 2149
Ja jÀrgmisel hetkel muutus mulle V595 numbriga hoiatused uurida vÀhem huvitavaks. Seega ei tea ma, kas siin on veel analoogseid vigu peale nimetatute.
Fragment N17, N18: Kahtlane nihke
static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
uint64_t &Encoding) {
....
unsigned Size = RegSize;
....
uint64_t NImms = ~(Size-1) << 1;
....
}PVS-Studio hoiatamine: [CWE-190] Kaaluge â~(Size â 1) << 1â vĂ€ljendi kontrollimist. 32-bitise vÀÀrtuse bititasemeline nihutamine, millele jĂ€rgneb laienemine 64-bitise tĂŒĂŒbini. AArch64AddressingModes.h 260
VĂ”ib-olla see ei ole viga, ja kood töötab just nii, nagu plaanitud. Kuid see on selgelt vĂ€ga kahtlane koht ja see tuleb ĂŒle vaadata.
Oletame, et muutuja Suurus on 16, ning koodi autor plaanis, et muutuja NImms saab vÀÀrtuse:
1111111111111111111111111111111111111111111111111111111111100000
Kuid tegelikult tuleb vÀÀrtuseks:
0000000000000000000000000000000011111111111111111111111111100000
Asi on selles, et kĂ”ik arvutused toimuvad 32-bitise unsigned tĂŒĂŒbi kasutamisel. Ja alles pĂ€rast seda laieneb see 32-bitine signaalita tĂŒĂŒp automaatselt uint64_ttĂŒĂŒbiks. Sellega kaasneb see, et kĂ”rgemad bitid on nullid.
Probleemi saab lahendada nii:
uint64_t NImms = ~static_cast(Size-1) << 1;Sarnane olukord: V629 [CWE-190] Kaaluge âImmr << 6â vĂ€ljendi kontrollimist. 32-bitise vÀÀrtuse bititasemeline nihutamine, millele jĂ€rgneb laienemine 64-bitise tĂŒĂŒbini. AArch64AddressingModes.h 269
Fragment N19: Omandatud mÀrksÔna muud?
void AMDGPUAsmParser::cvtDPP(MCInst & Inst, const OperandVector & Operands) {
....
if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) {
// VOP2b (v_add_u32, v_sub_u32 ...) dpp kasutab "vcc" mÀrgendit.
// JĂ€tame vahele.
continue;
} if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) { // <=
Op.addRegWithFPInputModsOperands(Inst, 2);
} else if (Op.isDPPCtrl()) {
Op.addImmOperands(Inst, 1);
} else if (Op.isImm()) {
// KĂ€sitleme valikulisi argumendi
OptionalIdx[Op.getImmTy()] = I;
} else {
llvm_unreachable("Kehtetu operanditĂŒĂŒp");
}
....
}PVS-Studio hoiatamine: [CWE-670] Kaaluge rakenduse loogika kontrollimist. On vÔimalik, et 'else' mÀrksÔna on puudu. AMDGPUAsmParser.cpp 5655
Siin pole vigu. Kuna esimese if then-plokk lÔpeb continue, siis pole oluline, kas mÀrksÔna muud on vÔi ei. Igal juhul töötab kood sama moodi. Siiski, puuduolev muud teeb koodi vÀhem arusaadavaks ja ohtlikuks. Kui hiljem continue kaob, hakkab kood tööle hoopis teistmoodi. Minu arvates on parem lisada muud.
Fragment N20: Neli sarnast trĂŒkiviga
LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const {
std::string Result;
if (isUndefined())
Result += "(undef) ";
if (isWeakDefined())
Result += "(weak-def) ";
if (isWeakReferenced())
Result += "(weak-ref) ";
if (isThreadLocalValue())
Result += "(tlv) ";
switch (Kind) {
case SymbolKind::GlobalSymbol:
Result + Name.str(); // <=
break;
case SymbolKind::ObjectiveCClass:
Result + "(ObjC Class) " + Name.str(); // <=
break;
case SymbolKind::ObjectiveCClassEHType:
Result + "(ObjC Class EH) " + Name.str(); // <=
break;
case SymbolKind::ObjectiveCInstanceVariable:
Result + "(ObjC IVar) " + Name.str(); // <=
break;
}
OS << Result;
}PVS-Studio hoiatused:
- V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit âResult + Name.str()â. Symbol.cpp 32
- V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit âResult + «(ObjC Class) » + Name.str()â. Symbol.cpp 35
- V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit âResult + «(ObjC Class EH) » + Name.str()â. Symbol.cpp 38
- V655 [CWE-480] Stringid liideti, kuid neid ei kasutata. Soovitame kontrollida vĂ€ljendit âResult + «(ObjC IVar) » + Name.str()â. Symbol.cpp 41
Juhuslikult kasutatakse operatori += asemel operatorit +. Tulemuseks on mÔttetu konstruktsioon.
Fragment N21: MÀÀramatu kÀitumine
static void getReqFeatures(std::map &FeaturesMap,
const std::vector &ReqFeatures) {
for (auto &R : ReqFeatures) {
StringRef AsmCondString = R->getValueAsString("AssemblerCondString");
SmallVector Ops;
SplitString(AsmCondString, Ops, ",");
assert(!Ops.empty() && "AssemblerCondString cannot be empty");
for (auto &Op : Ops) {
assert(!Op.empty() && "Empty operator");
if (FeaturesMap.find(Op) == FeaturesMap.end())
FeaturesMap[Op] = FeaturesMap.size();
}
}
}Proovige iseseisvalt ohtlik kood leida. Ja see pilt on tÀhelepanu hajutamiseks, et te kohe vastust ei vaataks:

PVS-Studio hoiatamine: [CWE-758] Ohtlik konstruktsioon on kasutusel: âFeaturesMap[Op] = FeaturesMap.size()â, kus âFeaturesMapâ on âmapâ klass. See vĂ”ib viia mÀÀramata kĂ€itumiseni. RISCVCompressInstEmitter.cpp 490
Problemaatiline rida:
FeaturesMap[Op] = FeaturesMap.size();Kui element Op ei leitud, siis luuakse kaardis uus element ja sinna salvestatakse elementide arv. Ainult et ei ole teada, kas funktsiooni size kutsutakse vÀlja enne vÔi pÀrast uue elemendi lisamist.
Fragment N22-N24: Korduvalt mÀÀramised
Error MachOObjectFile::checkSymbolTable() const {
....
} else {
MachO::nlist STE = getSymbolTableEntry(SymDRI);
NType = STE.n_type; // <=
NType = STE.n_type; // <=
NSect = STE.n_sect;
NDesc = STE.n_desc;
NStrx = STE.n_strx;
NValue = STE.n_value;
}
....
}PVS-Studio hoiatamine: [CWE-563] Muutuja âNTypeâ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1663, 1664. MachOObjectFile.cpp 1664
Arvan, et siin pole tegelikult viga. Lihtsalt ĂŒleliigne korduv omistamine. Aga ikka vale.
Sama:
- V519 [CWE-563] Muutuja âB.NDescâ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1488, 1489. llvm-nm.cpp 1489
- V519 [CWE-563] Muutuja omistatakse jÀrjestikku kaks korda vÀÀrtused. See vÔib olla eksitus. Kontrolli ridu: 59, 61. coff2yaml.cpp 61
Fragment N25-N27: Veel korduvad omistamised
NĂŒĂŒd vaatame natuke teistsugust korduva omistamise varianti.
bool Vectorizer::vectorizeLoadChain(
ArrayRef Chain,
SmallPtrSet *InstructionsProcessed) {
....
unsigned Alignment = getAlignment(L0);
....
unsigned NewAlign = getOrEnforceKnownAlignment(L0->getPointerOperand(),
StackAdjustedAlignment,
DL, L0, nullptr, &DT);
if (NewAlign != 0)
Alignment = NewAlign;
Alignment = NewAlign;
....
}PVS-Studio hoiatus: V519 [CWE-563] Muutuja âAlignmentâ omistatakse jĂ€rjestikku kaks korda vÀÀrtused. See vĂ”ib olla eksitus. Kontrolli ridu: 1158, 1160. LoadStoreVectorizer.cpp 1160
See on vĂ€ga kummaline kood, mis ilmselt sisaldab loogilist viga. Alguses omistatakse muutuja Alignment vÀÀrtus sĂ”ltuvalt tingimusest. Siis toimub taas omistamine, kuid nĂŒĂŒd juba ilma igasuguse kontrollita.
Sarnaseid olukordi vÔib nÀha siin:
- V519 [CWE-563] Muutuja 'Effects' on jÀrjestikku mÀÀratud kahesuguseid vÀÀrtusi. VÔib-olla on see viga. Kontrollige ridu: 152, 165. WebAssemblyRegStackify.cpp 165
- V519 [CWE-563] Muutuja 'ExpectNoDerefChunk' on jÀrjestikku mÀÀratud kahesuguseid vÀÀrtusi. VÔib-olla on see viga. Kontrollige ridu: 4970, 4973. SemaType.cpp 4973
Fragment N28: Alati tÔene tingimus
static int readPrefixes(struct InternalInstruction* insn) {
....
uint8_t byte = 0;
uint8_t nextByte;
....
if (byte == 0xf3 && (nextByte == 0x88 || nextByte == 0x89 ||
nextByte == 0xc6 || nextByte == 0xc7)) {
insn->xAcquireRelease = true;
if (nextByte != 0x90) // PAUSE juhendi tugi // <=
break;
}
....
}PVS-Studio hoiatamine: [CWE-571] Avalduss 'nextByte != 0x90' on alati tÔene. X86DisassemblerDecoder.cpp 379
Kontroll ei oma mÔtet. Muutuja nextByte on alati erinev vÀÀrtusest 0x90, mis tuleneb eelmisest kontrollist. See on mingi loogiline viga.
Fragment N29 â NâŠ: Alati tĂ”esed/vale tingimused
AnalĂŒsaator vĂ€ljastab palju hoiatusi seoses sellega, et kogu tingimus () vĂ”i selle osa () on alati tĂ”ene vĂ”i vale. Tihti ei ole need tegelikud vead, vaid lihtsalt hoolimatu kood, makrode rakendamise tulemused jne. Siiski on mĂ”istlik vaadata kĂ”iki neid hoiatustega, kuna aeg-ajalt tulenevad tĂ”elised loogilised vead. NĂ€iteks on kahtlane see koodilĂ”ik:
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder) {
DecodeStatus S = MCDisassembler::Success;
if (RegNo > 13)
return MCDisassembler::Fail;
if ((RegNo & 1) || RegNo == 0xe)
S = MCDisassembler::SoftFail;
....
}PVS-Studio hoiatamine: [CWE-570] Ăks tingimuslause osa on alati vale: RegNo == 0xe. ARMDisassembler.cpp 939
Konstant 0xE on vÀÀrtus 14 kĂŒmnendsĂŒsteemis. Kontroll RegNo == 0xe pole mĂ”ttekas, kuna kui RegNo > 13, siis lĂ”petab funktsioon oma töötamise.
Oli palju teisi hoiatusi ID-ga V547 ja V560, kuid nagu oli juba selge , ei olnud mul nende hoiatuste uurimise vastu huvi. Niigi oli selge, et mul on piisavalt materjali artikli kirjutamiseks :). SeepÀrast ei ole teada, kui palju selliseid vigu vÔiks LLVM-is PVS-Studio abil tuvastada.
Toon nĂ€ide, miks nende hoiatuste Ă”ppimine on igav. AnalĂŒsaator on tĂ€iesti Ă”ige, andes hoiatuse jĂ€rgmise koodi kohta. Kuid see ei ole viga.
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
tok::TokenKind ClosingBraceKind) {
bool HasError = false;
....
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
....
}PVS-Studio hoiatamine: V547 [CWE-570] VĂ€ljend â!HasErrorâ on alati vale. UnwrappedLineParser.cpp 1635
Fragment N30: Kahtlane return
static bool
isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
for (MachineRegisterInfo::def_instr_iterator It = MRI.def_instr_begin(Reg),
E = MRI.def_instr_end(); It != E; ++It) {
return (*It).isImplicitDef();
}
....
}PVS-Studio hoiatamine: [CWE-670] Tingimusteta âreturnâ tsĂŒkli sees. R600OptimizeVectorRegisters.cpp 63
See on kas viga vÔi spetsiifiline tehnika, mille eesmÀrk on midagi selgitada programmeerijatele, kes koodi loevad. Selline konstruktsioon ei selgita mulle midagi ja nÀeb vÀga kahtlane vÀlja. Paremini ei tasu nii kirjutada :).
VÀsinud? Siis on aeg teed vÔi kohvi keeta.

Defektid, mille uued diagnostikad on tuvastanud
Arvan, et 30 vana diagnostika hoiatust on piisavalt. Vaadakem nĂŒĂŒd, mida huvitavat me uute diagnostikatega, mis analĂŒsaatorisse ilmnesid, leida saame. kontrollide. Selle aja jooksul on C++ analĂŒsaatorisse lisandunud 66 ĂŒldist diagnostikat.
Fragment N31: JÔudmata kood
Error CtorDtorRunner::run() {
....
if (auto CtorDtorMap =
ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names),
NoDependenciesToRegister, true))
{
....
return Error::success();
} else
return CtorDtorMap.takeError();
CtorDtorsByPriority.clear();
return Error::success();
}PVS-Studio hoiatamine: [CWE-561] JÔudmata kood tuvastatud. VÔimalik, et viga on olemas. ExecutionUtils.cpp 146
Nagu nĂ€ete, lĂ”petavad mĂ”lemad harud operaatorit if operaatori kutsumisega return. Seega konteiner CtorDtorsByPriority ei tule kunagi tĂŒhjendamiseks.
Fragment N32: JÔudmata kood
bool LLParser::ParseSummaryEntry() {
....
switch (Lex.getKind()) {
case lltok::kw_gv:
return ParseGVEntry(SummaryID);
case lltok::kw_module:
return ParseModuleEntry(SummaryID);
case lltok::kw_typeid:
return ParseTypeIdEntry(SummaryID); // <=
break; // <=
default:
return Error(Lex.getLoc(), "unexpected summary kind");
}
Lex.setIgnoreColonInIdentifiers(false); // <=
return false;
}Hoiatus PVS-Studio: V779 [CWE-561] JÔudmata kood tuvastatud. VÔimalik, et viga on olemas. LLParser.cpp 835
Huvitav olukord. Vaatame esmalt seda kohta:
return ParseTypeIdEntry(SummaryID);
break;Esmapilgul tundub, et siin pole viga. Tundub, et operaator break siin on ĂŒleliigne osa, ja selle vĂ”ib lihtsalt eemaldada. Kuid mitte kĂ”ik on nii lihtne.
AnalĂŒsaator annab hoiatuse ridade kohta:
Lex.setIgnoreColonInIdentifiers(false);
return false;Ja tĂ”epoolest, see kood on saavutatav. KĂ”ik juhtumid switch lĂ”pevad kĂ€su kutsumisega return. Ja nĂŒĂŒd ei tundu ĂŒksildane break nii sĂŒĂŒtu! Ăkki peaks ĂŒks haru lĂ”ppema break, mitte return?
Fragment N33: Juhuslik kÔrgemate bitide nullimine
unsigned getStubAlignment() override {
if (Arch == Triple::systemz)
return 8;
else
return 1;
}
Expected
RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
const SectionRef &Section,
bool IsCode) {
....
uint64_t DataSize = Section.getSize();
....
if (StubBufSize > 0)
DataSize &= ~(getStubAlignment() - 1);
....
}PVS-Studio hoiatamine: Bitmaski suurus on vÀiksem kui esimese operandi suurus. See pÔhjustab kÔrgemate bitide kadumise. RuntimeDyld.cpp 815
Pange tĂ€hele, et funktsioon getStubAlignment tagastab tĂŒĂŒbi unsigned. Arvutame vĂ€ljendi vÀÀrtuse, eeldades, et funktsioon tagastab vÀÀrtuse 8:
~(getStubAlignment() - 1)
~(8u-1)
0xFFFFFFF8âŹu
NĂŒĂŒd pange tĂ€hele, et muutuja DataSize omab 64-bit unsigned tĂŒĂŒp. See tĂ€hendab, et DataSize & 0xFFFFFFF8âŹu teostamisel nullitakse kĂ”ik kolmkĂŒmmend kaks ĂŒlemist bitti. TĂ”enĂ€oliselt ei olnud see, mida programmeerija soovis. Kahtlustan, et ta tahtis arvutada: DataSize & 0xFFFFFFFFFFFFFFF8âŹu.
Vea parandamiseks tuleks kirjutada nii:
DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1);VÔi nii:
DataSize &= ~(getStubAlignment() - 1ULL);Fragment N34: EbaĂ”nnestunud tĂŒĂŒpide konverteerimine
template <typename T>
void scaleShuffleMask(int Scale, ArrayRef<T> Mask,
SmallVectorImpl<T> &ScaledMask) {
assert(0 < Scale && "Ootamatu skaleerimise tegur");
int NumElts = Mask.size();
ScaledMask.assign(static_cast<size_t>(NumElts * Scale), -1);
....
}PVS-Studio hoiatamine: [CWE-190] VĂ”imalik ĂŒlejÀÀgitus. Kaaluge operandide 'NumElts * Scale' operaatori kastmist 'size_t' tĂŒĂŒbiks, mitte tulemust. X86ISelLowering.h 1577
TĂŒĂŒpide konverteerimist kasutatakse, et vĂ€ltida ĂŒlejÀÀgitust muutuja tĂŒĂŒpide korrutamisel. int. Kuid siin ei kaitse tĂŒĂŒpide konverteerimine ĂŒlejÀÀgi eest. Alguses korrutatakse muutujad ja alles seejĂ€rel laiendatakse 32-bitine korrutamise tulemus. .
Fragment N35: EbaÔnnestunud Copy-Paste
Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) {
....
if (!match(Op0, m_PosZeroFP()) && isKnownNeverNaN(Op0, &TLI)) {
I.setOperand(0, ConstantFP::getNullValue(Op0->getType()));
return &I;
}
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op0->getType())); // <=
return &I;
}
....
}[CWE-682] Leiti sarnased koodi fragmentid. VĂ”ib-olla on see trĂŒkkimisviga ja 'Op1' muutuja peaks olema kasutatud 'Op0' asemel. InstCombineCompares.cpp 5507
See uus huvitav diagnoos tuvastab olukordi, kus koodifragmendi on kopeeritud ja nimesid on hakanud muutma, aga ĂŒhes kohas ei ole neid parandatud.
Pange tĂ€hele, et teises plokis muudeti Op0 jĂ€rgnevaga Op1. Aga ĂŒhes kohas ei ole neid parandatud. TĂ”enĂ€oliselt oleks pidanud kirjutama nii:
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
return &I;
}Fragment N36: Muutujate segadus
struct Status {
unsigned Mask;
unsigned Mode;
Status() : Mask(0), Mode(0){};
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
Mode &= Mask;
};
....
};PVS-Studio hoiatamine: [CWE-563] Muutujale 'Mode' antakse vÀÀrtus, kuid seda ei kasutata funktsiooni lÔpuks. SIModeRegister.cpp 48
On vÀga ohtlik anda funktsioonide argumentidele samu nimesid kui klassi liikmetele. On vÀga lihtne segadusse sattuda. See on just selline juhtum. See vÀljend ei oma tÀhendust:
Mode &= Mask;Funktsiooni argument muutub. Ja kÔik. Seda argumenti ei kasutata enam. TÔenÀoliselt pidi olema nii:
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
this->Mode &= Mask;
};Fragment N37: Muutuja segadus
class SectionBase {
....
uint64_t Size = 0;
....
};
class SymbolTableSection : public SectionBase {
....
};
void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value,
uint8_t Visibility, uint16_t Shndx,
uint64_t Size) {
....
Sym.Value = Value;
Sym.Visibility = Visibility;
Sym.Size = Size;
Sym.Index = Symbols.size();
Symbols.emplace_back(llvm::make_unique(Sym));
Size += this->EntrySize;
}PVS-Studio hoiatus: V1001 [CWE-563] Muutujale 'Size' antakse vÀÀrtus, kuid funktsiooni lÔpuks ei kasutata seda. Object.cpp 424
Situatsioon on analoogne eelnevale. Peaks olema kirjutatud:
this->Size += this->EntrySize;Fragment N38-N47: NĂ€idik unustati kontrollida
Varem oleme vaadanud diagnostika aktiveerumise nÀiteid . Selle olemus on see, et nÀidik dereferenseeritakse alguses ja alles siis kontrollitakse. Uhiuus diagnostika on vastupidine, kuid samal ajal avastab vÀga palju vigu. See paljastab olukordi, kus indikaatorit alguses kontrolliti, kuid siis unustati seda teha. Vaadakem selliseid juhtumeid, mis leiti LLVM'is.
int getGEPCost(Type *PointeeType, const Value *Ptr,
ArrayRef Operands) {
....
if (Ptr != nullptr) { // <=
assert(....);
BaseGV = dyn_cast(Ptr->stripPointerCasts());
}
bool HasBaseReg = (BaseGV == nullptr);
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType()); // <=
....
}PVS-Studio hoiatus: V1004 [CWE-476] Pointer 'Ptr' kasutati pÀrast null'i vastu kontrollimist ebaohutult. Kontrollige ridu: 729, 738. TargetTransformInfoImpl.h 738
Muutuja Ptr vÔib olla vÔrdne nullptr, mida nÀitab kontroll:
if (Ptr != nullptr)Kuid allpool dereferenseeritakse seda pointerit juba eelneva kontrollita:
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());Vaatame teist sarnast juhtumit.
llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
bool Stub) {
....
auto *FD = dyn_cast(GD.getDecl());
SmallVector ArgTypes;
if (FD) // parameters())
ArgTypes.push_back(Parm->getType());
CallingConv CC = FD->getType()->castAs()->getCallConv(); // <=
....
}PVS-Studio hoiatamine: V1004 [CWE-476] 'FD' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 3228, 3231. CGDebugInfo.cpp 3231
Pange tÀhele pointerit FD. Olen kindel, et probleem on selgelt nÀhtav ja ei vaja erilisi selgitusi.
Ja veel:
static void computePolynomialFromPointer(Value &Ptr, Polynomial &Result,
Value *&BasePtr,
const DataLayout &DL) {
PointerType *PtrTy = dyn_cast(Ptr.getType());
if (!PtrTy) { // getPointerAddressSpace()); // <=
....
}PVS-Studio hoiatamine: V1004 [CWE-476] 'PtrTy' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 960, 965. InterleavedLoadCombinePass.cpp 965
Kuidas end selliste vigade eest kaitsta? Olge tĂ€helepanelikumad koodi ĂŒlevaatusel ja kasutage regulaarseks koodikontrolliks staatilist analizatorit PVS-Studio.
Muude samasuguste vigadega koodifragmentide toomine pole mÔtet. JÀtan artiklisse ainult hoiatuste nimekirja:
- V1004 [CWE-476] 'Expr' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 1049, 1078. DebugInfoMetadata.cpp 1078
- V1004 [CWE-476] 'PI' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 733, 753. LegacyPassManager.cpp 753
- V1004 [CWE-476] 'StatepointCall' pointerit kasutati ebaohutult pÀrast null-pointeriga kontrollimist. Kontrollige ridu: 4371, 4379. Verifier.cpp 4379
- V1004 [CWE-476] âRVâ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 2263, 2268. TGParser.cpp 2268
- V1004 [CWE-476] âCalleeFnâ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 1081, 1096. SimplifyLibCalls.cpp 1096
- V1004 [CWE-476] âTCâ pointerit kasutati ebaohutult pĂ€rast nullpointeriga kontrollimist. Kontrollige ridu: 1819, 1824. Driver.cpp 1824
Fragment N48-N60: Mitte kriitiline, aga defekt (vÔimalik mÀluleke)
std::unique_ptr createISelMutator() {
....
std::vector<std::unique_ptr> Strategies;
Strategies.emplace_back(
new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
....
}PVS-Studio hoiatamine: [CWE-460] Pointer, millel pole omanikku, lisatakse âStrategiesâ konteinerisse âemplace_backâ meetodi kaudu. MĂ€luleke toimub juhul, kui tekib erand. llvm-isel-fuzzer.cpp 58
Elemendi lisamiseks konteineri lĂ”ppu, tĂŒĂŒpi std::vector<std::unique_ptr> ei saa lihtsalt kirjutada xxx.push_back(new X), kuna ei toimu varjatud teisendamist X* ĂŒhes std::unique_ptr.
Levinud lahendus on kirjutada xxx.emplace_back(new X), kuna see kompileerub: meetod emplace_back ehitab elemendi otse argumentidest ja seega vÔib kasutada selgeid konstruktorit.
See ei ole ohutu. Kui vektor on tĂ€is, toimub mĂ€lu ĂŒmberjaotamine. MĂ€lu ĂŒmberjaotamise operatsioon vĂ”ib ebaĂ”nnestuda, mille tagajĂ€rjel genereeritakse erand std::bad_alloc. Sel juhul kaob nĂ€idik ja loodud objekti ei saa kunagi kustutada.
Ohutu lahendus on loomine unique_ptr, mis omab nÀidikut kuni vektori katse mÀluruumi uuesti eraldada:
xxx.push_back(std::unique_ptr(new X))Alates C++14-st saab kasutada âstd::make_uniqueâ:
xxx.push_back(std::make_unique())Seda tĂŒĂŒpi viga ei ole LLVM jaoks kriitiline. Kui mĂ€luruumi eraldamine ebaĂ”nnestub, peatub kompilaatori töö lihtsalt. Kuid rakenduste jaoks, mille kĂ€ivitusaeg , mis ei saa lihtsalt lĂ”petada, kui mĂ€luruumi eraldamine ebaĂ”nnestub, vĂ”ib see olla tĂ”eline ebamugavus.
Seega, kuigi see kood ei kujuta endas praktilist ohtu LLVM-ile, leidis ma kasulik rÀÀkida sellest veapatrist ja sellest, kuidas PVS-Studio analĂŒsaator on Ă”ppinud seda tuvastama.
Muud selle tĂŒĂŒpi hoiatustega:
- V1023 [CWE-460] NĂ€idik, kellel pole omanikku, lisatakse 'Passes' konteinerisse âemplace_backâ meetodiga. Erakordsuse korral tekib mĂ€luleke. PassManager.h 546
- V1023 [CWE-460] NĂ€idik, kellel pole omanikku, lisatakse 'AAs' konteinerisse âemplace_backâ meetodiga. Erakordsuse korral tekib mĂ€luleke. AliasAnalysis.h 324
- V1023 [CWE-460] Omanikuta omanikuta lisatakse 'Entries' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. DWARFDebugFrame.cpp 519
- V1023 [CWE-460] Omanikuta omanik lisatakse 'AllEdges' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. CFGMST.h 268
- V1023 [CWE-460] Omanikuta omanik lisatakse 'VMaps' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. SimpleLoopUnswitch.cpp 2012
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Records' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. FDRLogBuilder.h 30
- V1023 [CWE-460] Omanikuta omanik lisatakse 'PendingSubmodules' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. ModuleMap.cpp 810
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Objects' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. DebugMap.cpp 88
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Strategies' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. llvm-isel-fuzzer.cpp 60
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. llvm-stress.cpp 685
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. llvm-stress.cpp 686
- V1023 [CWE-460] Omanikuta omanik lisatakse 'Modifiers' konteinerisse 'emplace_back' meetodiga. Erandi korral toimub mÀluleke. llvm-stress.cpp 688
- V1023 [CWE-460] Omanik, kellel ei ole omanikku, lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 689
- V1023 [CWE-460] Omanikuta pointern lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 690
- V1023 [CWE-460] Omanikuta pointer lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 691
- V1023 [CWE-460] Omanikuta pointer lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 692
- V1023 [CWE-460] Omanikuta pointer lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 693
- V1023 [CWE-460] Omanikuta pointer lisatakse âModifikaatoriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. llvm-stress.cpp 694
- V1023 [CWE-460] Omanikuta pointer lisatakse âOperandideâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 1911
- V1023 [CWE-460] Omanikuta pointer lisatakse âStashiâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 2100
- V1023 [CWE-460] Omanikuta pointer lisatakse âMatcheriteâ konteinerisse meetodi âemplace_backâ abil. Erandi korral tekib mĂ€lu lekkimine. GlobalISelEmitter.cpp 2702
KokkuvÔte
Kokku olen koostanud 60 hoiatust, mille jĂ€rel peatusin. Kas PVS-Studio analĂŒsaator tuvastab veel muid Defekte LLVM-s? Jah, tuvastab. Kuid kui ma koostasin artikli jaoks koodilĂ”ike, oli juba hiline Ă”htu, pigem isegi öö, ja otsustasin, et on aeg lĂ”petada.
Loodan, et teile oli huvitav ja soovite proovida PVS-Studio analĂŒsaatorit.
Saate analĂŒsaatori alla laadida ja saada proovivĂ”tmiseks vĂ”tme .
KĂ”ige tĂ€htsam, kasutage staatilist analĂŒĂŒsi regulaarselt. Ăhekordsed kontrollid, mida me teeme staatilise analĂŒĂŒsi ja PVS-Studio metodoloogia populariseerimise eesmĂ€rgil, ei ole normaalne stsenaarium.
Edu koodi kvaliteedi ja usaldusvÀÀrsuse parandamisel!
Kui soovite seda artiklit jagada ingliskeelse auditooriumiga, siis palun kasutage tÔlke linki: Andrey Karpov. .
Allikas: habr.com
