Tá níos mó ná dhá bhliain caite ó rinneadh seiceáil cód dheireanach ar thionscadal LLVM ag baint úsáide as ár n-anailíseoir PVS-Studio. Déanaimis cinnte go bhfuil an anailísí PVS-Studio fós ina phríomhuirlis chun earráidí agus leochaileachtaí féideartha a aithint. Chun seo a dhéanamh, déanfaimid earráidí nua a sheiceáil agus a aimsiú san eisiúint LLVM 8.0.0.
Alt le scríobh
Le bheith macánta, ní raibh mé ag iarraidh an t-alt seo a scríobh. Níl sé suimiúil scríobh faoi thionscadal atá seiceáilte againn arís agus arís eile (
Gach uair a scaoiltear nó a nuashonraítear leagan nua de LLVM
Féach, d'fhoghlaim an leagan nua de Anailíseoir Statach Clang conas earráidí nua a aimsiú! Feictear dom go bhfuil laghdú ag teacht ar ábharthacht úsáid PVS-Studio. Aimsíonn Clang níos mó earráidí ná mar a bhí roimhe agus cuireann sé suas le cumais PVS-Studio. Cad a cheapann tú faoi seo?
Chuige seo ba mhaith liom i gcónaí rud éigin mar seo a fhreagairt:
Ní shuíonn muid díomhaoin ach an oiread! Tá feabhas suntasach déanta againn ar chumais an anailísí PVS-Studio. Mar sin ná bí buartha, leanaimid orainn ag stiúradh mar a bhí roimhe seo.
Ar an drochuair, is drochfhreagra é seo. Níl aon cruthúnais ann. Agus is é sin an fáth go bhfuil an t-alt seo á scríobh agam anois. Mar sin, tá an tionscadal LLVM seiceáilte arís agus tá éagsúlacht earráidí aimsithe ann. Léireoidh mé anois iad siúd a raibh cuma spéisiúil ormsa orthu. Ní féidir le Anailíseoir Clang Statach na hearráidí seo a aimsiú (nó tá sé thar a bheith deacair é sin a dhéanamh lena chabhair). Ach is féidir linn. Thairis sin, fuair mé agus scríobh mé síos na hearráidí seo go léir i tráthnóna amháin.
Ach ghlac roinnt seachtainí leis an alt a scríobh. Ní raibh mé in ann mé féin a thabhairt liom chun é seo go léir a chur i téacs :).
Dála an scéil, má tá suim agat cad iad na teicneolaíochtaí a úsáidtear san anailíseoir PVS-Studio chun earráidí agus leochaileachtaí a d'fhéadfadh a bheith ann a aithint, molaim duit dul i dtaithí air seo.
Diagnóisic nua agus sean
Mar a tugadh faoi deara cheana féin, timpeall dhá bhliain ó shin rinneadh an tionscadal LLVM a sheiceáil arís, agus ceartaíodh na hearráidí a aimsíodh. Anois beidh an t-alt seo i láthair bhaisc nua earráidí. Cén fáth a bhfuarthas fabhtanna nua? Tá 3 chúis leis seo:
- Tá an tionscadal LLVM ag athrú, ag athrú seanchód agus ag cur cód nua leis. Ar ndóigh, tá earráidí nua sa chód modhnaithe agus scríofa. Léiríonn sé seo go soiléir gur cheart anailís statach a úsáid go rialta, agus ní ó am go chéile. Léiríonn ár n-alt go maith cumais an anailísí PVS-Studio, ach níl baint ar bith aige seo le cáilíocht an chóid a fheabhsú agus an costas a bhaineann le earráidí a shocrú a laghdú. Bain úsáid as anailísí cód statach go rialta!
- Táimid ag tabhairt chun críche agus ag feabhsú diagnóisic reatha. Mar sin, is féidir leis an anailíseoir earráidí a aithint nár thug sé faoi deara le linn scanadh roimhe seo.
- Tá diagnóisic nua le feiceáil i PVS-Studio nach raibh ann 2 bhliain ó shin. Chinn mé aird a tharraingt orthu i rannóg ar leith chun forbairt PVS-Studio a thaispeáint go soiléir.
Lochtanna arna sainaithint ag diagnóisic a bhí ann 2 bhliain ó shin
Cuid N1: Cóip-Greamaigh
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
....
}
Rabhadh PVS-Studio:
Déantar seiceáil faoi dhó go dtosaíonn an t-ainm leis an bhfotheaghrán "avx512.mask.permvar.". Sa dara seiceáil, ba léir gur theastaigh uathu rud éigin eile a scríobh, ach rinne siad dearmad ar an téacs cóipeáilte a cheartú.
Mír 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;
....
}
Rabhadh PVS-Studio: V501 Tá fo-léirithe comhionanna 'CXNameRange_WantQualifier' ar chlé agus ar dheis an '|' oibreoir. CIndex.cpp 7245
De bharr tíopála, úsáidtear an tairiseach ainmnithe céanna faoi dhó CXNameRange_WantQualifier.
Cuid N3: Mearbhall le tosaíocht oibreora
int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
....
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
return 0;
....
}
Rabhadh PVS-Studio:
Is é mo thuairim gur botún an-álainn é seo. Sea, tá a fhios agam go bhfuil smaointe aisteach agam faoi áilleacht :).
Anois, de réir
(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0
Ó thaobh praiticiúil, ní dhéanann coinníoll den sórt sin ciall, mar is féidir é a laghdú go dtí:
(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())
Is botún soiléir é seo. Is dócha go raibh siad ag iarraidh 0/1 a chur i gcomparáid le hathróg innéacs. Chun an cód a shocrú ní mór duit lúibíní a chur timpeall ar an oibreoir trínártha:
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))
Dála an scéil, tá an t-oibreoir trínártha an-chontúirteach agus spreagann sé earráidí loighciúla. Bí an-chúramach leis agus ná bí sanntach le lúibíní. D'fhéach mé ar an ábhar seo níos mine
Fragment N4, N5: Pointeoir 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;
}
....
}
Rabhadh PVS-Studio:
Má tá an pointeoir LHS ar neamhní, ba cheart rabhadh a eisiúint. Mar sin féin, ina ionad sin, déanfar an pointeoir nialasach céanna seo a dhífhostú: LHS->getAsString().
Is gnáthchás é seo nuair a bhíonn earráid i bhfolach i láimhseálaí earráide, toisc nach ndéanann aon duine tástáil orthu. Seiceálann anailíseoirí statacha gach cód insroichte, is cuma cé chomh minic a úsáidtear é. Is sampla an-mhaith é seo ar conas a chomhlánaíonn anailís statach teicnící tástála agus cosanta earráide eile.
Earráid láimhseála pointeora dá samhail HRH ceadaithe sa chód díreach thíos: V522 [CWE-476] D’fhéadfadh sé go ndéanfaí an pointeoir nialasach ‘RHS’ a dhífhostú. TGParser.cpp 2186
Fragment N6: Úsáid an pointeoir tar éis bogadh
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);
}
....
}
Rabhadh PVS-Stiúideo: V522 [CWE-476] D’fhéadfadh sé go ndéanfaí an pointeoir nialasach ‘ProgClone’ a athshonrú. Miscompilation.cpp 601
Ag an tús pointeoir cliste ClárClone scoirfidh sé de bheith ina húinéir ar an réad:
BD.setNewProgram(std::move(ProgClone));
Go deimhin, anois ClárClone is pointeoir nialasach. Mar sin, ba cheart go dtarlódh tagairt pointeora nialasach díreach thíos:
Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);
Ach, i ndáiríre, ní tharlóidh sé seo! Tabhair faoi deara nach bhfuil an lúb chun báis i ndáiríre.
Ag tús an choimeádáin Feidhmeanna Miscompiled glanta:
MiscompiledFunctions.clear();
Ansin, úsáidtear méid an choimeádáin seo sa riocht lúb:
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {
Is furasta a fheiceáil nach dtosaíonn an lúb. Sílim gur fabht é seo freisin agus ba cheart an cód a scríobh ar bhealach difriúil.
Is cosúil gur tháinig muid ar an bpaireacht cháiliúil earráidí sin! Cuimsíonn botún amháin botún eile :).
Fragment N7: Úsáid an pointeoir tar éis bogadh
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;
}
....
}
Rabhadh PVS-Stiúideo: V522 [CWE-476] D'fhéadfadh sé go ndéanfaí an pointeoir nialasach 'Tástáil' a athshonrú. Miscompilation.cpp 709
An scéal céanna arís. Ar dtús, bogtar ábhar an ruda, agus ansin úsáidtear é amhail is nár tharla aon rud. Feicim an cás seo níos mó agus níos minice i gcód cláir tar éis do shéimeantaic gluaiseachta a bheith le feiceáil in C++. Sin é an fáth gur breá liom an teanga C++! Tá níos mó agus níos mó bealaí nua ann chun do chos féin a scaoileadh. Beidh obair i gcónaí ag an anailísí PVS-Studio :).
Mír N8: Pointeoir 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);
}
Rabhadh PVS-Stiúideo: V522 [CWE-476] D’fhéadfadh sé go ndéanfaí an pointeoir nialasach ‘Cineál’ a dhífhostú. PrettyFunctionDumper.cpp 233
Chomh maith le láimhseálaithe earráide, ní dhéantar tástáil ar fheidhmeanna asphrionta dífhabhtaithe de ghnáth. Níl ach a leithéid de chás os ár gcomhair. Tá an fheidhm ag fanacht leis an úsáideoir, a bheidh, in ionad a chuid fadhbanna a réiteach, iallach a shocrú é.
Ceart:
if (Type)
Type->dump(*this);
else
Printer << "<unknown-type>";
Mír N9: Pointeoir 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());
....
}
Rabhadh PVS-Stiúideo: V522 [CWE-476] D’fhéadfadh sé go ndéanfaí an pointeoir nialasach ‘Ty’ a athshonrú. InchuardaitheTableEmitter.cpp 614
Sílim go bhfuil gach rud soiléir agus nach gá míniú.
Mír 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;
}
Rabhadh PVS-Studio:
Níl aon phointe ag baint le hathróg a shannadh dó féin. Is dócha gur theastaigh uathu scríobh:
Identifier->Type = Question->Type;
Fragment N11: Briseadh amhrasach
void SystemZOperand::print(raw_ostream &OS) const {
switch (Kind) {
break;
case KindToken:
OS << "Token:" << getToken();
break;
case KindReg:
OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
break;
....
}
Rabhadh PVS-Studio:
Tá oibreoir an-amhrasach ag an tús bhriseadh. An ndearna tú dearmad rud éigin eile a scríobh anseo?
Cuid N12: Pointeoir a sheiceáil tar éis díthagairt a dhéanamh
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");
....
}
Rabhadh PVS-Studio:
Pointeoir Callee ag an tús tá dereferenced ag an am a dtugtar an fheidhm faighTTI.
Agus ansin tharlaíonn sé gur chóir an pointeoir seo a sheiceáil le haghaidh comhionannais nullptr:
if (!Callee || Callee->isDeclaration())
Ach tá sé ró-dhéanach…
Fragment N13 - N...: Pointeoir a sheiceáil tar éis díthagairt
Níl an scéal a pléadh sa bhlúire cód roimhe seo uathúil. Tá sé le feiceáil anseo:
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()) { // <=
....
}
Rabhadh PVS-Studio: V595 [CWE-476] Úsáideadh an pointeoir ‘CalleeFn’ sular fíoraíodh é i gcoinne nullptr. Línte seiceála: 1079, 1081. SimplifyLibCalls.cpp 1079
Agus anseo:
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()); // <=
....
}
Rabhadh PVS-Studio: V595 [CWE-476] Úsáideadh an pointeoir 'ND' sular fíoraíodh é i gcoinne nullptr. Seiceáil línte: 532, 534. SemaTemplateInstantiateDecl.cpp 532
Agus anseo:
- V595 [CWE-476] Úsáideadh an pointeoir 'U' sular fíoraíodh é i gcoinne nullptr. Línte seiceála: 404, 407. DWARFormValue.cpp 404
- V595 [CWE-476] Úsáideadh an pointeoir 'ND' sular fíoraíodh é i gcoinne nullptr. Línte seiceála: 2149, 2151. SemaTemplateInstantiate.cpp 2149
Agus ansin níor bhain mé leas as staidéar a dhéanamh ar na rabhaidh leis an uimhir V595. Mar sin níl a fhios agam an bhfuil níos mó earráidí cosúla seachas na cinn atá liostaithe anseo. Is dócha go bhfuil.
Fragment N17, N18: Aistriú amhrasach
static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
uint64_t &Encoding) {
....
unsigned Size = RegSize;
....
uint64_t NImms = ~(Size-1) << 1;
....
}
Rabhadh PVS-Studio:
Seans nach fabht atá ann agus oibríonn an cód go díreach mar a bhí beartaithe. Ach is léir gur áit an-amhrasach é seo agus ní mór é a sheiceáil.
Ligean le rá an athróg méid comhionann le 16, agus ansin bheartaigh údar an chóid é a fháil in athróg nimms luach:
1111111111111111111111111111111111111111111111111111111111100000
Mar sin féin, i ndáiríre beidh an toradh:
0000000000000000000000000000000011111111111111111111111111100000
Is é fírinne an scéil go dtarlaíonn gach ríomh ag baint úsáide as an gcineál 32-giotán gan síniú. Agus ansin amháin, déanfar an cineál 32-giotán seo gan síniú a leathnú go hintuigthe uint64_t. Sa chás seo, beidh na giotáin is suntasaí náid.
Is féidir leat an cás a shocrú mar seo:
uint64_t NImms = ~static_cast<uint64_t>(Size-1) << 1;
Cás cosúil leis: V629 [CWE-190] Smaoinigh ar an slonn 'Immr << 6' a iniúchadh. Aistriú giotán den luach 32-giotán agus leathnú ina dhiaidh sin chuig an gcineál 64-giotán. AArch64AddressingModes.h 269
Fragment N19: Eochairfhocal ar iarraidh eile?
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");
}
....
}
Rabhadh PVS-Studio:
Níl aon botún anseo. Ó tharla an bloc sin den chéad uair if chríochnaíonn le leanúint ar aghaidh, ansin is cuma, tá eochairfhocal eile nó nach bhfuil. Nó slí oibreoidh an cód mar an gcéanna. Fós caillte eile a dhéanann an cód níos doiléir agus contúirteacha. Más rud é sa todhchaí leanúint ar aghaidh disappears, beidh an cód tosú ag obair go hiomlán difriúil. Is é mo thuairim go bhfuil sé níos fearr a chur leis eile.
Fragment N20: Ceithre clóscríobhán den chineál céanna
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;
}
Rabhadh PVS-Studio:
- V655 [CWE-480] Comhdhlúthaíodh na teaghráin ach ní úsáidtear iad. Smaoinigh ar an slonn 'Torthaí + Ainm.str()' a iniúchadh. Siombail.cpp 32
- V655 [CWE-480] Comhdhlúthaíodh na teaghráin ach ní úsáidtear iad. Smaoinigh ar an slonn 'Toradh + "(ObjC Class)" + Name.str()' a iniúchadh. Siombail.cpp 35
- V655 [CWE-480] Comhdhlúthaíodh na teaghráin ach ní úsáidtear iad. Smaoinigh ar an slonn 'Toradh + "(ObjC Class EH)" + Name.str()' a iniúchadh. Siombail.cpp 38
- V655 [CWE-480] Comhdhlúthaíodh na teaghráin ach ní úsáidtear iad. Smaoinigh ar an slonn 'Toradh + "(ObjC IVar)" + Name.str()' a iniúchadh. Siombail.cpp 41
Trí thimpiste, úsáidtear an t-oibreoir + in ionad an oibreora +=. Is é an toradh ná dearaí nach bhfuil brí leo.
Fragment N21: Iompar neamhshainithe
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();
}
}
}
Déan iarracht an cód contúirteach a aimsiú duit féin. Agus is pictiúr é seo chun aird a tharraingt ar shiúl ionas nach bhféachtar láithreach ar an bhfreagra:
Rabhadh PVS-Studio:
Líne fhadhb:
FeaturesMap[Op] = FeaturesMap.size();
Más eilimint Op Ní fhaightear, ansin cruthaítear eilimint nua sa léarscáil agus scríobhtar líon na ndúl sa léarscáil seo ann. Níl a fhios ach an dtabharfar an fheidhm méid roimh nó tar éis eilimint nua a chur leis.
Fragment N22-N24: Tascanna arís agus arís eile
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;
}
....
}
Rabhadh PVS-Studio:
Ní dóigh liom go bhfuil botún fíor anseo. Just a sannadh arís agus arís eile gan ghá. Ach fós botún.
Mar an gcéanna:
- V519 [CWE-563] Sanntar luachanna don athróg ‘B.NDesc’ faoi dhó as a chéile. B’fhéidir gur botún é seo. Línte seiceála: 1488, 1489. llvm-nm.cpp 1489
- V519 [CWE-563] Sanntar luachanna don athróg faoi dhó as a chéile. B’fhéidir gur botún é seo. Seiceáil línte: 59, 61. coff2yaml.cpp 61
Fragment N25-N27: Tuilleadh athshannta
Anois, déanaimis féachaint ar leagan beagán difriúil den athshannadh.
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;
....
}
Rabhadh PVS-Stiúideo: V519 [CWE-563] Sanntar luachanna don athróg ‘Ailíniú’ dhá uair as a chéile. B’fhéidir gur botún é seo. Seiceáil línte: 1158, 1160. LoadStoreVectorizer.cpp 1160
Is é seo an cód an-aisteach go bhfuil cosúil earráid loighciúil. Ag an tús, athraitheach Ailíniú sanntar luach ag brath ar an gcoinníoll. Agus ansin tarlaíonn an tasc arís, ach anois gan aon seiceáil.
Tá cásanna cosúla le feiceáil anseo:
- V519 [CWE-563] Sanntar luachanna don athróg ‘Éifeachtaí’ faoi dhó as a chéile. B’fhéidir gur botún é seo. Línte seiceála: 152, 165. WebAssemblyRegStackify.cpp 165
- V519 [CWE-563] Sanntar luachanna don athróg ‘ExpectNoDerefChunk’ faoi dhó as a chéile. B’fhéidir gur botún é seo. Línte seiceála: 4970, 4973. SemaType.cpp 4973
Mír N28: Bail fíor i gcónaí
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;
}
....
}
Rabhadh PVS-Studio:
Ní dhéanann seiceáil ciall. Athróg nextByte i gcónaí nach ionann an luach 0x90, a leanann ón seiceáil roimhe seo. Is earráid loighciúil de shaghas éigin é seo.
Cuid N29 - N...: Coinníollacha fíor/bréagacha i gcónaí
Eisíonn an anailíseoir go leor rabhadh go bhfuil an coinníoll iomlán (
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;
....
}
Rabhadh PVS-Studio:
Is é an tairiseach 0xE an luach 14 i deachúil. Scrúdú Rial Níl == 0xe nach bhfuil ciall leis mar má Rial > 13, ansin déanfaidh an fheidhm a fhorghníomhú i gcrích.
Bhí go leor rabhadh eile le IDs V547 agus V560, ach mar a bhí
Tabharfaidh mé sampla duit de cén fáth a bhfuil sé leadránach staidéar a dhéanamh ar na truicear seo. Tá an anailíseoir go hiomlán ceart agus é ag eisiúint rabhadh don chód seo a leanas. Ach ní botún é seo.
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
tok::TokenKind ClosingBraceKind) {
bool HasError = false;
....
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
....
}
Rabhadh PVS-Stiúideo: V547 [CWE-570] Léiriú '!HasError' i gcónaí bréagach. UnwrappedLineParser.cpp 1635
Fragment N30: Fill ar ais amhrasach
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();
}
....
}
Rabhadh PVS-Studio:
Earráid nó teicníocht ar leith é seo atá beartaithe chun rud éigin a mhíniú do ríomhchláraitheoirí a léann an cód. Ní mhíníonn an dearadh seo aon rud dom agus tá cuma an-amhrasach air. Is fearr gan scríobh mar sin :).
Tuirseach? Ansin tá sé in am tae nó caife a dhéanamh.
Lochtanna arna sainaithint ag diagnóisic nua
Sílim gur leor 30 gníomhachtú diagnóisic d'aois. Feicfimid anois cad iad na rudaí suimiúla is féidir a fháil leis na diagnóisic nua a bhí le feiceáil san anailíseoir ina dhiaidh sin
Fragment N31: Cód dosroichte
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();
}
Rabhadh PVS-Studio:
Mar a fheiceann tú, an dá bhrainse den oibreoir if chríochnaíonn sé le glaoch ar an oibreoir ar ais. Dá réir sin, an coimeádán CtorDtorsByTosaíocht ní bheidh glanta.
Fragment N32: Cód dosroichte
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;
}
Rabhadh PVS-Stiúideo: V779 [CWE-561] Cód dosroichte braite. Is féidir go bhfuil earráid i láthair. LLParser.cpp 835
Staid suimiúil. Breathnaímid ar an áit seo ar dtús:
return ParseTypeIdEntry(SummaryID);
break;
Ar an gcéad amharc, is cosúil nach bhfuil aon earráid anseo. Breathnaíonn sé cosúil leis an oibreoir bhriseadh tá ceann breise anseo, agus is féidir leat a scriosadh go simplí. Mar sin féin, ní léir chomh simplí.
Eisíonn an anailíseoir rabhadh ar na línte:
Lex.setIgnoreColonInIdentifiers(false);
return false;
Agus go deimhin, níl an cód seo inrochtana. Gach cás i aistriú chríochnaíonn sé le glao ón oibreoir ar ais. Agus anois senseless ina n-aonar bhriseadh nach cuma chomh neamhdhíobhálach! B'fhéidir gur chóir go mbeadh deireadh le ceann de na brainsí bhriseadh, ní ar ar ais?
Fragment N33: Athshocrú randamach ar ghiotán arda
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);
....
}
Rabhadh PVS-Studio:
Tabhair faoi deara go bhfuil an fheidhm getStubAilíniú cineál tuairisceáin gan síniú. Déanaimis luach an slonn a ríomh, ag glacadh leis go dtugann an fheidhm an luach 8 ar ais:
~(getStubAlignment() - 1)
~(8u-1)
0xFFFFFFFF8u
Anois faoi deara go bhfuil an athróg Méid Sonraí tá cineál 64-giotán gan síniú aige. Tharlaíonn sé go raibh nuair a bheidh an oibríocht DataSize & 0xFFFFFFF8u á dhéanamh, athshocrófar na tríocha dó giotán ard-ordú go nialas. Is dócha, ní hé seo an rud a theastaigh ón ríomhchláraitheoir. Doigh liom go raibh sé ag iarraidh a ríomh: DataSize & 0xFFFFFFFFFFFFFFF8u.
Chun an earráid a réiteach, ba cheart duit é seo a scríobh:
DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1);
Nó mar sin:
DataSize &= ~(getStubAlignment() - 1ULL);
Fragment N34: Teip den chineál follasach
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);
....
}
Rabhadh PVS-Studio:
Úsáidtear cineál réitigh follasach chun ró-shreabhadh a sheachaint nuair a bhíonn athróga cineáil á iolrú int. Mar sin féin, ní chosnaíonn cineál-réitigh sainráite anseo in aghaidh ró-shreabhadh. Ar dtús, déanfar na hathróga a iolrú, agus go dtí sin leathnófar toradh 32-giotán an iolrúcháin go dtí an cineál
Fragment N35: Cóip-Greamú Theip
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;
}
....
}
Aithníonn an dhiagnóiseach spéisiúil nua seo cásanna ina ndearnadh cóip de chód agus inar tosaíodh ar roinnt ainmneacha a athrú, ach in aon áit amháin níor cheartaigh siad é.
Tabhair faoi deara gur athraigh siad sa dara bloc Op0 ar Op1. Ach in aon áit amháin níor réitigh siad é. Is dócha gur cheart é a bheith scríofa mar seo:
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
return &I;
}
Cuid N36: Mearbhall Athraitheach
struct Status {
unsigned Mask;
unsigned Mode;
Status() : Mask(0), Mode(0){};
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
Mode &= Mask;
};
....
};
Rabhadh PVS-Studio:
Tá sé an-chontúirteach na hainmneacha céanna a thabhairt d’argóintí feidhme agus baill ranga. Tá sé an-éasca a bheith ar dhaoine eatarthu. Níl ach a leithéid de chás os ár gcomhair. Ní dhéanann an slonn seo ciall:
Mode &= Mask;
Athraíonn argóint na feidhme. Sin é an méid. Ní úsáidtear an argóint seo a thuilleadh. Is dócha gur cheart duit é a scríobh mar seo:
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
this->Mode &= Mask;
};
Cuid N37: Mearbhall Athraitheach
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;
}
Rabhadh PVS-Studio: V1001 [CWE-563] Sanntar an athróg ‘Méid’ ach ní úsáidtear í faoi dheireadh na feidhme. Réad.cpp 424
Tá an scéal cosúil leis an gceann roimhe seo. Ba chóir a scríobh:
this->Size += this->EntrySize;
Fragment N38-N47: Rinne siad dearmad an t-innéacs a sheiceáil
Roimhe seo, d’fhéachamar ar shamplaí de thrioblóidí diagnóiseacha
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()); // <=
....
}
Rabhadh PVS-Studio: V1004 [CWE-476] Úsáideadh an pointeoir 'Ptr' go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 729, 738. TargetTransformInfoImpl.h 738
Athróg Ptr féadfaidh sé a bheith comhionann nullptr, mar is léir ón seic:
if (Ptr != nullptr)
Mar sin féin, faoi bhun an phointeora seo dírítear aird orthu gan réamhsheiceáil:
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());
Déanaimis cás eile den chineál céanna a mheas.
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(); // <=
....
}
Rabhadh PVS-Studio: V1004 [CWE-476] Úsáideadh an pointeoir 'FD' go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 3228, 3231. CGDebugInfo.cpp 3231
Tabhair aird ar an gcomhartha FD. Táim cinnte go bhfuil an fhadhb le feiceáil go soiléir agus níl aon mhíniú speisialta ag teastáil.
Agus a thuilleadh:
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()); // <=
....
}
Rabhadh PVS-Studio: V1004 [CWE-476] Úsáideadh an pointeoir 'PtrTy' go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 960, 965. InterleavedLoadCombinePass.cpp 965
Conas tú féin a chosaint ó earráidí den sórt sin? Bí níos airdeallaí ar Athbhreithniú Cód agus bain úsáid as an anailísí statach PVS-Studio chun do chód a sheiceáil go rialta.
Ní fiú blúirí cód eile a lua le hearráidí den chineál seo. Ní fhágfaidh mé ach liosta rabhaidh san alt:
- V1004 [CWE-476] Úsáideadh an pointeoir ‘Expr’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 1049, 1078. DebugInfoMetadata.cpp 1078
- V1004 [CWE-476] Úsáideadh an pointeoir ‘PI’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 733, 753. LegacyPassManager.cpp 753
- V1004 [CWE-476] Úsáideadh an pointeoir ‘StatepointCall’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 4371, 4379. Verifier.cpp 4379
- V1004 [CWE-476] Úsáideadh an pointeoir ‘RV’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 2263, 2268. TGParser.cpp 2268
- V1004 [CWE-476] Úsáideadh an pointeoir ‘CalleeFn’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 1081, 1096. SimplifyLibCalls.cpp 1096
- V1004 [CWE-476] Úsáideadh an pointeoir ‘TC’ go neamhshábháilte tar éis é a fhíorú i gcoinne nullptr. Línte seiceála: 1819, 1824. Driver.cpp 1824
Fragment N48-N60: Níl sé ríthábhachtach, ach locht (sceitheadh cuimhne féideartha)
std::unique_ptr<IRMutator> createISelMutator() {
....
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
Strategies.emplace_back(
new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
....
}
Rabhadh PVS-Studio:
Chun eilimint a chur le deireadh coimeádán cosúil le std::veicteoir > ní féidir leat scríobh go díreach xxx.push_back(X nua), ós rud é nach bhfuil aon chomhshó intuigthe ó X* в std:: uathúil_ptr.
Réiteach coitianta ná scríobh xxx.emplace_back(X nua)ó tiomsaíonn sé: modh emplace_back tógann sé eilimint go díreach óna hargóintí agus dá bhrí sin is féidir leis cruthaitheoirí follasacha a úsáid.
Níl sé sábháilte. Má tá an veicteoir lán, ansin déantar an chuimhne a ath-leithdháileadh. D’fhéadfadh go dteipfeadh ar an oibríocht ath-leithdháilte cuimhne, agus mar thoradh air sin caitear eisceacht std:: bad_alloc. Sa chás seo, caillfear an pointeoir agus ní scriosfar an réad cruthaithe choíche.
Tá réiteach sábháilte a chruthú uathúil_ptrag a mbeidh an pointeoir féin sula ndéanann an veicteoir iarracht cuimhne a athdháileadh:
xxx.push_back(std::unique_ptr<X>(new X))
Ó C++14, is féidir leat 'std::make_unique' a úsáid:
xxx.push_back(std::make_unique<X>())
Níl an cineál seo fabht ríthábhachtach do LLVM. Mura féidir cuimhne a leithdháileadh, stopfaidh an tiomsaitheoir. Mar sin féin, le haghaidh iarratas le fada
Mar sin, cé nach bhfuil an cód seo ina bhagairt phraiticiúil do LLVM, fuair mé go raibh sé úsáideach labhairt faoin bpatrún earráide seo agus gur fhoghlaim an anailísí PVS-Studio é a aithint.
Rabhadh eile den chineál seo:
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Pasanna' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. PassManager.h 546
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘AAs’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. AiliasAnail.h 324
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Iontrálacha' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. DWARFDebugFrame.cpp 519
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘AllEdges’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. CFGMST.h 268
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'VMaps' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. SimpleLoopUnswitch.cpp 2012
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘Records’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. FDRLogBuilder.h 30
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘PendingSubmodules’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. ModuleMap.cpp 810
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘Objects’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. DebugMap.cpp 88
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Straitéisí' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-isel-fuzzer.cpp 60
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 685
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 686
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 688
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 689
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 690
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 691
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 692
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 693
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Athraithe' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. llvm-strus.cpp 694
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘Operands’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. GlobalISelEmitter.cpp 1911
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán ‘Stash’ tríd an modh ‘emplace_back’. Tarlóidh sceitheadh cuimhne i gcás eisceachta. GlobalISelEmitter.cpp 2100
- V1023 [CWE-460] Cuirtear pointeoir gan úinéir leis an gcoimeádán 'Matchers' tríd an modh 'emplace_back'. Tarlóidh sceitheadh cuimhne i gcás eisceachta. GlobalISelEmitter.cpp 2702
Conclúid
D'eisigh mé 60 rabhadh san iomlán agus stop mé ansin. An bhfuil lochtanna eile ann a bhraitheann an t-anailísí PVS-Studio in LLVM? Sea, tá agam. Mar sin féin, nuair a bhí blúirí cód á scríobh agam don alt, bhí sé déanach tráthnóna, nó in áit fiú oíche, agus chinn mé go raibh sé in am é a ghlaoch in aghaidh an lae.
Tá súil agam go raibh sé suimiúil duit agus go mbeidh tú ag iarraidh triail a bhaint as an anailísí PVS-Studio.
Is féidir leat an anailíseoir a íoslódáil agus an eochair minesweeper a fháil ag
Níos tábhachtaí fós, bain úsáid as anailís statach go rialta. Seiceálacha aonuaire, a rinne muid d'fhonn an mhodheolaíocht anailís statach a popularize agus nach bhfuil PVS-Studio cás gnáth.
Ádh mór i bhfeabhsú cáilíocht agus iontaofacht do chód!
Más mian leat an t-alt seo a roinnt le lucht féachana Béarla, bain úsáid as an nasc aistriúcháin: Andrey Karpov.
Foinse: will.com