Dod o hyd i fygiau yn LLVM 8 gan ddefnyddio'r dadansoddwr PVS-Studio

Dod o hyd i fygiau yn LLVM 8 gan ddefnyddio'r dadansoddwr PVS-Studio
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 (1, 2, 3). Mae'n well ysgrifennu am rywbeth newydd, ond does gen i ddim dewis.

Bob tro mae fersiwn newydd o LLVM yn cael ei ryddhau neu ei ddiweddaru Dadansoddwr Statig Clang, rydym yn derbyn cwestiynau o'r math canlynol yn ein post:

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 Nodyn.

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:

  1. 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!
  2. Rydym yn cwblhau ac yn gwella diagnosteg bresennol. Felly, gall y dadansoddwr nodi gwallau na sylwodd arnynt yn ystod sganiau blaenorol.
  3. 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: V501 [CWE-570] Ceir is-fynegiadau unfath 'Name.startswith("avx512.mask.permvar.")' i'r chwith ac i'r dde o'r '|| gweithredydd. AutoUpgrade.cpp 73

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: V502 [CWE-783] Efallai bod y gweithredwr '?:' yn gweithio mewn ffordd wahanol i'r disgwyl. Mae gan y gweithredwr '?:' flaenoriaeth is na'r gweithredwr '=='. PPCTargetTransformInfo.cpp 404

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 blaenoriaethau gweithredwr, mae'r mynegiant yn cael ei werthuso fel a ganlyn:

(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 yma, yn y bennod “ Gochelwch rhag y ?: Gweithredwr ac Amgaewch Ef mewn Cromfachau.”

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: V522 [CWE-476] Efallai y bydd y pwyntydd null 'LHS' yn cael ei gyfeirio. TGParser.cpp 2152

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: V570 Mae'r newidyn 'Dynodwr-> Math' wedi'i neilltuo iddo'i hun. FormatTokenLexer.cpp 249

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: V622 [CWE-478] Ystyried archwilio'r datganiad 'switsh'. Mae'n bosibl bod y gweithredwr 'achos' cyntaf ar goll. SystemZAsmParser.cpp 652

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: V595 [CWE-476] Defnyddiwyd y pwyntydd 'Callee' cyn iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 172, 174. AMDGPUInline.cpp 172

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: V629 [CWE-190] Ystyriwch archwilio'r ymadrodd '~(Maint - 1) << 1'. Newid did y gwerth 32-did gydag ehangiad dilynol i'r math 64-did. AArch64AddressingModes.h 260

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: V646 [CWE-670] Ystyried archwilio rhesymeg y cais. Mae'n bosibl bod allweddair 'arall' ar goll. AMDGPUAsmParser.cpp 5655

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:

Dod o hyd i fygiau yn LLVM 8 gan ddefnyddio'r dadansoddwr PVS-Studio

Rhybudd PVS-Stiwdio: V708 [CWE-758] Defnyddir adeiladwaith peryglus: 'FeaturesMap[Op] = FeaturesMap.size()', lle mae 'FeaturesMap' o ddosbarth 'map'. Gall hyn arwain at ymddygiad heb ei ddiffinio. RISCVCCompressInstEmitter.cpp 490

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: V519 [CWE-563] Rhoddir gwerthoedd i'r newidyn 'NType' ddwywaith yn olynol. Efallai mai camgymeriad yw hwn. Llinellau gwirio: 1663, 1664. MachOObjectFile.cpp 1664

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: V547 [CWE-571] Mae'r ymadrodd 'nextByte!= 0x90' bob amser yn wir. X86DisassemblerDecoder.cpp 379

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 (V547) neu ran ohono (V560) bob amser yn wir neu'n anwir. Yn aml nid yw'r rhain yn wallau go iawn, ond yn syml cod blêr, canlyniad ehangu macro, ac ati. Fodd bynnag, mae'n gwneud synnwyr edrych ar yr holl rybuddion hyn, gan fod gwallau rhesymegol gwirioneddol yn digwydd o bryd i'w gilydd. Er enghraifft, mae'r adran hon o'r cod yn amheus:

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: V560 [CWE-570] Mae rhan o fynegiant amodol bob amser yn ffug: RegNo == 0xe. ARMDisassembler.cpp 939

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 V595, nid oedd gennyf ddiddordeb mewn astudio'r rhybuddion hyn. Roedd hi eisoes yn amlwg bod gen i ddigon o ddeunydd i ysgrifennu erthygl :). Felly, nid yw'n hysbys faint o wallau o'r math hwn y gellir eu nodi yn LLVM gan ddefnyddio PVS-Studio.

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: V612 [CWE-670] 'Dychweliad' diamod o fewn dolen. R600OptimizeVectorRegisters.cpp 63

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.

Dod o hyd i fygiau yn LLVM 8 gan ddefnyddio'r dadansoddwr PVS-Studio

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 blaenorol sieciau. Yn ystod yr amser hwn, ychwanegwyd cyfanswm o 66 diagnosteg pwrpas cyffredinol at y dadansoddwr C ++.

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: V779 [CWE-561] Cod anghyraeddadwy wedi'i ganfod. Mae'n bosibl bod gwall yn bresennol. ExecutionUtils.cpp 146

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: V784 Mae maint y mwgwd bit yn llai na maint yr operand cyntaf. Bydd hyn yn achosi colli darnau uwch. RuntimeDydd.cpp 815

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: V1028 [CWE-190] Gorlif posibl. Ystyriwch gastio operands y gweithredwr 'NumElts * Scale' i'r math 'size_t', nid y canlyniad. X86ISelLowering.h 1577

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 maint_t.

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;
  }
  ....
}

V778 [CWE-682] Darganfuwyd dau ddarn cod tebyg. Efallai, mae hwn yn deipo a dylid defnyddio newidyn 'Op1' yn lle 'Op0'. InstCombineCompares.cpp 5507

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: V1001 [CWE-563] Mae'r newidyn 'Modd' wedi'i neilltuo ond ni chaiff ei ddefnyddio erbyn diwedd y ffwythiant. SIModeRegister.cpp 48

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 V595. Ei hanfod yw bod y pwyntydd yn cael ei ddadgyfeirio ar y dechrau, a dim ond wedyn y caiff ei wirio. Diagnosteg ifanc V1004 yn y gwrthwyneb o ran ystyr, ond hefyd yn datgelu llawer o wallau. Mae'n nodi sefyllfaoedd lle cafodd y pwyntydd ei wirio ar y dechrau ac yna anghofio gwneud hynny. Gadewch i ni edrych ar achosion o'r fath a geir y tu mewn i LLVM.

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: 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 58

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 uptime, na all ddod i ben yn unig os bydd dyraniad cof yn methu, gall hyn fod yn fyg cas iawn.

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 Mae'r dudalen hon.

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!

Dod o hyd i fygiau yn LLVM 8 gan ddefnyddio'r dadansoddwr PVS-Studio

Os ydych chi am rannu'r erthygl hon â chynulleidfa Saesneg ei hiaith, defnyddiwch y ddolen gyfieithu: Andrey Karpov. Dod o Hyd i Fygiau yn LLVM 8 gyda PVS-Studio.

Ffynhonnell: hab.com

Ychwanegu sylw