Għaddew aktar minn sentejn mill-aħħar verifika tal-kodiċi tal-proġett LLVM bl-użu tal-analizzatur PVS-Studio tagħna. Ejja niżguraw li l-analizzatur PVS-Studio għadu għodda ewlenija għall-identifikazzjoni ta 'żbalji u vulnerabbiltajiet potenzjali. Biex tagħmel dan, aħna se niċċekkjaw u nsibu żbalji ġodda fir-rilaxx LLVM 8.0.0.
Artiklu li jrid jinkiteb
Biex inkun onest, ma ridtx nikteb dan l-artiklu. Mhux interessanti li tikteb dwar proġett li diġà vverifikajna diversi drabi (
Kull darba li tiġi rilaxxata jew aġġornata verżjoni ġdida ta' LLVM
Ara, il-verżjoni l-ġdida ta 'Clang Static Analyzer tgħallmet issib żbalji ġodda! Jidhirli li r-rilevanza tal-użu ta 'PVS-Studio qed tonqos. Clang isib aktar żbalji minn qabel u jlaħħaq mal-kapaċitajiet ta 'PVS-Studio. X'taħseb dwar dan?
Għal dan irrid dejjem inwieġeb xi ħaġa bħal:
Ma noqogħdux idle lanqas! Aħna tjiebna b'mod sinifikanti l-kapaċitajiet tal-analizzatur PVS-Studio. Mela tinkwetax, inkomplu mmexxu bħal qabel.
Sfortunatament, din hija tweġiba ħażina. M'hemm l-ebda provi fiha. U għalhekk qed nikteb dan l-artiklu issa. Għalhekk, il-proġett LLVM għal darb'oħra ġie ċċekkjat u nstabu varjetà ta 'żbalji fih. Issa se nuri dawk li dehru interessanti għalija. Clang Static Analyzer ma jistax isib dawn l-iżbalji (jew huwa estremament inkonvenjenti li tagħmel dan bl-għajnuna tiegħu). Imma nistgħu. Barra minn hekk, sibt u ktibt dawn l-iżbalji kollha f'lejla waħda.
Iżda l-kitba tal-artiklu ħadet diversi ġimgħat. Sempliċement ma stajtx inġib ruħi biex inpoġġi dan kollu fit-test :).
Mill-mod, jekk inti interessat f'liema teknoloġiji jintużaw fl-analizzatur PVS-Studio biex tidentifika żbalji u vulnerabbiltajiet potenzjali, allura nissuġġerixxi li tiffamiljarizza ma' dan
Dijanjostiċi ġodda u qodma
Kif diġà nnutat, madwar sentejn ilu l-proġett LLVM reġa’ ġie ċċekkjat, u l-iżbalji misjuba ġew ikkoreġuti. Issa dan l-artikolu se jippreżenta lott ġdid ta 'żbalji. Għaliex instabu bugs ġodda? Hemm 3 raġunijiet għal dan:
- Il-proġett LLVM qed jevolvi, ibiddel kodiċi antik u jżid kodiċi ġdid. Naturalment, hemm żbalji ġodda fil-kodiċi modifikat u miktub. Dan juri biċ-ċar li l-analiżi statika għandha tintuża regolarment, u mhux okkażjonalment. L-artikoli tagħna juru tajjeb il-kapaċitajiet tal-analizzatur PVS-Studio, iżda dan m'għandu x'jaqsam xejn mat-titjib tal-kwalità tal-kodiċi u t-tnaqqis tal-ispiża tal-iffissar tal-iżbalji. Uża analizzatur tal-kodiċi statiku regolarment!
- Qed nifinalizzaw u ntejbu d-dijanjostiċi eżistenti. Għalhekk, l-analizzatur jista 'jidentifika żbalji li ma ndunax waqt skans preċedenti.
- F'PVS-Studio dehru dijanjostiċi ġodda li ma kinux jeżistu sentejn ilu. Iddeċidejt li nenfasizzahom f'sezzjoni separata biex nuri b'mod ċar l-iżvilupp ta 'PVS-Studio.
Difetti identifikati minn dijanjostiċi li kienu jeżistu sentejn ilu
Framment N1: Ikkopja-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
....
}
Twissija PVS-Studio:
Huwa ċċekkjat darbtejn li l-isem jibda bis-substring "avx512.mask.permvar.". Fit-tieni kontroll, ovvjament riedu jiktbu xi ħaġa oħra, iżda nesa jikkoreġu t-test ikkupjat.
Framment 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;
....
}
Twissija PVS-Studio: V501 Hemm subespressjonijiet identiċi 'CXNameRange_WantQualifier' fuq ix-xellug u fuq il-lemin tal-'|' operatur. CIndex.cpp 7245
Minħabba typo, l-istess kostanti msemmija tintuża darbtejn CXNameRange_WantQualifier.
Framment N3: Konfużjoni mal-preċedenza tal-operatur
int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
....
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
return 0;
....
}
Twissija PVS-Studio:
Fl-opinjoni tiegħi, dan huwa żball sabiħ ħafna. Iva, naf li għandi ideat strambi dwar is-sbuħija :).
Issa, skond
(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0
Mil-lat prattiku, kundizzjoni bħal din ma tagħmilx sens, peress li tista 'titnaqqas għal:
(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())
Dan huwa żball ċar. Ħafna probabbli, riedu jqabblu 0/1 ma 'varjabbli indiċi. Biex tiffissa l-kodiċi trid iżżid parentesi madwar l-operatur ternarju:
if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))
Mill-mod, l-operatur ternarju huwa perikoluż ħafna u jipprovoka żbalji loġiċi. Oqgħod attent ħafna magħha u ma tkun greedy bil-parentesi. Ħarist lejn dan is-suġġett f'aktar dettall
Framment N4, N5: Pointer 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;
}
....
}
Twissija PVS-Studio:
Jekk il-pointer LHS hija nulla, għandha tinħareġ twissija. Madankollu, minflok, dan l-istess pointer null se jiġi dereferenced: LHS->getAsString().
Din hija sitwazzjoni tipika ħafna meta żball ikun moħbi f'handler, peress li ħadd ma jittestjahom. L-analizzaturi statiċi jiċċekkjaw il-kodiċi kollu li jista' jintlaħaq, irrispettivament minn kemm jintuża. Dan huwa eżempju tajjeb ħafna ta 'kif l-analiżi statika tikkumplimenta tekniki oħra ta' ttestjar u protezzjoni ta 'żbalji.
Żball simili fl-immaniġġjar tal-pointer RHS permess fil-kodiċi eżatt taħt: V522 [CWE-476] Jista' jseħħ dereferencing tal-pointer null 'RHS'. TGParser.cpp 2186
Framment N6: Uża l-pointer wara li tiċċaqlaq
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);
}
....
}
Twissija ta' PVS-Studio: V522 [CWE-476] Jista' jsir dereferencing tal-pointer null 'ProgClone'. Miscompilation.cpp 601
Fil-bidu pointer intelliġenti ProgClone ma jibqax jippossjedi l-oġġett:
BD.setNewProgram(std::move(ProgClone));
Fil-fatt, issa ProgClone huwa pointer null. Għalhekk, dereferenza null pointer għandha sseħħ eżatt taħt:
Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);
Iżda, fir-realtà, dan mhux se jiġri! Innota li l-linja mhix attwalment eżegwita.
Fil-bidu tal-kontenitur Funzjonijiet Kompilati Ħażin approvat:
MiscompiledFunctions.clear();
Sussegwentement, id-daqs ta 'dan il-kontenitur jintuża fil-kondizzjoni tal-linja:
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {
Huwa faċli li tara li l-linja ma tibda. Naħseb li dan huwa wkoll bug u l-kodiċi għandu jinkiteb b'mod differenti.
Jidher li ltqajna ma' dik il-famuża parità ta' żbalji! Żball wieħed jaħbi ieħor :).
Framment N7: Uża l-pointer wara li tiċċaqlaq
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;
}
....
}
Twissija ta' PVS-Studio: V522 [CWE-476] Jista' jsir dereferencing tal-pointer null 'Test'. Miscompilation.cpp 709
L-istess sitwazzjoni mill-ġdid. Għall-ewwel, il-kontenut tal-oġġett jitmexxa, u mbagħad jintuża bħallikieku ma ġara xejn. Nara din is-sitwazzjoni aktar u aktar spiss fil-kodiċi tal-programm wara li s-semantika tal-moviment dehret f'C++. Dan huwa għaliex inħobb il-lingwa C++! Hemm aktar u aktar modi ġodda biex tispara riġel tiegħek stess. L-analizzatur PVS-Studio dejjem ikollu xogħol :).
Framment N8: Pointer 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);
}
Twissija ta' PVS-Studio: V522 [CWE-476] Jista' jsir dereferencing tal-pointer null 'Tip'. PrettyFunctionDumper.cpp 233
Minbarra li jimmaniġġjaw l-iżbalji, il-funzjonijiet tal-istampar tad-debugging normalment ma jiġux ittestjati. Għandna biss każ bħal dan quddiemna. Il-funzjoni qed tistenna lill-utent, li, minflok isolvi l-problemi tiegħu, se jkun sfurzat jirranġaha.
B'mod korrett:
if (Type)
Type->dump(*this);
else
Printer << "<unknown-type>";
Framment N9: Pointer 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());
....
}
Twissija ta' PVS-Studio: V522 [CWE-476] Jista' jsir dereferencing tal-pointer null 'Ty'. SearchableTableEmitter.cpp 614
Naħseb li kollox huwa ċar u ma jeħtieġx spjegazzjoni.
Framment 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;
}
Twissija PVS-Studio:
M'hemm l-ebda punt li tassenja varjabbli għaliha nnifisha. X'aktarx li riedu jiktbu:
Identifier->Type = Question->Type;
Framment N11: Tkissir suspettuż
void SystemZOperand::print(raw_ostream &OS) const {
switch (Kind) {
break;
case KindToken:
OS << "Token:" << getToken();
break;
case KindReg:
OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
break;
....
}
Twissija PVS-Studio:
Fil-bidu hemm operatur suspettuż ħafna break. Insejt tikteb xi ħaġa oħra hawn?
Framment N12: Iċċekkjar pointer wara dereferencing
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");
....
}
Twissija PVS-Studio:
Pointer Callee fil-bidu hija dereferenced fil-ħin li tissejjaħ il-funzjoni getTTI.
U mbagħad jirriżulta li dan il-pointer għandu jiġi ċċekkjat għall-ugwaljanza nullptr:
if (!Callee || Callee->isDeclaration())
Imma huwa tard wisq...
Framment N13 - N...: Iċċekkjar pointer wara dereferencing
Is-sitwazzjoni diskussa fil-framment tal-kodiċi preċedenti mhijiex unika. Jidher hawn:
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()) { // <=
....
}
Twissija PVS-Studio: V595 [CWE-476] Il-pointer 'CalleeFn' ġie utilizzat qabel ma ġie vverifikat kontra nullptr. Iċċekkja l-linji: 1079, 1081. SimplifyLibCalls.cpp 1079
U hawn:
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()); // <=
....
}
Twissija PVS-Studio: V595 [CWE-476] Il-pointer 'ND' intuża qabel ma ġie vverifikat kontra nullptr. Iċċekkja linji: 532, 534. SemaTemplateInstantiateDecl.cpp 532
U hawn:
- V595 [CWE-476] Il-pointer 'U' ġie utilizzat qabel ma ġie vverifikat kontra nullptr. Iċċekkja linji: 404, 407. DWARFormValue.cpp 404
- V595 [CWE-476] Il-pointer 'ND' ġie utilizzat qabel ma ġie vverifikat kontra nullptr. Iċċekkja linji: 2149, 2151. SemaTemplateInstantiate.cpp 2149
U mbagħad sirt mhux interessat li nistudja t-twissijiet bin-numru V595. Allura ma nafx jekk hemmx aktar żbalji simili minbarra dawk elenkati hawn. Ħafna probabbli hemm.
Framment N17, N18: Ċaqliq suspettuż
static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
uint64_t &Encoding) {
....
unsigned Size = RegSize;
....
uint64_t NImms = ~(Size-1) << 1;
....
}
Twissija PVS-Studio:
Jista 'ma jkunx bug u l-kodiċi jaħdem eżatt kif maħsub. Iżda dan huwa ċar post suspettuż ħafna u jeħtieġ li jiġi ċċekkjat.
Ejja ngħidu l-varjabbli daqs huwa ugwali għal 16, u mbagħad l-awtur tal-kodiċi ppjanat li ġġibu f'varjabbli NImms valur:
1111111111111111111111111111111111111111111111111111111111100000
Madankollu, fir-realtà r-riżultat se jkun:
0000000000000000000000000000000011111111111111111111111111100000
Il-fatt hu li l-kalkoli kollha jseħħu bl-użu tat-tip 32-bit mhux iffirmat. U allura biss, dan it-tip mhux iffirmat ta '32 bit se jiġi estiż impliċitament għal uint64_t. F'dan il-każ, l-aktar bits sinifikanti se jkunu żero.
Tista' tirranġa s-sitwazzjoni bħal din:
uint64_t NImms = ~static_cast<uint64_t>(Size-1) << 1;
Sitwazzjoni simili: V629 [CWE-190] Ikkunsidra li tispezzjona l-espressjoni 'Immr << 6'. Ċaqliq tal-bit tal-valur 32-bit b'espansjoni sussegwenti għat-tip 64-bit. AArch64AddressingModes.h 269
Framment N19: kelma prinċipali nieqsa inkella?
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");
}
....
}
Twissija PVS-Studio:
M'hemm l-ebda żball hawn. Peress li dak iż-żmien-blokk tal-ewwel if jispiċċa bi tkompli, allura ma jimpurtax, hemm kelma prinċipali inkella jew le. Jew il-mod il-kodiċi se jaħdem l-istess. Xorta mitlufa inkella jagħmel il-kodiċi aktar mhux ċar u perikoluż. Jekk fil-futur tkompli tisparixxi, il-kodiċi se jibda jaħdem b'mod kompletament differenti. Fl-opinjoni tiegħi huwa aħjar li żżid inkella.
Framment N20: Erba' typos tal-istess tip
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;
}
Twissijiet ta' PVS-Studio:
- V655 [CWE-480] Il-kordi kienu magħqudin iżda ma jintużawx. Ikkunsidra li tispezzjona l-espressjoni 'Riżultat + Isem.str()'. Simbolu.cpp 32
- V655 [CWE-480] Il-kordi kienu magħqudin iżda ma jintużawx. Ikkunsidra li tispezzjona l-espressjoni 'Riżultat + "(Klassi ObjC)" + Isem.str()'. Simbolu.cpp 35
- V655 [CWE-480] Il-kordi kienu magħqudin iżda ma jintużawx. Ikkunsidra li tispezzjona l-espressjoni 'Riżultat + "(Klassi ObjC EH)" + Isem.str()'. Simbolu.cpp 38
- V655 [CWE-480] Il-kordi kienu magħqudin iżda ma jintużawx. Ikkunsidra li tispezzjona l-espressjoni 'Riżultat + "(ObjC IVar)" + Isem.str()'. Simbolu.cpp 41
B'inċident, l-operatur + jintuża minflok l-operatur +=. Ir-riżultat huwa disinji li huma nieqsa minn tifsira.
Framment N21: Imġieba mhux definita
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();
}
}
}
Ipprova sib il-kodiċi perikoluż lilek innifsek. U din hija stampa biex tfixkel l-attenzjoni sabiex ma tħaresx immedjatament lejn it-tweġiba:
Twissija PVS-Studio:
Linja tal-problema:
FeaturesMap[Op] = FeaturesMap.size();
Jekk element Op ma jinstabx, allura jinħoloq element ġdid fil-mappa u n-numru ta' elementi f'din il-mappa jinkiteb hemm. Mhux magħruf jekk il-funzjoni se tissejjaħ daqs qabel jew wara li żżid element ġdid.
Framment N22-N24: Assenjazzjonijiet ripetuti
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;
}
....
}
Twissija PVS-Studio:
Ma naħsibx li hawn żball reali. Biss assenjazzjoni ripetuta bla bżonn. Iżda xorta waħda taħwid.
Bl-istess mod:
- V519 [CWE-563] Il-varjabbli 'B.NDesc' hija assenjata valuri darbtejn suċċessivament. Forsi dan huwa żball. Iċċekkja linji: 1488, 1489. llvm-nm.cpp 1489
- V519 [CWE-563] Il-varjabbli hija assenjata valuri darbtejn suċċessivament. Forsi dan huwa żball. Iċċekkja linji: 59, 61. coff2yaml.cpp 61
Framment N25-N27: Aktar assenjazzjonijiet mill-ġdid
Issa ejja nħarsu lejn verżjoni kemmxejn differenti ta 'assenjazzjoni mill-ġdid.
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;
....
}
Twissija PVS-Studio: V519 [CWE-563] Il-varjabbli 'Allinjament' hija assenjata valuri darbtejn suċċessivament. Forsi dan huwa żball. Iċċekkja l-linji: 1158, 1160. LoadStoreVectorizer.cpp 1160
Dan huwa kodiċi stramb ħafna li jidher li fih żball loġiku. Fil-bidu, varjabbli Allinjament jiġi assenjat valur skont il-kundizzjoni. U mbagħad l-inkarigu jerġa' jseħħ, iżda issa mingħajr ebda kontroll.
Sitwazzjonijiet simili jistgħu jidhru hawn:
- V519 [CWE-563] Il-varjabbli 'Effetti' hija assenjata valuri darbtejn suċċessivament. Forsi dan huwa żball. Iċċekkja linji: 152, 165. WebAssemblyRegStackify.cpp 165
- V519 [CWE-563] Il-varjabbli 'ExpectNoDerefChunk' hija assenjata valuri darbtejn suċċessivament. Forsi dan huwa żball. Iċċekkja linji: 4970, 4973. SemaType.cpp 4973
Framment N28: Dejjem kundizzjoni vera
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;
}
....
}
Twissija PVS-Studio:
Iċċekkjar ma jagħmilx sens. Varjabbli nextByte dejjem mhux ugwali għall-valur 0x90, li ġej mill-verifika preċedenti. Dan huwa xi tip ta 'żball loġiku.
Framment N29 - N...: Kundizzjonijiet dejjem veri/foloz
L-analizzatur joħroġ ħafna twissijiet li l-kundizzjoni kollha (
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;
....
}
Twissija PVS-Studio:
Il-kostanti 0xE huwa l-valur 14 f'deċimali. Eżami RegNo == 0xe ma jagħmilx sens għax jekk RegNo > 13, allura l-funzjoni se tlesti l-eżekuzzjoni tagħha.
Kien hemm ħafna twissijiet oħra bl-IDs V547 u V560, iżda bħal ma
Nagħtik eżempju ta 'għaliex l-istudju ta' dawn il-kawżi huwa boring. L-analizzatur għandu raġun assolut meta joħroġ twissija għall-kodiċi li ġej. Iżda dan mhuwiex żball.
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
tok::TokenKind ClosingBraceKind) {
bool HasError = false;
....
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
....
}
Twissija PVS-Studio: V547 [CWE-570] L-espressjoni '!HasError' hija dejjem falza. UnwrappedLineParser.cpp 1635
Framment N30: Ritorn suspettuż
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();
}
....
}
Twissija PVS-Studio:
Dan huwa jew żball jew teknika speċifika li hija maħsuba biex tispjega xi ħaġa lill-programmaturi li jaqraw il-kodiċi. Dan id-disinn ma jispjegali xejn u jidher suspettuż ħafna. Aħjar ma tiktebx hekk :).
Għajjien? Imbagħad wasal iż-żmien li tagħmel it-te jew il-kafè.
Difetti identifikati minn dijanjostiċi ġodda
Naħseb li 30 attivazzjoni ta 'dijanjostika antika hija biżżejjed. Ejja issa naraw x'affarijiet interessanti jistgħu jinstabu bid-dijanjostiċi l-ġodda li dehru fl-analizzatur wara
Framment N31: Kodiċi ma jistax jintlaħaq
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();
}
Twissija PVS-Studio:
Kif tistgħu taraw, iż-żewġ fergħat tal-operatur if jispiċċa b'sejħa lill-operatur ritorn. Għaldaqstant, il-kontenitur CtorDtorsByPriority qatt mhu se jkun ikklerjat.
Framment N32: Kodiċi ma jistax jintlaħaq
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;
}
Twissija ta' PVS-Studio: V779 [CWE-561] Kodiċi li ma jintlaħaqx. Huwa possibbli li jkun hemm żball. LLParser.cpp 835
Sitwazzjoni interessanti. Ejja nħarsu lejn dan il-post l-ewwel:
return ParseTypeIdEntry(SummaryID);
break;
L-ewwel daqqa t'għajn, jidher li m'hemm l-ebda żball hawnhekk. Jidher bħall-operatur break hemm waħda żejda hawn, u tista 'sempliċement tħassarha. Madankollu, mhux kollha daqshekk sempliċi.
L-analizzatur joħroġ twissija fuq il-linji:
Lex.setIgnoreColonInIdentifiers(false);
return false;
U tabilħaqq, dan il-kodiċi ma jistax jintlaħaq. Il-każijiet kollha fil jaqilbu jispiċċa b'sejħa mill-operatur ritorn. U issa bla sens waħdu break ma tidhirx daqshekk bla ħsara! Forsi waħda mill-fergħat għandha tispiċċa bi break, mhux mixgħul ritorn?
Framment N33: Reset bl-addoċċ ta 'bits għoljin
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);
....
}
Twissija PVS-Studio:
Jekk jogħġbok innota li l-funzjoni getStubAlignment tip prospetti mhux iffirmat. Ejja nikkalkulaw il-valur tal-espressjoni, billi nassumu li l-funzjoni tirritorna l-valur 8:
~(getStubAlignment() - 1)
~(8u-1)
0xFFFFFFFF8u
Issa avviż li l-varjabbli DataSize għandu tip mhux iffirmat ta' 64 bit. Jirriżulta li meta twettaq l-operazzjoni DataSize & 0xFFFFFFF8u, tnejn u tletin bit ta 'ordni għolja se jiġu reset għal żero. Ħafna probabbli, dan mhuwiex dak li ried il-programmatur. Nissuspetta li ried jikkalkula: DataSize & 0xFFFFFFFFFFFFFFF8u.
Biex tirranġa l-iżball, għandek tikteb dan:
DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1);
Jew hekk:
DataSize &= ~(getStubAlignment() - 1ULL);
Framment N34: mitfugħa tat-tip espliċitu fallut
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);
....
}
Twissija PVS-Studio:
L-ikkastjar tat-tip espliċitu jintuża biex jevita l-overflow meta timmultiplika varjabbli tat-tip int. Madankollu, ikkastjar tat-tip espliċitu hawnhekk ma jipproteġix kontra l-overflow. L-ewwel, il-varjabbli se jiġu mmultiplikati, u mbagħad biss ir-riżultat ta '32-bit tal-multiplikazzjoni se jiġi estiż għat-tip
Framment N35: Ikkopja-Paste falliet
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;
}
....
}
Din id-dijanjostika interessanti ġdida tidentifika sitwazzjonijiet fejn biċċa kodiċi ġiet ikkupjata u xi ismijiet fiha bdew jinbidlu, iżda f'post wieħed ma kkoreġuhiex.
Jekk jogħġbok innota li fit-tieni blokk inbidlu Op0 fuq Op1. Iżda f'post wieħed ma rranġawhx. Aktarx li kellu jinkiteb hekk:
if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
return &I;
}
Framment N36: Konfużjoni Varjabbli
struct Status {
unsigned Mask;
unsigned Mode;
Status() : Mask(0), Mode(0){};
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
Mode &= Mask;
};
....
};
Twissija PVS-Studio:
Huwa perikoluż ħafna li l-argumenti tal-funzjoni jingħataw l-istess ismijiet bħall-membri tal-klassi. Huwa faċli ħafna li titħawwad. Għandna biss każ bħal dan quddiemna. Din l-espressjoni ma tagħmilx sens:
Mode &= Mask;
L-argument tal-funzjoni jinbidel. Dak kollox. Dan l-argument m'għadux jintuża. X'aktarx kellek ktibtu hekk:
Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
this->Mode &= Mask;
};
Framment N37: Konfużjoni Varjabbli
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;
}
Twissija PVS-Studio: V1001 [CWE-563] Il-varjabbli 'Daqs' hija assenjata iżda ma tintużax sa tmiem il-funzjoni. Oġġett.cpp 424
Is-sitwazzjoni hija simili għal dik preċedenti. Għandu jinkiteb:
this->Size += this->EntrySize;
Framment N38-N47: Insew jiċċekkjaw l-indiċi
Preċedentement, ħares lejn eżempji ta 'attivazzjoni dijanjostika
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()); // <=
....
}
Twissija PVS-Studio: V1004 [CWE-476] Il-pointer 'Ptr' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 729, 738. TargetTransformInfoImpl.h 738
Varjabbli ptr jistgħu jkunu ugwali nullptr, kif muri mill-kontroll:
if (Ptr != nullptr)
Madankollu, taħt dan il-pointer huwa dereferenced mingħajr verifika preliminari:
auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());
Ejja nikkunsidraw każ ieħor simili.
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(); // <=
....
}
Twissija PVS-Studio: V1004 [CWE-476] Il-pointer 'FD' intuża b'mod mhux sigur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 3228, 3231. CGDebugInfo.cpp 3231
Oqgħod attent għas-sinjal FD. Jiena ċert li l-problema hija viżibbli b'mod ċar u mhi meħtieġa l-ebda spjegazzjoni speċjali.
U aktar:
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()); // <=
....
}
Twissija PVS-Studio: V1004 [CWE-476] Il-pointer 'PtrTy' intuża b'mod mhux sigur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 960, 965. InterleavedLoadCombinePass.cpp 965
Kif tipproteġi lilek innifsek minn żbalji bħal dawn? Kun aktar attent fuq Code-Review u uża l-analizzatur statiku PVS-Studio biex tiċċekkja regolarment il-kodiċi tiegħek.
M'hemm l-ebda skop li tiċċita frammenti oħra ta 'kodiċi bi żbalji ta' dan it-tip. Se nħalli biss lista ta 'twissijiet fl-artiklu:
- V1004 [CWE-476] Il-pointer 'Expr' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja l-linji: 1049, 1078. DebugInfoMetadata.cpp 1078
- V1004 [CWE-476] Il-pointer 'PI' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja l-linji: 733, 753. LegacyPassManager.cpp 753
- V1004 [CWE-476] Il-pointer 'StatepointCall' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 4371, 4379. Verifier.cpp 4379
- V1004 [CWE-476] Il-pointer 'RV' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 2263, 2268. TGParser.cpp 2268
- V1004 [CWE-476] Il-pointer 'CalleeFn' intuża b'mod mhux sigur wara li ġie vverifikat kontra nullptr. Iċċekkja l-linji: 1081, 1096. SimplifyLibCalls.cpp 1096
- V1004 [CWE-476] Il-pointer 'TC' intuża b'mod mhux sikur wara li ġie vverifikat kontra nullptr. Iċċekkja linji: 1819, 1824. Driver.cpp 1824
Framment N48-N60: Mhux kritiku, iżda difett (tnixxija possibbli tal-memorja)
std::unique_ptr<IRMutator> createISelMutator() {
....
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
Strategies.emplace_back(
new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
....
}
Twissija PVS-Studio:
Biex iżżid element fit-tarf ta 'kontenitur simili std::vector > ma tistax tikteb biss xxx.push_back (X ġdid), peress li m'hemm l-ebda konverżjoni impliċita minn X* в std::unique_ptr.
Soluzzjoni komuni hija li tikteb xxx.emplace_back(X ġdid)peress li jikkompila: metodu emplace_back jibni element direttament minn argumenti u għalhekk jista' juża kostrutturi espliċiti.
Mhuwiex sigur. Jekk il-vettur ikun mimli, allura l-memorja tiġi allokata mill-ġdid. L-operazzjoni ta' allokazzjoni mill-ġdid tal-memorja tista' tfalli, li tirriżulta f'eċċezzjoni li tintefa' std::bad_alloc. F'dan il-każ, il-pointer jintilef u l-oġġett maħluq qatt mhu se jitħassar.
Soluzzjoni sigura hija li toħloq unique_ptrli se jippossjedi l-pointer qabel ma l-vettur jipprova jalloka mill-ġdid il-memorja:
xxx.push_back(std::unique_ptr<X>(new X))
Minn C++14, tista' tuża 'std::make_unique':
xxx.push_back(std::make_unique<X>())
Dan it-tip ta' difett mhuwiex kritiku għal LLVM. Jekk il-memorja ma tistax tiġi allokata, il-kompilatur sempliċement jieqaf. Madankollu, għal applikazzjonijiet b'tul
Għalhekk, għalkemm dan il-kodiċi ma joħloqx theddida prattika għal LLVM, sibt utli li nitkellem dwar dan il-mudell ta 'żball u li l-analizzatur PVS-Studio tgħallem jidentifikah.
Twissijiet oħra ta’ dan it-tip:
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Passes' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. PassManager.h 546
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'AAs' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. AliasAnalysis.h 324
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Entries' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. DWARFDebugFrame.cpp 519
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'AllEdges' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. CFGMST.h 268
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'VMaps' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. SimpleLoopUnswitch.cpp 2012
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Records' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. FDRLogBuilder.h 30
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'PendingSubmodules' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. ModuleMap.cpp 810
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Oġġetti' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. DebugMap.cpp 88
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Istrateġiji' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-isel-fuzzer.cpp 60
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 685
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 686
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 688
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 689
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 690
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 691
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 692
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 693
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Modifikaturi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. llvm-stress.cpp 694
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Operandi' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. GlobalISelEmitter.cpp 1911
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Stash' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. GlobalISelEmitter.cpp 2100
- V1023 [CWE-460] Pointer mingħajr sid huwa miżjud mal-kontenitur 'Matchers' bil-metodu 'emplace_back'. Tnixxija tal-memorja se sseħħ f'każ ta 'eċċezzjoni. GlobalISelEmitter.cpp 2702
Konklużjoni
Ħarġejt 60 twissija b’kollox u mbagħad waqaft. Hemm difetti oħra li l-analizzatur PVS-Studio jiskopri fl-LLVM? Iva għandi. Madankollu, meta kont qed nikteb frammenti tal-kodiċi għall-artiklu, kien tard filgħaxija, jew aħjar anke bil-lejl, u ddeċidejt li kien wasal iż-żmien li nsejħilha kuljum.
Nispera li sibtha interessanti u tkun trid tipprova l-analizzatur PVS-Studio.
Tista 'tniżżel l-analizzatur u tikseb iċ-ċavetta tal-minjieri fuq
L-aktar importanti, uża analiżi statika regolarment. Kontrolli ta' darba, imwettqa minna sabiex popolarizzaw il-metodoloġija ta 'analiżi statika u PVS-Studio mhumiex xenarju normali.
Xorti tajba fit-titjib tal-kwalità u l-affidabbiltà tal-kodiċi tiegħek!
Jekk trid taqsam dan l-artikolu ma 'udjenza li titkellem bl-Ingliż, jekk jogħġbok uża l-link tat-traduzzjoni: Andrey Karpov.
Sors: www.habr.com