Mae mwy na dwy flynedd wedi mynd heibio ers gwiriad cod diwethaf y prosiect LLVM gan ddefnyddio ein dadansoddwr PVS-Studio. Gadewch i ni sicrhau bod y dadansoddwr PVS-Studio yn dal i fod yn offeryn blaenllaw ar gyfer nodi gwallau a gwendidau posibl. I wneud hyn, byddwn yn gwirio ac yn dod o hyd i wallau newydd yn y datganiad LLVM 8.0.0.
Erthygl i'w hysgrifennu
I fod yn onest, doeddwn i ddim eisiau ysgrifennu'r erthygl hon. Nid yw'n ddiddorol ysgrifennu am brosiect yr ydym eisoes wedi'i wirio sawl gwaith (
Bob tro mae fersiwn newydd o LLVM yn cael ei ryddhau neu ei ddiweddaru
Edrychwch, mae'r fersiwn newydd o Clang Static Analyzer wedi dysgu dod o hyd i wallau newydd! Mae'n ymddangos i mi fod perthnasedd defnyddio PVS-Studio yn lleihau. Mae Clang yn dod o hyd i fwy o wallau nag o'r blaen ac yn dal i fyny â galluoedd PVS-Studio. Beth yw eich barn am hyn?
I hyn rwyf bob amser eisiau ateb rhywbeth fel:
Nid ydym yn eistedd yn segur chwaith! Rydym wedi gwella galluoedd y dadansoddwr PVS-Studio yn sylweddol. Felly peidiwch â phoeni, rydym yn parhau i arwain fel o'r blaen.
Yn anffodus, mae hwn yn ateb gwael. Nid oes unrhyw broflenni ynddo. A dyna pam rydw i'n ysgrifennu'r erthygl hon nawr. Felly, mae'r prosiect LLVM wedi'i wirio unwaith eto ac mae amrywiaeth o wallau wedi'u canfod ynddo. Byddaf yn awr yn dangos y rhai a oedd yn ymddangos yn ddiddorol i mi. Ni all Clang Static Analyzer ddod o hyd i'r gwallau hyn (neu mae'n anghyfleus iawn gwneud hynny gyda'i help). Ond gallwn. Ar ben hynny, darganfyddais ac ysgrifennais yr holl wallau hyn mewn un noson.
Ond cymerodd ysgrifennu'r erthygl sawl wythnos. Allwn i ddim dod â fy hun i roi hyn i gyd mewn testun :).
Gyda llaw, os oes gennych ddiddordeb yn y technolegau a ddefnyddir yn y dadansoddwr PVS-Studio i nodi gwallau a gwendidau posibl, yna rwy'n awgrymu dod yn gyfarwydd â hyn
Diagnosteg hen a newydd
Fel y nodwyd eisoes, tua dwy flynedd yn ôl gwiriwyd y prosiect LLVM unwaith eto, a chywirwyd y gwallau a ganfuwyd. Nawr bydd yr erthygl hon yn cyflwyno swp newydd o wallau. Pam y canfuwyd chwilod newydd? Mae 3 rheswm am hyn:
- Mae'r prosiect LLVM yn esblygu, yn newid hen god ac yn ychwanegu cod newydd. Yn naturiol, mae gwallau newydd yn y cod addasedig ac ysgrifenedig. Mae hyn yn dangos yn glir y dylid defnyddio dadansoddiad statig yn rheolaidd, ac nid yn achlysurol. Mae ein herthyglau yn dangos yn dda alluoedd y dadansoddwr PVS-Studio, ond nid oes a wnelo hyn ddim â gwella ansawdd cod a lleihau cost trwsio gwallau. Defnyddiwch ddadansoddwr cod statig yn rheolaidd!
- Rydym yn cwblhau ac yn gwella diagnosteg bresennol. Felly, gall y dadansoddwr nodi gwallau na sylwodd arnynt yn ystod sganiau blaenorol.
- Mae diagnosteg newydd wedi ymddangos yn PVS-Studio nad oedd yn bodoli 2 flynedd yn ôl. Penderfynais eu hamlygu mewn adran ar wahân i ddangos yn glir ddatblygiad PVS-Studio.
Diffygion a nodwyd gan ddiagnosteg a oedd yn bodoli 2 flynedd yn ôl
Darn N1: Copi-Paste
static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) {
if (Name == "addcarryx.u32" || // Added in 8.0
....
Name == "avx512.mask.cvtps2pd.128" || // Added in 7.0
Name == "avx512.mask.cvtps2pd.256" || // Added in 7.0
Name == "avx512.cvtusi2sd" || // Added in 7.0
Name.startswith("avx512.mask.permvar.") || // Added in 7.0 // <=
Name.startswith("avx512.mask.permvar.") || // Added in 7.0 // <=
Name == "sse2.pmulu.dq" || // Added in 7.0
Name == "sse41.pmuldq" || // Added in 7.0
Name == "avx2.pmulu.dq" || // Added in 7.0
....
}
Rhybudd PVS-Stiwdio:
Mae'n cael ei wirio ddwywaith bod yr enw yn dechrau gyda'r is-linyn "avx512.mask.permvar.". Yn yr ail siec, roedd yn amlwg eu bod am ysgrifennu rhywbeth arall, ond wedi anghofio cywiro'r testun a gopïwyd.
Darn N2: Typo
enum CXNameRefFlags {
CXNameRange_WantQualifier = 0x1,
CXNameRange_WantTemplateArgs = 0x2,
CXNameRange_WantSinglePiece = 0x4
};
void AnnotateTokensWorker::HandlePostPonedChildCursor(
CXCursor Cursor, unsigned StartTokenIndex) {
const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier;
....
}
Rhybudd PVS-Studio: V501 Mae yna is-fynegiadau union yr un fath 'CXNameRange_WantQualifier' i'r chwith ac i'r dde o'r '|' gweithredydd. CIndex.cpp 7245
Oherwydd teipio, defnyddir yr un cysonyn a enwir ddwywaith CXNameRange_WantQualifier.
Darn N3: Dryswch gyda blaenoriaeth gweithredwr
int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
....
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
return 0;
....
}
Rhybudd PVS-Stiwdio:
Yn fy marn i, mae hwn yn gamgymeriad hardd iawn. Ydw, dwi'n gwybod bod gen i syniadau rhyfedd am harddwch :).
Yn awr, yn ol
(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0
O safbwynt ymarferol, nid yw cyflwr o'r fath yn gwneud synnwyr, oherwydd gellir ei leihau i:
(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())
Mae hwn yn gamgymeriad amlwg. Yn fwyaf tebygol, roedden nhw eisiau cymharu 0/1 â newidyn mynegai. I drwsio'r cod mae angen i chi ychwanegu cromfachau o amgylch y gweithredwr teiran:
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))
Gyda llaw, mae'r gweithredwr teiran yn beryglus iawn ac yn ysgogi gwallau rhesymegol. Byddwch yn ofalus iawn ag ef a pheidiwch â bod yn farus gyda cromfachau. Edrychais ar y pwnc hwn yn fanylach
Darn N4, N5: Pwyntydd null
Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
....
TypedInit *LHS = dyn_cast<TypedInit>(Result);
....
LHS = dyn_cast<TypedInit>(
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
->Fold(CurRec));
if (!LHS) {
Error(PasteLoc, Twine("can't cast '") + LHS->getAsString() +
"' to string");
return nullptr;
}
....
}
Rhybudd PVS-Stiwdio:
Os bydd y pwyntydd LHS yn null, dylid rhoi rhybudd. Fodd bynnag, yn lle hynny, bydd yr un pwyntydd null hwn yn cael ei ddadgyfeirio: LHS->getAsString().
Mae hon yn sefyllfa nodweddiadol iawn pan fo gwall yn cael ei guddio mewn triniwr gwallau, gan nad oes neb yn eu profi. Mae dadansoddwyr statig yn gwirio pob cod cyraeddadwy, ni waeth pa mor aml y caiff ei ddefnyddio. Mae hon yn enghraifft dda iawn o sut mae dadansoddiad statig yn ategu technegau profi a diogelu gwallau eraill.
Gwall trin pwyntydd tebyg RHS a ganiateir yn y cod ychydig isod: V522 [CWE-476] Efallai y bydd y pwyntydd null 'RHS' yn cael ei gyfeirio. TGParser.cpp 2186
Darn N6: Defnyddio'r pwyntydd ar ôl symud
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-Rhybudd Stiwdio: V522 [CWE-476] Mae'n bosibl y bydd y pwyntydd null 'ProgClone' yn cael ei atgyfeirio. Camgrynhoad.cpp 601
Ar y dechrau pwyntydd smart ProgClone yn peidio â bod yn berchen ar y gwrthrych:
BD.setNewProgram(std::move(ProgClone));
Yn wir, nawr ProgClone yn bwyntydd null. Felly, dylai cyfeirnod pwyntydd nwl ddigwydd ychydig yn is:
Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);
Ond, mewn gwirionedd, ni fydd hyn yn digwydd! Sylwch nad yw'r ddolen yn cael ei gweithredu mewn gwirionedd.
Ar ddechrau'r cynhwysydd Swyddogaethau Cam-Gyfun clirio:
MiscompiledFunctions.clear();
Nesaf, defnyddir maint y cynhwysydd hwn yn y cyflwr dolen:
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {
Mae'n hawdd gweld nad yw'r ddolen yn dechrau. Rwy'n meddwl bod hwn hefyd yn nam a dylai'r cod gael ei ysgrifennu'n wahanol.
Mae'n ymddangos ein bod wedi dod ar draws y cydraddoldeb enwog hwnnw o wallau! Mae un camgymeriad yn cuddio un arall :).
Darn N7: Defnyddio'r pwyntydd ar ôl symud
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-Rhybudd stiwdio: V522 [CWE-476] Mae'n bosibl y bydd y 'Prawf' pwyntydd null yn cael ei gyfeirio. Camgrynhoad.cpp 709
Yr un sefyllfa eto. Ar y dechrau, mae cynnwys y gwrthrych yn cael ei symud, ac yna fe'i defnyddir fel pe na bai dim wedi digwydd. Rwy'n gweld y sefyllfa hon yn amlach ac yn amlach mewn cod rhaglen ar ôl i semanteg symud ymddangos yn C ++. Dyma pam dwi'n caru'r iaith C++! Mae mwy a mwy o ffyrdd newydd o saethu'ch coes eich hun i ffwrdd. Bydd gan y dadansoddwr PVS-Studio waith bob amser :).
Darn N8: Pwyntydd null
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-Rhybudd stiwdio: V522 [CWE-476] Efallai y bydd y pwyntydd null 'Math' yn cael ei gyfeirio. PrettyFunctionDumper.cpp 233
Yn ogystal â thrinwyr gwallau, nid yw swyddogaethau allbrint dadfygio yn cael eu profi fel arfer. Mae gennym achos o'r fath ger ein bron. Mae'r swyddogaeth yn aros am y defnyddiwr, a fydd, yn lle datrys ei broblemau, yn cael ei orfodi i'w drwsio.
Yn gywir:
if (Type)
Type->dump(*this);
else
Printer << "<unknown-type>";
Darn N9: Pwyntydd null
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-Rhybudd stiwdio: V522 [CWE-476] Mae'n bosibl y bydd y pwyntydd null 'Ty' yn cael ei atgyfeirio. SearchableTableEmitter.cpp 614
Rwy'n credu bod popeth yn glir ac nid oes angen esboniad arno.
Darn N10: Typo
bool FormatTokenLexer::tryMergeCSharpNullConditionals() {
....
auto &Identifier = *(Tokens.end() - 2);
auto &Question = *(Tokens.end() - 1);
....
Identifier->ColumnWidth += Question->ColumnWidth;
Identifier->Type = Identifier->Type; // <=
Tokens.erase(Tokens.end() - 1);
return true;
}
Rhybudd PVS-Stiwdio:
Nid oes diben neilltuo newidyn iddo'i hun. Yn fwyaf tebygol eu bod am ysgrifennu:
Identifier->Type = Question->Type;
Darn N11: Toriad amheus
void SystemZOperand::print(raw_ostream &OS) const {
switch (Kind) {
break;
case KindToken:
OS << "Token:" << getToken();
break;
case KindReg:
OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
break;
....
}
Rhybudd PVS-Stiwdio:
Mae yna weithredwr amheus iawn ar y dechrau torri. A wnaethoch chi anghofio ysgrifennu rhywbeth arall yma?
Darn N12: Gwirio pwyntydd ar ôl dadgyfeirio
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");
....
}
Rhybudd PVS-Stiwdio:
Pointer Callee ar y dechrau yn cael ei ddadgyfeirio ar yr adeg y gelwir y ffwythiant caelTTI.
Ac yna mae'n troi allan y dylid gwirio pwyntydd hwn ar gyfer cydraddoldeb nullptr:
if (!Callee || Callee->isDeclaration())
Ond mae hi'n rhy hwyr…
Darn N13 - N...: Gwirio pwyntydd ar ôl dadgyfeirio
Nid yw'r sefyllfa a drafodwyd yn y darn cod blaenorol yn unigryw. Mae'n ymddangos yma:
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()) { // <=
....
}
Rhybudd PVS-Stiwdio: V595 [CWE-476] Defnyddiwyd y pwyntydd 'CalleeFn' cyn iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 1079, 1081. SimplifyLibCalls.cpp 1079
Ac yma:
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()); // <=
....
}
Rhybudd PVS-Stiwdio: V595 [CWE-476] Defnyddiwyd y pwyntydd 'ND' cyn iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 532, 534. SemaTemplateInstantiateDecl.cpp 532
Ac yma:
- V595 [CWE-476] Defnyddiwyd y pwyntydd 'U' cyn iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 404, 407. DWARFormValue.cpp 404
- V595 [CWE-476] Defnyddiwyd y pwyntydd 'ND' cyn iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 2149, 2151. SemaTemplateInstantiate.cpp 2149
Ac yna es i ddim diddordeb mewn astudio'r rhybuddion gyda rhif V595. Felly nid wyf yn gwybod a oes mwy o wallau tebyg ar wahân i'r rhai a restrir yma. Yn fwyaf tebygol mae yna.
Darn N17, N18: Sifft amheus
static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
uint64_t &Encoding) {
....
unsigned Size = RegSize;
....
uint64_t NImms = ~(Size-1) << 1;
....
}
Rhybudd PVS-Stiwdio:
Efallai nad yw'n nam ac mae'r cod yn gweithio'n union fel y bwriadwyd. Ond mae hwn yn amlwg yn lle amheus iawn ac mae angen ei wirio.
Gadewch i ni ddweud y newidyn Maint yn hafal i 16, ac yna awdur y cod yn bwriadu ei gael mewn newidyn NImms gwerth:
1111111111111111111111111111111111111111111111111111111111100000
Fodd bynnag, mewn gwirionedd y canlyniad fydd:
0000000000000000000000000000000011111111111111111111111111100000
Y ffaith yw bod pob cyfrifiad yn digwydd gan ddefnyddio'r math 32-did heb ei lofnodi. A dim ond wedyn, bydd y math 32-did hwn heb ei lofnodi yn cael ei ehangu'n ymhlyg i uint64_t. Yn yr achos hwn, y darnau mwyaf arwyddocaol fydd sero.
Gallwch chi drwsio'r sefyllfa fel hyn:
uint64_t NImms = ~static_cast<uint64_t>(Size-1) << 1;
Sefyllfa debyg: V629 [CWE-190] Ystyriwch archwilio'r ymadrodd 'Immr << 6'. Newid did y gwerth 32-did gydag ehangiad dilynol i'r math 64-did. AArch64AddressingModes.h 269
Darn N19: Allweddair coll arall?
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");
}
....
}
Rhybudd PVS-Stiwdio:
Does dim camgymeriad yma. Ers hynny-bloc y cyntaf if yn gorffen gyda parhau, yna does dim ots, mae yna allweddair arall neu ddim. Y naill ffordd neu'r llall bydd y cod yn gweithio yr un peth. Dal ar goll arall gwneud y cod yn fwy aneglur a pheryglus. Os yn y dyfodol parhau yn diflannu, bydd y cod yn dechrau gweithio'n hollol wahanol. Yn fy marn i mae'n well ychwanegu arall.
Darn N20: Pedwar teip teip o'r un math
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;
}
Rhybuddion PVS-Stiwdio:
- V655 [CWE-480] Roedd y tannau wedi'u concatenated ond nid ydynt yn cael eu defnyddio. Ystyriwch archwilio'r ymadrodd 'Canlyniad + Enw.str()'. Symbol.cpp 32
- V655 [CWE-480] Roedd y tannau wedi'u concatenated ond nid ydynt yn cael eu defnyddio. Ystyriwch archwilio'r mynegiad 'Canlyniad + "(Dosbarth ObjC)" + Name.str()'. Symbol.cpp 35
- V655 [CWE-480] Roedd y tannau wedi'u concatenated ond nid ydynt yn cael eu defnyddio. Ystyriwch archwilio'r mynegiad 'Canlyniad + "(ObjC Class EH)" + Name.str()'. Symbol.cpp 38
- V655 [CWE-480] Roedd y tannau wedi'u concatenated ond nid ydynt yn cael eu defnyddio. Ystyriwch archwilio'r mynegiad 'Canlyniad + "(ObjC IVar)" + Name.str()'. Symbol.cpp 41
Ar ddamwain, defnyddir y gweithredwr + yn lle'r gweithredwr +=. Y canlyniad yw dyluniadau sy'n amddifad o ystyr.
Darn N21: Ymddygiad anniffiniedig
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();
}
}
}
Ceisiwch ddod o hyd i'r cod peryglus eich hun. A dyma lun i dynnu sylw er mwyn peidio ag edrych ar yr ateb ar unwaith:
Rhybudd PVS-Stiwdio:
Llinell broblem:
FeaturesMap[Op] = FeaturesMap.size();
Os elfen Op heb ei ddarganfod, yna mae elfen newydd yn cael ei chreu yn y map ac mae nifer yr elfennau yn y map hwn yn cael ei ysgrifennu yno. Nid yw'n hysbys a fydd y swyddogaeth yn cael ei galw maint cyn neu ar ôl ychwanegu elfen newydd.
Darn N22-N24: Aseiniadau ailadroddus
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;
}
....
}
Rhybudd PVS-Stiwdio:
Dydw i ddim yn meddwl bod yna gamgymeriad gwirioneddol yma. Dim ond aseiniad diangen a ailadroddir. Ond yn dal yn gamgymeriad.
Yn yr un modd:
- V519 [CWE-563] Mae'r newidyn 'B.NDesc' yn cael ei neilltuo gwerthoedd ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 1488, 1489. llvm-nm.cpp 1489
- V519 [CWE-563] Mae'r newidyn yn cael ei neilltuo gwerthoedd ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 59, 61. coff2yaml.cpp 61
Darn N25-N27: Mwy o ailbennu
Nawr, gadewch i ni edrych ar fersiwn ychydig yn wahanol o ailbennu.
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;
....
}
Rhybudd PVS-Stiwdio: V519 [CWE-563] Mae'r newidyn 'Aliniad' yn cael ei neilltuo i werthoedd ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 1158, 1160. LoadStoreVectorizer.cpp 1160
Mae hwn yn god rhyfedd iawn sydd yn ôl pob golwg yn cynnwys gwall rhesymegol. Ar y dechrau, amrywiol Aliniad mae gwerth yn cael ei neilltuo yn dibynnu ar yr amod. Ac yna mae'r aseiniad yn digwydd eto, ond nawr heb unrhyw wiriad.
Mae sefyllfaoedd tebyg i'w gweld yma:
- V519 [CWE-563] Rhoddir gwerthoedd i'r newidyn 'Effeithiau' ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 152, 165. WebAssemblyRegStackify.cpp 165
- V519 [CWE-563] Mae'r newidyn 'ExpectNoDerefChunk' yn cael ei neilltuo gwerthoedd ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 4970, 4973. SemaType.cpp 4973
Darn N28: Cyflwr cywir bob amser
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;
}
....
}
Rhybudd PVS-Stiwdio:
Nid yw gwirio yn gwneud synnwyr. Amrywiol nesafBeit bob amser ddim yn gyfartal â'r gwerth 0x90, sy'n dilyn o'r gwiriad blaenorol. Mae hwn yn rhyw fath o gamgymeriad rhesymegol.
Darn N29 - N...: Amodau gwir/anwir bob amser
Mae'r dadansoddwr yn cyhoeddi llawer o rybuddion bod y cyflwr cyfan (
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;
....
}
Rhybudd PVS-Stiwdio:
Y cysonyn 0xE yw'r gwerth 14 mewn degol. Arholiad RegNo == 0xe ddim yn gwneud synnwyr oherwydd os Rhif Cofrestru > 13, yna bydd y swyddogaeth yn cwblhau ei gweithredu.
Roedd llawer o rybuddion eraill gydag IDs V547 a V560, ond fel gyda
Rhoddaf enghraifft ichi o pam mae astudio'r sbardunau hyn yn ddiflas. Mae'r dadansoddwr yn llygad ei le wrth roi rhybudd ar gyfer y cod canlynol. Ond nid camgymeriad yw hyn.
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
tok::TokenKind ClosingBraceKind) {
bool HasError = false;
....
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
....
}
PVS-Rhybudd Stiwdio: V547 [CWE-570] Mynegiad '!HasError' bob amser yn ffug. UnwrappedLineParser.cpp 1635
Darn N30: Dychweliad amheus
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();
}
....
}
Rhybudd PVS-Stiwdio:
Mae hyn naill ai'n gamgymeriad neu'n dechneg benodol sydd â'r bwriad o esbonio rhywbeth i raglenwyr sy'n darllen y cod. Nid yw'r dyluniad hwn yn esbonio unrhyw beth i mi ac mae'n edrych yn amheus iawn. Gwell peidio ag ysgrifennu felly :).
Wedi blino? Yna mae'n amser gwneud te neu goffi.
Diffygion a nodwyd gan ddiagnosteg newydd
Rwy'n meddwl bod 30 o actifadu hen ddiagnosteg yn ddigon. Gadewch i ni nawr weld pa bethau diddorol sydd i'w cael gyda'r diagnosteg newydd a ymddangosodd yn y dadansoddwr ar ôl hynny
Darn N31: Cod anghyraeddadwy
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();
}
Rhybudd PVS-Stiwdio:
Fel y gwelwch, mae dwy gangen y gweithredwr if yn gorffen gyda galwad i'r gweithredwr dychwelyd. Yn unol â hynny, y cynhwysydd CtorDtorsByBlaenoriaeth fydd byth yn cael ei glirio.
Darn N32: Cod anghyraeddadwy
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;
}
Rhybudd PVS-Stiwdio: V779 [CWE-561] Cod na ellir ei gyrraedd wedi'i ganfod. Mae'n bosibl bod gwall yn bresennol. LLParser.cpp 835
Sefyllfa ddiddorol. Edrychwn ar y lle hwn yn gyntaf:
return ParseTypeIdEntry(SummaryID);
break;
Ar yr olwg gyntaf, mae'n ymddangos nad oes unrhyw gamgymeriad yma. Mae'n edrych fel y gweithredwr torri mae un ychwanegol yma, a gallwch ei ddileu yn syml. Fodd bynnag, nid yw pob un mor syml.
Mae'r dadansoddwr yn rhoi rhybudd ar y llinellau:
Lex.setIgnoreColonInIdentifiers(false);
return false;
Ac yn wir, mae'r cod hwn yn anghyraeddadwy. Pob achos yn newid yn gorffen gyda galwad gan y gweithredwr dychwelyd. Ac yn awr disynnwyr yn unig torri ddim yn edrych mor ddiniwed! Efallai y dylai un o'r canghennau orffen gyda torri, nid ymlaen dychwelyd?
Darn N33: Ailosod darnau uchel ar hap
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);
....
}
Rhybudd PVS-Stiwdio:
Sylwch fod y swyddogaeth getStubAliniad yn dychwelyd math heb ei arwyddo. Gadewch i ni gyfrifo gwerth y mynegiad, gan dybio bod y ffwythiant yn dychwelyd y gwerth 8:
~(getStubAlignment() - 1)
~(8u-1)
0xFFFFFFFF8u
Nawr sylwi bod y newidyn Maint Data Mae ganddo fath 64-did heb ei lofnodi. Mae'n ymddangos, wrth berfformio gweithrediad DataSize & 0xFFFFFFF8u, y bydd pob un o'r tri deg dau o ddarnau lefel uchel yn cael eu hailosod i sero. Yn fwyaf tebygol, nid dyma oedd y rhaglennydd ei eisiau. Rwy'n amau ei fod eisiau cyfrifo: DataSize & 0xFFFFFFFFFFFFFFF8u.
I drwsio'r gwall, dylech ysgrifennu hwn:
DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1);
Neu felly:
DataSize &= ~(getStubAlignment() - 1ULL);
Darn N34: Cast math penodol wedi methu
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);
....
}
Rhybudd PVS-Stiwdio:
Defnyddir castio math penodol i osgoi gorlif wrth luosi newidynnau math int. Fodd bynnag, nid yw castio math penodol yma yn amddiffyn rhag gorlif. Yn gyntaf, bydd y newidynnau'n cael eu lluosi, a dim ond wedyn bydd canlyniad 32-did y lluosiad yn cael ei ehangu i'r math
Darn N35: Copi-Gludo wedi Methu
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;
}
....
}
Mae'r diagnostig diddorol newydd hwn yn nodi sefyllfaoedd lle copïwyd darn o god a newidiwyd rhai enwau ynddo, ond mewn un lle ni chawsant eu cywiro.
Sylwch eu bod wedi newid yn yr ail floc Op0 ar Op1. Ond mewn un man wnaethon nhw ddim ei drwsio. Yn fwyaf tebygol y dylai fod wedi'i ysgrifennu fel hyn:
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
return &I;
}
Darn N36: Dryswch Amrywiol
struct Status {
unsigned Mask;
unsigned Mode;
Status() : Mask(0), Mode(0){};
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
Mode &= Mask;
};
....
};
Rhybudd PVS-Stiwdio:
Mae'n beryglus iawn rhoi'r un enwau i ddadleuon swyddogaeth ag aelodau dosbarth. Mae'n hawdd iawn drysu. Mae gennym achos o'r fath ger ein bron. Nid yw'r ymadrodd hwn yn gwneud synnwyr:
Mode &= Mask;
Mae'r ddadl swyddogaeth yn newid. Dyna i gyd. Nid yw'r ddadl hon yn cael ei defnyddio mwyach. Yn fwyaf tebygol y dylech fod wedi ei ysgrifennu fel hyn:
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
this->Mode &= Mask;
};
Darn N37: Dryswch Amrywiol
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;
}
Rhybudd PVS-Studio: V1001 [CWE-563] Mae'r newidyn 'Maint' wedi'i neilltuo ond nid yw'n cael ei ddefnyddio erbyn diwedd y ffwythiant. Gwrthrych.cpp 424
Mae'r sefyllfa yn debyg i'r un blaenorol. Dylid ei ysgrifennu:
this->Size += this->EntrySize;
Darn N38-N47: Maent wedi anghofio gwirio'r mynegai
Yn flaenorol, buom yn edrych ar enghreifftiau o sbarduno diagnostig
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()); // <=
....
}
Rhybudd PVS-Stiwdio: V1004 [CWE-476] Defnyddiwyd y pwyntydd 'Ptr' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 729, 738. TargetTransformInfoImpl.h 738
Amrywiol Ptr gall fod yn gyfartal nullptr, fel y dangosir gan y siec:
if (Ptr != nullptr)
Fodd bynnag, o dan y pwyntydd hwn mae'n cael ei ddadgyfeirio heb wiriad rhagarweiniol:
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());
Gadewch i ni ystyried achos tebyg arall.
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(); // <=
....
}
Rhybudd PVS-Stiwdio: V1004 [CWE-476] Defnyddiwyd y pwyntydd 'FD' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 3228, 3231. CGDebugInfo.cpp 3231
Rhowch sylw i'r arwydd FD. Rwy’n siŵr bod y broblem i’w gweld yn glir ac nid oes angen esboniad arbennig.
Ac ymhellach:
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()); // <=
....
}
Rhybudd PVS-Stiwdio: V1004 [CWE-476] Defnyddiwyd y pwyntydd 'PtrTy' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 960, 965. InterleavedLoadCombinePass.cpp 965
Sut i amddiffyn eich hun rhag gwallau o'r fath? Byddwch yn fwy sylwgar ar Code-Review a defnyddiwch y dadansoddwr statig PVS-Studio i wirio'ch cod yn rheolaidd.
Nid oes diben dyfynnu darnau eraill o god gyda gwallau o'r math hwn. Dim ond rhestr o rybuddion a adawaf yn yr erthygl:
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'Expr' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 1049, 1078. DebugInfoMetadata.cpp 1078
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'PI' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 733, 753. LegacyPassManager.cpp 753
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'StatepointCall' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 4371, 4379. Verifier.cpp 4379
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'RV' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 2263, 2268. TGParser.cpp 2268
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'CalleeFn' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 1081, 1096. SimplifyLibCalls.cpp 1096
- V1004 [CWE-476] Defnyddiwyd y pwyntydd 'TC' yn anniogel ar ôl iddo gael ei ddilysu yn erbyn nullptr. Llinellau siec: 1819, 1824. Driver.cpp 1824
Darn N48-N60: Ddim yn feirniadol, ond diffyg (gollyngiad cof posibl)
std::unique_ptr<IRMutator> createISelMutator() {
....
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
Strategies.emplace_back(
new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
....
}
Rhybudd PVS-Stiwdio:
I ychwanegu elfen at ddiwedd cynhwysydd fel std::fector > ni allwch ysgrifennu yn unig xxx.push_back(X newydd), gan nad oes trosiad ymhlyg o X* в std::unigryw_ptr.
Ateb cyffredin yw ysgrifennu xxx.emplace_back(X newydd)gan ei fod yn llunio: dull emplace_back yn llunio elfen yn uniongyrchol o'i ddadleuon ac felly'n gallu defnyddio llunwyr amlwg.
Nid yw'n ddiogel. Os yw'r fector yn llawn, yna caiff y cof ei ailddyrannu. Efallai y bydd y gweithrediad ailddyrannu cof yn methu, gan arwain at eithriad yn cael ei daflu std::bad_alloc. Yn yr achos hwn, bydd y pwyntydd yn cael ei golli ac ni fydd y gwrthrych a grëwyd byth yn cael ei ddileu.
Ateb diogel yw creu unigryw_ptra fydd yn berchen ar y pwyntydd cyn i'r fector geisio ailddyrannu cof:
xxx.push_back(std::unique_ptr<X>(new X))
Ers C++14, gallwch ddefnyddio 'std:: make_unique':
xxx.push_back(std::make_unique<X>())
Nid yw'r math hwn o ddiffyg yn hanfodol ar gyfer LLVM. Os na ellir dyrannu cof, bydd y casglwr yn stopio. Fodd bynnag, ar gyfer ceisiadau gyda hir
Felly, er nad yw'r cod hwn yn fygythiad ymarferol i LLVM, roedd yn ddefnyddiol i mi siarad am y patrwm gwall hwn a bod y dadansoddwr PVS-Studio wedi dysgu ei adnabod.
Rhybuddion eraill o'r math hwn:
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Passes' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. PassManager.h 546
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'AAs' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. AliasAnalysis.h 324
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Entries' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. DWARFDebugFrame.cpp 519
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'AllEdges' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. CFGMST.h 268
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'VMaps' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. SimpleLoopUnswitch.cpp 2012
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Records' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. FDRLogBuilder.h 30
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'PendingSubmodules' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. ModiwlMap.cpp 810
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Objects' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. DebugMap.cpp 88
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Strategaethau' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-isel-fuzzer.cpp 60
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 685
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 686
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 688
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 689
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 690
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 691
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 692
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 693
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Addaswyr' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. llvm-straen.cpp 694
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Operands' trwy'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. GlobalISelEmitter.cpp 1911
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Stash' gan y dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. GlobalISelEmitter.cpp 2100
- V1023 [CWE-460] Mae pwyntydd heb berchennog yn cael ei ychwanegu at y cynhwysydd 'Matchers' gan ddefnyddio'r dull 'emplace_back'. Bydd gollyngiad cof yn digwydd rhag ofn y bydd eithriad. GlobalISelEmitter.cpp 2702
Casgliad
Cyhoeddais 60 o rybuddion i gyd ac yna stopiais. A oes unrhyw ddiffygion eraill y mae'r dadansoddwr PVS-Studio yn eu canfod yn LLVM? Oes, mae gen i. Fodd bynnag, pan oeddwn yn ysgrifennu darnau cod ar gyfer yr erthygl, roedd hi'n hwyr gyda'r nos, neu'n hytrach yn noson hyd yn oed, a phenderfynais ei bod yn bryd ei alw'n ddiwrnod.
Rwy'n gobeithio ei fod yn ddiddorol ichi ac y byddwch am roi cynnig ar y dadansoddwr PVS-Studio.
Gallwch chi lawrlwytho'r dadansoddwr a chael yr allwedd minesweeper yn
Yn bwysicaf oll, defnyddiwch ddadansoddiad statig yn rheolaidd. Gwiriadau un-amser, a gynhaliwyd gennym ni er mwyn poblogeiddio'r fethodoleg dadansoddi statig ac nid yw PVS-Studio yn senario arferol.
Pob lwc wrth wella ansawdd a dibynadwyedd eich cod!
Os ydych chi am rannu'r erthygl hon â chynulleidfa Saesneg ei hiaith, defnyddiwch y ddolen gyfieithu: Andrey Karpov.
Ffynhonnell: hab.com