Ҷустуҷӯи хатогиҳо дар LLVM 8 бо истифода аз таҳлилгари PVS-Studio

Ҷустуҷӯи хатогиҳо дар LLVM 8 бо истифода аз таҳлилгари PVS-Studio
Зиёда аз ду сол аз санҷиши охирини коди лоиҳаи LLVM бо истифода аз таҳлилгари PVS-Studio мо гузашт. Биёед боварӣ ҳосил кунем, ки таҳлилгари PVS-Studio то ҳол як воситаи пешбари муайян кардани хатогиҳо ва осебпазирии эҳтимолӣ мебошад. Барои ин, мо хатогиҳои навро дар версияи LLVM 8.0.0 тафтиш ва пайдо хоҳем кард.

Мақола бояд навишта шавад

Рости гап, ман ин мақоларо навиштан намехостам. Навиштан дар бораи лоиҳае ҷолиб нест, ки мо аллакай якчанд маротиба тафтиш кардаем (1, 2, 3). Дар бораи чизи нав навиштан беҳтар аст, аммо илоҷе надорам.

Ҳар дафъае, ки версияи нави LLVM бароварда мешавад ё нав карда мешавад Clang таҳлилгари статикӣ, мо дар почтаи худ саволҳои зеринро мегирем:

Инак, версияи нави Clang Static Analyzer пайдо кардани хатогиҳои навро омӯхтааст! Ба назари ман, аҳамияти истифодаи PVS-Studio кам мешавад. Clang нисбат ба пештара хатогиҳои бештар пайдо мекунад ва ба имкониятҳои PVS-Studio мувофиқат мекунад. Шумо дар ин бора чӣ фикр доред?

Ба ин ман ҳамеша мехоҳам ба чизе ҷавоб диҳам:

Мо хам бекор намешинем! Мо имкониятҳои анализатори PVS-Studio-ро хеле беҳтар кардем. Пас хавотир нашавед, мо мисли пештара роҳбариро идома медиҳем.

Мутаассифона, ин ҷавоби бад аст. Дар он ҳеҷ далеле вуҷуд надорад. Ва барои ҳамин ҳоло ин мақоларо менависам. Ҳамин тариқ, лоиҳаи LLVM бори дигар санҷида шуд ва дар он хатогиҳои гуногун пайдо шуданд. Ҳоло ман он чизҳоеро, ки ба ман ҷолиб буданд, нишон медиҳам. Clang Static Analyzer ин хатогиҳоро ёфта наметавонад (ё бо ёрии он кор кардан бениҳоят нороҳат аст). Вале мо метавонем. Гузашта аз ин, дар як шом ҳамаи ин хатогиҳоро ёфта навиштам.

Аммо навиштани мақола чанд ҳафта тӯл кашид. Ман наметавонистам, ки ин ҳамаро ба матн гузорам :).

Дар омади гап, агар шумо ба он таваҷҷӯҳ дошта бошед, ки кадом технологияҳо дар таҳлилгари PVS-Studio барои муайян кардани хатогиҳо ва осебпазириҳои эҳтимолӣ истифода мешаванд, ман тавсия медиҳам, ки бо ин шинос шавед. Шарҳ.

Диагностикаи нав ва кӯҳна

Тавре ки аллакай зикр гардид, тақрибан ду сол пеш лоиҳаи LLVM бори дигар санҷида шуд ва хатогиҳои ошкоршуда ислоҳ карда шуданд. Ҳоло ин мақола маҷмӯи нави хатогиҳоро пешниҳод мекунад. Чаро хатогиҳои нав пайдо шуданд? Ин 3 сабаб дорад:

  1. Лоиҳаи LLVM инкишоф меёбад, рамзи кӯҳнаро иваз мекунад ва рамзи навро илова мекунад. Табиист, ки дар коди таѓйирёфта ва навишташуда хатоњои нав ба назар мерасанд. Ин ба таври возеҳ нишон медиҳад, ки таҳлили статикӣ бояд мунтазам истифода шавад, на баъзан. Мақолаҳои мо имкониятҳои анализатори PVS-Studio-ро хуб нишон медиҳанд, аммо ин ба беҳтар кардани сифати код ва кам кардани хароҷоти ислоҳи хатогиҳо ҳеҷ иртиботе надорад. Аз таҳлилгари рамзи статикӣ мунтазам истифода баред!
  2. Мо ташхиси мавҷударо ба анҷом мерасонем ва такмил медиҳем. Аз ин рӯ, анализатор метавонад хатогиҳоеро муайян кунад, ки ҳангоми сканҳои қаблӣ пай набурдааст.
  3. Дар PVS-Studio ташхиси нав пайдо шуд, ки 2 сол пеш вуҷуд надошт. Ман тасмим гирифтам, ки онҳоро дар як бахши алоҳида нишон диҳам, то рушди PVS-Studio равшан нишон дода шавад.

Камбудиҳое, ки 2 сол пеш вуҷуд доштанд, бо ташхис муайян карда шуданд

Фрагмент N1: Нусхабардорӣ-Чавондан

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

Огоҳии PVS-Studio: V501 [CWE-570] Зер ифодаҳои якхела 'Name.startswith("avx512.mask.permvar.")' дар чап ва рости '||' мавҷуданд. оператор. AutoUpgrade.cpp 73

Ду маротиба тафтиш карда мешавад, ки ном бо зерсатри "avx512.mask.permvar." оғоз мешавад. Дар тафтиши дуюм онхо аз афташ чизи дигаре навиштан мехостанд, вале ислохи матни нусхабардориро фаромуш кардаанд.

Фрагмент N2: Хатогӣ

enum CXNameRefFlags {
  CXNameRange_WantQualifier = 0x1,
  CXNameRange_WantTemplateArgs = 0x2,
  CXNameRange_WantSinglePiece = 0x4
};

void AnnotateTokensWorker::HandlePostPonedChildCursor(
    CXCursor Cursor, unsigned StartTokenIndex) {
  const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier;
  ....
}

Огоҳӣ PVS-Studio: V501 Зер ифодаҳои якхела 'CXNameRange_WantQualifier' дар чап ва рости '|' мавҷуданд. оператор. Cindex.cpp 7245

Аз сабаби хатогии хаттӣ, ҳамон доимии номбаршуда ду маротиба истифода мешавад CXNameRange_WantQualifier.

Фрагмент N3: Нофаҳмиҳо бо афзалияти оператор

int PPCTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
  ....
  if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian() ? 1 : 0)
    return 0;
  ....
}

Огоҳии PVS-Studio: V502 [CWE-783] Шояд оператори '?:' ба тарзи дигар аз он ки интизор мерафт, кор мекунад. Оператори '?:' нисбат ба оператори '==' афзалияти камтар дорад. PPCTargetTransformInfo.cpp 404

Ба назари ман, ин хатои хеле зебост. Бале, ман медонам, ки ман дар бораи зебоӣ ақидаҳои аҷибе дорам :).

Холо, мувофики афзалиятҳои оператор, ифода ба таври зерин арзёбӣ мешавад:

(ISD == ISD::EXTRACT_VECTOR_ELT && (Index == ST->isLittleEndian())) ? 1 : 0

Аз нуқтаи назари амалӣ, чунин шарт маъно надорад, зеро он метавонад ба:

(ISD == ISD::EXTRACT_VECTOR_ELT && Index == ST->isLittleEndian())

Ин хатои равшан аст. Эҳтимол, онҳо мехостанд 0/1-ро бо тағирёбанда муқоиса кунанд Индекс. Барои ислоҳ кардани код ба шумо лозим аст, ки дар атрофи оператори сегона қавс илова кунед:

if (ISD == ISD::EXTRACT_VECTOR_ELT && Index == (ST->isLittleEndian() ? 1 : 0))

Воқеан, оператори сегона хеле хатарнок аст ва хатогиҳои мантиқӣ ба вуҷуд меорад. Бо он хеле эҳтиёткор бошед ва бо қавс тамаъ накунед. Ман ин мавзӯъро муфассалтар дидам дар ин ҷо, дар боби "Аз ?: Оператор эҳтиёт шавед ва онро ба қавс дохил кунед."

Фрагмент N4, N5: Нишондиҳандаи нул

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

Огоҳии PVS-Studio: V522 [CWE-476] Барқарор кардани ишораи нул 'LHS' метавонад сурат гирад. TGParser.cpp 2152

Агар нишондиханда LHS беэътибор аст, огохй дода шавад. Аммо, ба ҷои ин, ин нишондиҳандаи нулӣ истинод карда мешавад: LHS-> getAsString ().

Ин як ҳолати хеле маъмул аст, вақте ки хато дар коркардкунандаи хато пинҳон мешавад, зеро ҳеҷ кас онҳоро озмоиш намекунад. Анализаторҳои статикӣ, новобаста аз он ки чӣ қадар истифода мешаванд, ҳама рамзи дастрасро тафтиш мекунанд. Ин як мисоли хеле хуби он аст, ки чӣ гуна таҳлили статикӣ усулҳои дигари санҷиш ва муҳофизати хатогиҳоро пурра мекунад.

Хатогии коркарди нишондиҳандаи шабеҳ RHS дар коди дар поён овардашуда иҷозат дода шудааст: V522 [CWE-476] Барқарор кардани ишораи нул 'RHS' метавонад сурат гирад. TGParser.cpp 2186

Фрагмент N6: Истифодаи нишоннамо пас аз ҳаракат

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-Studio: V522 [CWE-476] Барқарор кардани ишораи нул 'ProgClone' метавонад сурат гирад. Тартиби нодуруст.cpp 601

Дар ибтидо як нишондиҳандаи интеллектуалӣ ProgClone моликияти объектро қатъ мекунад:

BD.setNewProgram(std::move(ProgClone));

Дар асл, ҳоло ProgClone нишондиҳандаи нул аст. Аз ин рӯ, истинод ба нул ишора бояд танҳо дар зер сурат гирад:

Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first);

Аммо, дар асл, ин рӯй нахоҳад дод! Дар хотир доред, ки ҳалқа воқеан иҷро намешавад.

Дар ибтидои контейнер Функсияҳои нодуруст тартибдодашуда тоза карда шуд:

MiscompiledFunctions.clear();

Баъдан, андозаи ин контейнер дар ҳолати ҳалқа истифода мешавад:

for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {

Дидани он осон аст, ки ҳалқа оғоз намекунад. Ман фикр мекунам, ки ин ҳам хато аст ва рамз бояд ба таври дигар навишта шавад.

Чунин ба назар мерасад, ки мо ба он паритети машҳури хатогиҳо дучор шудаем! Як хатоги дигареро ниқоб мекунад :).

Фрагмент N7: Истифодаи нишоннамо пас аз ҳаракат

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-Studio: V522 [CWE-476] Барқарор кардани ишораи нул 'Test' метавонад сурат гирад. Тартиби нодуруст.cpp 709

Боз ҳамон вазъият. Дар аввал мазмуни предмет кӯчонида мешавад ва баъд аз он истифода мешавад, ки гӯё ҳеҷ чиз рӯй надода бошад. Ман ин ҳолатро бештар ва бештар дар коди барнома пас аз пайдо шудани семантикаи ҳаракат дар C++ мебинам. Барои ҳамин ман забони C++-ро дӯст медорам! Роҳҳои бештари нав барои тирандозии пои худ вуҷуд доранд. Анализатори PVS-Studio ҳамеша кор хоҳад кард :).

Фрагмент N8: Нишондиҳандаи нул

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-Studio: V522 [CWE-476] Барқарор кардани ишораи нул "Намуд" метавонад сурат гирад. PrettyFunctionDumper.cpp 233

Илова ба коркардкунандагони хатоҳо, функсияҳои ислоҳи чоп одатан санҷида намешаванд. Дар назди мо махз хамин гуна парванда истодааст. Функсия корбареро интизор аст, ки ба ҷои ҳалли мушкилоти худ маҷбур мешавад, ки онро ислоҳ кунад.

Дуруст аст:

if (Type)
  Type->dump(*this);
else
  Printer << "<unknown-type>";

Фрагмент N9: Нишондиҳандаи нул

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-Studio: V522 [CWE-476] Барқарор кардани ишораи нул 'Ty' метавонад сурат гирад. SearchableTableEmitter.cpp 614

Ман фикр мекунам, ки ҳама чиз равшан аст ва шарҳ талаб намекунад.

Фрагмент N10: Хатогӣ

bool FormatTokenLexer::tryMergeCSharpNullConditionals() {
  ....
  auto &Identifier = *(Tokens.end() - 2);
  auto &Question = *(Tokens.end() - 1);
  ....
  Identifier->ColumnWidth += Question->ColumnWidth;
  Identifier->Type = Identifier->Type;                    // <=
  Tokens.erase(Tokens.end() - 1);
  return true;
}

Огоҳии PVS-Studio: V570 Тағйирёбандаи 'Identifier->Type' ба худ таъин карда мешавад. FormatTokenLexer.cpp 249

Таъин кардани тағирёбанда ба худ маъно надорад. Эҳтимол, онҳо мехостанд бинависанд:

Identifier->Type = Question->Type;

Фрагмент N11: Танаффуси шубҳанок

void SystemZOperand::print(raw_ostream &OS) const {
  switch (Kind) {
    break;
  case KindToken:
    OS << "Token:" << getToken();
    break;
  case KindReg:
    OS << "Reg:" << SystemZInstPrinter::getRegisterName(getReg());
    break;
  ....
}

Огоҳии PVS-Studio: V622 [CWE-478] Санҷиши изҳороти "гузариш" -ро баррасӣ кунед. Эҳтимол дорад, ки оператори аввалини "касе" нест. SystemZAsmParser.cpp 652

Дар ибтидо оператори хеле шубҳанок аст танаффус. Оё шумо дар ин ҷо чизи дигаре навиштанро фаромӯш кардаед?

Фрагмент N12: Санҷиши нишоннамо пас аз барҳам додани истинод

InlineCost AMDGPUInliner::getInlineCost(CallSite CS) {
  Function *Callee = CS.getCalledFunction();
  Function *Caller = CS.getCaller();
  TargetTransformInfo &TTI = TTIWP->getTTI(*Callee);

  if (!Callee || Callee->isDeclaration())
    return llvm::InlineCost::getNever("undefined callee");
  ....
}

Огоҳии PVS-Studio: V595 [CWE-476] Нишондиҳандаи 'Callee' пеш аз тасдиқи он бар зидди nullptr истифода шудааст. Хатҳои тафтиш: 172, 174. AMDGPUInline.cpp 172

Ишора Калли дар ибтидо ҳангоми даъват кардани функсия бекор карда мешавад дастТТИ.

Ва он гоҳ маълум мешавад, ки ин нишондиҳанда бояд барои баробарӣ тафтиш карда шавад nullptr:

if (!Callee || Callee->isDeclaration())

Аммо хеле дер шудааст…

Фрагменти N13 - N...: Санҷиши нишондиҳанда пас аз барҳам додани истинод

Вазъияте, ки дар порчаи коди қаблӣ баррасӣ шуда буд, беназир нест. Дар ин ҷо пайдо мешавад:

static Value *optimizeDoubleFP(CallInst *CI, IRBuilder<> &B,
                               bool isBinary, bool isPrecise = false) {
  ....
  Function *CalleeFn = CI->getCalledFunction();
  StringRef CalleeNm = CalleeFn->getName();                 // <=
  AttributeList CalleeAt = CalleeFn->getAttributes();
  if (CalleeFn && !CalleeFn->isIntrinsic()) {               // <=
  ....
}

Огоҳии PVS-Studio: V595 [CWE-476] Нишондиҳандаи 'CalleeFn' пеш аз тасдиқи он бар зидди nullptr истифода шудааст. Хатҳои тафтиш: 1079, 1081. SimplifyLibCalls.cpp 1079

Ва дар ин ҷо:

void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
                            const Decl *Tmpl, Decl *New,
                            LateInstantiatedAttrVec *LateAttrs,
                            LocalInstantiationScope *OuterMostScope) {
  ....
  NamedDecl *ND = dyn_cast<NamedDecl>(New);
  CXXRecordDecl *ThisContext =
    dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());         // <=
  CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
                             ND && ND->isCXXInstanceMember());     // <=
  ....
}

Огоҳии PVS-Studio: V595 [CWE-476] Нишондиҳандаи 'ND' пеш аз тасдиқи он бар зидди nullptr истифода шудааст. Хатҳои тафтиш: 532, 534. SemaTemplateInstantiateDecl.cpp 532

Ва дар ин ҷо:

  • V595 [CWE-476] Нишондиҳандаи 'U' пеш аз тасдиқи он бар зидди nullptr истифода шудааст. Хатҳои тафтиш: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] Нишондиҳандаи 'ND' пеш аз тасдиқи он бар зидди nullptr истифода шудааст. Хатҳои тафтиш: 2149, 2151. SemaTemplateInstantiate.cpp 2149

Ва он гоҳ ман ба омӯзиши огоҳиҳо бо рақами V595 шавқ надоштам. Ҳамин тавр, ман намедонам, ки ба ғайр аз хатоҳои дар ин ҷо номбаршуда хатогиҳои шабеҳ бештар вуҷуд доранд. Ба эҳтимоли зиёд вуҷуд дорад.

Фрагмент N17, N18: Гузариши шубҳанок

static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
                                           uint64_t &Encoding) {
  ....
  unsigned Size = RegSize;
  ....
  uint64_t NImms = ~(Size-1) << 1;
  ....
}

Огоҳии PVS-Studio: V629 [CWE-190] Санҷиши ифодаи '~(Андоза - 1) << 1'-ро баррасӣ кунед. Гузариши бит аз арзиши 32-бит бо тавсеаи минбаъда ба навъи 64-бит. AArch64AddressingModes.h 260

Ин метавонад хато набошад ва код маҳз мувофиқи пешбинишуда кор мекунад. Аммо ин ҷои хеле шубҳанок аст ва бояд тафтиш карда шавад.

Биёед тағирёбандаро бигӯем андоза ба 16 баробар аст ва он гоҳ муаллифи код онро дар як тағирёбанда ба нақша гирифтааст НИммс арзиш:

1111111111111111111111111111111111111111111111111111111111100000

Аммо, дар асл натиҷа чунин хоҳад буд:

0000000000000000000000000000000011111111111111111111111111100000

Далели он аст, ки ҳама ҳисобҳо бо истифода аз навъи 32-бити имзонашуда сурат мегиранд. Ва танҳо пас аз он, ин навъи 32-бити беимзо ба таври ғайримустақим васеъ карда мешавад uint64_t. Дар ин ҳолат, битҳои муҳимтарин сифр хоҳанд буд.

Шумо метавонед вазъиятро чунин ислоҳ кунед:

uint64_t NImms = ~static_cast<uint64_t>(Size-1) << 1;

Ҳолати шабеҳ: V629 [CWE-190] Санҷиши ифодаи 'Immr << 6'-ро баррасӣ кунед. Гузариши бит аз арзиши 32-бит бо тавсеаи минбаъда ба навъи 64-бит. AArch64AddressingModes.h 269

Фрагмент N19: Калимаи калидӣ мавҷуд нест боз?

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

Огоҳии PVS-Studio: V646 [CWE-670] Санҷиши мантиқи барномаро баррасӣ кунед. Эҳтимол аст, ки калимаи калидии 'else' мавҷуд набошад. AMDGPUAsmParser.cpp 5655

Дар ин ҷо хато нест. Аз хамон вакт блоки якум if ба охир мерасад давом додан, он гоҳ муҳим нест, калимаи калидӣ вуҷуд дорад боз ё не. Дар ҳар сурат, код ҳамон кор хоҳад кард. Ҳанӯз пазмон шудам боз кодро норавшан ва хавфноктар мегардонад. Агар дар оянда давом додан нест мешавад, код тамоман дигар хел кор мекунад. Ба назари ман, илова кардан беҳтар аст боз.

Фрагменти N20: Чор хатои якхела

LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const {
  std::string Result;
  if (isUndefined())
    Result += "(undef) ";
  if (isWeakDefined())
    Result += "(weak-def) ";
  if (isWeakReferenced())
    Result += "(weak-ref) ";
  if (isThreadLocalValue())
    Result += "(tlv) ";
  switch (Kind) {
  case SymbolKind::GlobalSymbol:
    Result + Name.str();                        // <=
    break;
  case SymbolKind::ObjectiveCClass:
    Result + "(ObjC Class) " + Name.str();      // <=
    break;
  case SymbolKind::ObjectiveCClassEHType:
    Result + "(ObjC Class EH) " + Name.str();   // <=
    break;
  case SymbolKind::ObjectiveCInstanceVariable:
    Result + "(ObjC IVar) " + Name.str();       // <=
    break;
  }
  OS << Result;
}

Огоҳӣ аз PVS-Studio:

  • V655 [CWE-480] Сатрҳо пайваст карда шуданд, аммо истифода намешаванд. Санҷиши ифодаи 'Result + Name.str()'-ро баррасӣ кунед. Symbol.cpp 32
  • V655 [CWE-480] Сатрҳо пайваст карда шуданд, аммо истифода намешаванд. Санҷиши ифодаи 'Result + "(ObjC Class)" + Name.str()'-ро баррасӣ кунед. Symbol.cpp 35
  • V655 [CWE-480] Сатрҳо пайваст карда шуданд, аммо истифода намешаванд. Санҷиши ифодаи 'Result + "(ObjC Class EH) " + Name.str()' -ро баррасӣ кунед. Symbol.cpp 38
  • V655 [CWE-480] Сатрҳо пайваст карда шуданд, аммо истифода намешаванд. Санҷиши ифодаи 'Result + "(ObjC IVar)" + Name.str()' -ро баррасӣ кунед. Symbol.cpp 41

Тасодуфан, оператори + ба ҷои оператори += истифода мешавад. Дар натиҷа тарҳҳое ҳастанд, ки маъно надоранд.

Фрагмент N21: Рафтори номуайян

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();
    }
  }
}

Кӯшиш кунед, ки рамзи хатарнокро худатон пайдо кунед. Ва ин расмест, ки диққатро парешон кунад, то фавран ба ҷавоб нигоҳ накунад:

Ҷустуҷӯи хатогиҳо дар LLVM 8 бо истифода аз таҳлилгари PVS-Studio

Огоҳии PVS-Studio: V708 [CWE-758] Сохтмони хатарнок истифода мешавад: 'FeaturesMap[Op] = FeaturesMap.size()', ки дар он 'FeaturesMap' аз синфи 'харита' аст. Ин метавонад ба рафтори номуайян оварда расонад. RISCVCompressInstEmitter.cpp 490

Хатти мушкилот:

FeaturesMap[Op] = FeaturesMap.size();

Агар элемент Op ёфт нашуда бошад, пас дар харита элементи нав сохта мешавад ва дар он чо шумораи элементхои ин харита навишта мешавад. Танҳо маълум нест, ки ин функсия даъват карда мешавад ё не андоза пеш аз ё баъд аз илова кардани элементи нав.

Фрагмент N22-N24: Супоришҳои такрорӣ

Error MachOObjectFile::checkSymbolTable() const {
  ....
  } else {
    MachO::nlist STE = getSymbolTableEntry(SymDRI);
    NType = STE.n_type;                              // <=
    NType = STE.n_type;                              // <=
    NSect = STE.n_sect;
    NDesc = STE.n_desc;
    NStrx = STE.n_strx;
    NValue = STE.n_value;
  }
  ....
}

Огоҳии PVS-Studio: V519 [CWE-563] Тағйирёбандаи 'NType' ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Хатҳои тафтиш: 1663, 1664. MachOObjectFile.cpp 1664

Ман фикр намекунам, ки дар ин ҷо хатои воқеӣ вуҷуд дорад. Танҳо як супориши такрории нолозим. Аммо боз як хато.

Мисли:

  • V519 [CWE-563] Тағйирёбандаи "B.NDesc" ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Хатхои тафтиш: 1488, 1489. llvm-nm.cpp 1489
  • V519 [CWE-563] Ба тағирёбанда ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Сатрҳои тафтиш: 59, 61. coff2yaml.cpp 61

Фрагмент N25-N27: Тағйироти бештар

Акнун биёед як варианти каме фарқкунандаи таъйинотро бубинем.

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

Огоҳии PVS-Studio: V519 [CWE-563] Тағйирёбандаи 'Alignment' ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Хатҳои тафтиш: 1158, 1160. LoadStoreVectorizer.cpp 1160

Ин рамзи хеле аҷиб аст, ки зоҳиран хатои мантиқӣ дорад. Дар ибтидо, тағйирёбанда Мутобиқ вобаста ба шароит арзиш таъин карда мешавад. Ва он гоҳ супориш дубора ба амал меояд, аммо ҳоло бидуни санҷиш.

Чунин ҳолатҳоро дар ин ҷо дидан мумкин аст:

  • V519 [CWE-563] Тағйирёбандаи "Эффектҳо" ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Хатҳои тафтиш: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] Тағйирёбандаи 'ExpectNoDerefChunk' ду маротиба пайдарпай арзишҳо таъин карда мешавад. Шояд ин хато бошад. Хатҳои тафтиш: 4970, 4973. SemaType.cpp 4973

Фрагмент N28: Ҳолати ҳамеша ҳақиқӣ

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

Огоҳии PVS-Studio: V547 [CWE-571] Ифодаи 'nextByte != 0x90' ҳамеша дуруст аст. X86DisassemblerDecoder.cpp 379

Санҷиш маъно надорад. Тағйирёбанда nextByte на ҳамеша ба арзиш баробар аст 0x90, ки аз тафтиши пештара бармеояд. Ин як навъ хатои мантиқӣ аст.

Фрагмент N29 - N...: Ҳамеша шартҳои дуруст/дурӯғ

Анализатор бисёр огоҳӣ медиҳад, ки тамоми ҳолати (V547) ё як қисми он (V560) ҳамеша рост ё дурӯғ аст. Аксар вақт инҳо хатогиҳои воқеӣ нестанд, балки рамзи оддӣ, натиҷаи васеъшавии макросҳо ва ғайра мебошанд. Бо вуҷуди ин, ба ҳамаи ин огоҳиҳо нигоҳ кардан маъно дорад, зеро баъзан хатогиҳои мантиқии ҳақиқӣ рӯй медиҳанд. Масалан, ин фасли код шубҳанок аст:

static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
                                   uint64_t Address, const void *Decoder) {
  DecodeStatus S = MCDisassembler::Success;

  if (RegNo > 13)
    return MCDisassembler::Fail;

  if ((RegNo & 1) || RegNo == 0xe)
     S = MCDisassembler::SoftFail;
  ....
}

Огоҳии PVS-Studio: V560 [CWE-570] Як қисми ифодаи шартӣ ҳамеша нодуруст аст: RegNo == 0xe. ARMDisassembler.cpp 939

0xE доимӣ арзиши 14 дар даҳӣ мебошад. Имтиҳон RegNo == 0xe маъно надорад, зеро агар RegNo > 13, он гоҳ функсия иҷрои худро анҷом медиҳад.

Бисёр огоҳиҳои дигар бо ID-ҳои V547 ва V560 буданд, аммо мисли V595, Ман ба омӯзиши ин огоҳиҳо таваҷҷӯҳ надоштам. Аллакай маълум буд, ки барои навиштани мақола маводи кофӣ доштам :). Аз ин рӯ, маълум нест, ки дар LLVM бо истифода аз PVS-Studio чӣ қадар ин гуна хатогиҳоро муайян кардан мумкин аст.

Ман ба шумо мисоле медиҳам, ки чаро омӯзиши ин триггерҳо дилгиркунанда аст. Анализатор комилан дуруст аст, ки барои коди зерин огоҳӣ диҳад. Аммо ин хато нест.

bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
                                          tok::TokenKind ClosingBraceKind) {
  bool HasError = false;
  ....
  HasError = true;
  if (!ContinueOnSemicolons)
    return !HasError;
  ....
}

Огоҳии PVS-Studio: V547 [CWE-570] Ифодаи '!HasError' ҳамеша дурӯғ аст. UnwrappedLineParser.cpp 1635

Фрагмент N30: ​​Бозгашти шубҳанок

static bool
isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
  for (MachineRegisterInfo::def_instr_iterator It = MRI.def_instr_begin(Reg),
      E = MRI.def_instr_end(); It != E; ++It) {
    return (*It).isImplicitDef();
  }
  ....
}

Огоҳии PVS-Studio: V612 [CWE-670] "Бозгашти" бидуни шарт дар дохили давр. R600OptimizeVectorRegisters.cpp 63

Ин ё хато ё техникаи мушаххасест, ки барои шарҳ додани чизе ба барномасозоне, ки кодро мехонанд, пешбинӣ шудааст. Ин тарҳ ба ман чизе намефаҳмонад ва хеле шубҳанок менамояд. Бехтараш ин хел нанависед :).

Хаста? Он гоҳ вақти он расидааст, ки чой ё қаҳва тайёр кунед.

Ҷустуҷӯи хатогиҳо дар LLVM 8 бо истифода аз таҳлилгари PVS-Studio

Камбудиҳое, ки бо ташхиси нав муайян карда шудаанд

Ман фикр мекунам, ки 30 фаъолсозии ташхиси кӯҳна кифоя аст. Биёед ҳоло бубинем, ки бо ташхиси наве, ки пас аз он дар анализатор пайдо шуд, чӣ чизҳои ҷолибро ёфтан мумкин аст қаблӣ чекхо. Дар ин муддат ба анализатори C++ ҳамагӣ 66 ташхиси таъиноти умумӣ илова карда шуд.

Фрагмент N31: Рамзи дастнорас

Error CtorDtorRunner::run() {
  ....
  if (auto CtorDtorMap =
          ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names),
                    NoDependenciesToRegister, true))
  {
    ....
    return Error::success();
  } else
    return CtorDtorMap.takeError();

  CtorDtorsByPriority.clear();

  return Error::success();
}

Огоҳии PVS-Studio: V779 [CWE-561] Рамзи дастнорас ошкор карда шуд. Мумкин аст, ки хатогӣ вуҷуд дошта бошад. ExecutionUtils.cpp 146

Тавре ки шумо мебинед, ҳар ду филиали оператор if бо занг ба оператор ба охир мерасад бозгашт. Мувофиқи он, контейнер CtorDtorsByPriority ҳеҷ гоҳ тоза карда намешавад.

Фрагмент N32: Рамзи дастнорас

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

Огоҳии PVS-Studio: V779 [CWE-561] Рамзи дастнорас ошкор карда шуд. Мумкин аст, ки хатогӣ вуҷуд дошта бошад. LLparser.cpp 835

Ҳолати ҷолиб. Биёед аввал ин ҷойро бубинем:

return ParseTypeIdEntry(SummaryID);
break;

Дар назари аввал чунин менамояд, ки дар ин чо хатое нест. Чунин ба назар мерасад, ки оператор танаффус дар ин ҷо як иловагӣ вуҷуд дорад ва шумо метавонед онро танҳо нест кунед. Бо вуҷуди ин, на ҳама он қадар оддӣ.

Анализатор дар сатрҳо огоҳӣ медиҳад:

Lex.setIgnoreColonInIdentifiers(false);
return false;

Ва дар ҳақиқат, ин рамз дастнорас аст. Ҳама ҳолатҳо дар гузаред бо занги оператор ба охир мерасад бозгашт. Ва ҳоло танҳо бемаънӣ танаффус он кадар безарар ба назар намерасад! Шояд яке аз шохаҳо бояд бо анҷом танаффусна дар бозгашт?

Фрагмент N33: Барқароркунии тасодуфии битҳои баланд

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

Огоҳии PVS-Studio: V784 Андозаи ниқоби бит аз андозаи операнди аввал камтар аст. Ин боиси аз даст додани битҳои баландтар мегардад. RuntimeDyld.cpp 815

Лутфан қайд кунед, ки функсия getStubAlignment навъи бармегардад беимзо. Биёед арзиши ифодаро ҳисоб кунем, бо назардошти он ки функсия арзиши 8-ро бармегардонад:

~(getStubAlignment() - 1)

~(8у-1)

0xFFFFFFFF8u

Акнун диққат диҳед, ки тағирёбанда Андозаи маълумот дорои навъи 64-битаи имзонашуда. Маълум мешавад, ки ҳангоми иҷрои амалиёти DataSize & 0xFFFFFFFF8u, ҳамаи сию ду битҳои дараҷаи олӣ ба сифр барқарор карда мешаванд. Эҳтимол, ин чизест, ки барномасоз мехост. Ман гумон мекунам, ки ӯ мехост ҳисоб кунад: DataSize & 0xFFFFFFFFFFFFFF8u.

Барои ислоҳ кардани хато, шумо бояд инҳоро нависед:

DataSize &= ~(static_cast<uint64_t>(getStubAlignment()) - 1);

Ё ин ки:

DataSize &= ~(getStubAlignment() - 1ULL);

Фрагмент N34: Намоиши навъи возеҳ

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

Огоҳии PVS-Studio: V1028 [CWE-190] Зиёдшавии эҳтимолӣ. Дар бораи интиқол додани операндҳои оператори 'NumElts * Scale' ба навъи 'size_t' баррасӣ кунед, на натиҷа. X86ISelLowering.h 1577

Кастинги навъи возеҳ барои пешгирӣ кардани изофа ҳангоми зиёд кардани тағирёбандаҳои навъи истифода мешавад Int. Аммо, кастинги навъи возеҳ дар ин ҷо аз обхезӣ муҳофизат намекунад. Аввалан, тағирёбандаҳо зарб карда мешаванд ва танҳо пас аз он натиҷаи 32-битии зарб ба намуди васеъ карда мешавад. андоза_т.

Фрагмент N35: Нусхабардорӣ ва часбонед

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] Ду порчаи коди шабеҳ ёфт шуд. Эҳтимол, ин хато аст ва тағирёбандаи "Op1" бояд ба ҷои "Op0" истифода шавад. InstCombineCompares.cpp 5507

Ин ташхиси нави ҷолиб вазъиятҳоеро муайян мекунад, ки пораи код нусхабардорӣ шудааст ва баъзе номҳо дар он тағир ёфтаанд, аммо дар як ҷо онҳо онро ислоҳ накардаанд.

Лутфан қайд кунед, ки дар блоки дуюм онҳо иваз карда шуданд Оп 0 ба Оп 1. Аммо дар як чо онро ислох накарданд. Эҳтимол, он бояд чунин навишта шавад:

if (!match(Op1, m_PosZeroFP()) && isKnownNeverNaN(Op1, &TLI)) {
  I.setOperand(1, ConstantFP::getNullValue(Op1->getType()));
  return &I;
}

Фрагмент N36: Нофаҳмиҳои тағйирёбанда

struct Status {
  unsigned Mask;
  unsigned Mode;

  Status() : Mask(0), Mode(0){};

  Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
    Mode &= Mask;
  };
  ....
};

Огоҳии PVS-Studio: V1001 [CWE-563] Тағйирёбандаи "Мод" таъин шудааст, аммо дар охири функсия истифода намешавад. SIModeRegister.cpp 48

Ба аргументҳои функсионалӣ ҳамон номҳоеро бо аъзоёни синф додан хеле хатарнок аст. Ошуфта шудан хеле осон аст. Дар назди мо махз хамин гуна парванда истодааст. Ин ибора маъно надорад:

Mode &= Mask;

Аргументи функсия тағир меёбад. Ҳамааш ҳамин. Ин далел дигар истифода намешавад. Эҳтимол, шумо бояд онро чунин навиштед:

Status(unsigned Mask, unsigned Mode) : Mask(Mask), Mode(Mode) {
  this->Mode &= Mask;
};

Фрагмент N37: Нофаҳмиҳои тағйирёбанда

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

Огоҳӣ PVS-Studio: V1001 [CWE-563] Тағйирёбандаи 'Size' таъин шудааст, аммо дар охири функсия истифода намешавад. Object.cpp 424

Вазъият ба вазъияти пештара монанд аст. Он бояд навишта шавад:

this->Size += this->EntrySize;

Фрагмент N38-N47: Онҳо тафтиши индексро фаромӯш кардаанд

Пештар, мо мисолҳои триггерҳои ташхисро дида баромадем V595. Мохияти он аз он иборат аст, ки нишондиханда дар ибтидо аз эътибор гирифта мешавад ва танхо баъд санчида мешавад. Диагностикаи ҷавон V1004 аз чихати маънй мукобил буда, хатохои зиёдеро низ ошкор мекунад. Он ҳолатҳоеро муайян мекунад, ки нишондиҳанда дар аввал санҷида шуда, баъд фаромӯш карда шудааст. Биёед чунин ҳолатҳоро дар дохили 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());  // <=
  ....
}

Огоҳӣ дар бораи PVS-Studio: V1004 [CWE-476] Нишондиҳандаи 'Ptr' пас аз санҷиши он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 729, 738. TargetTransformInfoImpl.h 738

Тағйирёбанда Птр баробар шуда метавонад nullptr, чи тавре ки тафтиш шаходат медихад:

if (Ptr != nullptr)

Аммо, дар зер ин нишондод бе тафтиши пешакӣ истинод карда мешавад:

auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());

Боз як мисоли ба ин монандро дида мебароем.

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(); // <=
  ....
}

Огоҳӣ дар бораи PVS-Studio: V1004 [CWE-476] Нишондиҳандаи 'FD' пас аз санҷиши он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 3228, 3231. CGDebugInfo.cpp 3231

Ба аломат диққат диҳед FD. Ман боварӣ дорам, ки мушкилот ба таври равшан намоён аст ва ҳеҷ шарҳи махсус талаб карда намешавад.

Ва минбаъд:

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());     // <=
  ....
}

Огоҳӣ дар бораи PVS-Studio: V1004 [CWE-476] Нишондиҳандаи 'PtrTy' пас аз санҷиши он бар зидди nullptr ба таври бехатар истифода шуд. Хатҳои тафтиш: 960, 965. InterleavedLoadCombinePass.cpp 965

Чӣ тавр худро аз чунин хатогиҳо муҳофизат кардан мумкин аст? Ба Code-Review бештар бодиққат бошед ва таҳлилгари статикии PVS-Studioро истифода баред, то рамзи худро мунтазам тафтиш кунед.

Иқтибос овардани порчаҳои дигари рамзӣ бо хатогиҳои ин намуд ҷоиз нест. Ман танҳо як рӯйхати огоҳиҳоро дар мақола мегузорам:

  • V1004 [CWE-476] Нишондиҳандаи 'Expr' пас аз тасдиқи он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 1049, 1078. DebugInfoMetadata.cpp 1078
  • V1004 [CWE-476] Нишондиҳандаи 'PI' пас аз санҷиши он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 733, 753. LegacyPassManager.cpp 753
  • V1004 [CWE-476] Нишондиҳандаи 'StatepointCall' пас аз санҷиши он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 4371, 4379. Verifier.cpp 4379
  • V1004 [CWE-476] Нишондиҳандаи 'RV' пас аз санҷиши он бар зидди nullptr ноустувор истифода шуд. Хатҳои санҷиш: 2263, 2268. TGParser.cpp 2268
  • V1004 [CWE-476] Нишондиҳандаи 'CalleeFn' пас аз тасдиқи он бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 1081, 1096. SimplifyLibCalls.cpp 1096
  • V1004 [CWE-476] Нишондиҳандаи 'TC' пас аз санҷида шуданаш бар зидди nullptr ноустувор истифода шуд. Хатҳои тафтиш: 1819, 1824. Driver.cpp 1824

Фрагмент N48-N60: Муҳим нест, аммо нуқсон (хуриши хотираи эҳтимолӣ)

std::unique_ptr<IRMutator> createISelMutator() {
  ....
  std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
  Strategies.emplace_back(
      new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
  ....
}

Огоҳии PVS-Studio: V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Strategies" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-isel-fuzzer.cpp 58

Барои илова кардани элемент ба охири контейнер монанди std::вектор > шумо наметавонед танҳо нависед xxx.push_back(X нав), зеро ҳеҷ табдили номуайян аз вуҷуд надорад X* в std::unique_ptr.

Як ҳалли умумӣ ин навиштан аст xxx.emplace_back(X нав)зеро он тартиб медихад: метод ҷои_баргашт як унсурро мустақиман аз аргументҳои худ месозад ва аз ин рӯ метавонад конструкторҳои возеҳро истифода барад.

Ин бехатар нест. Агар вектор пур бошад, пас хотира аз нав тақсим карда мешавад. Амали азнавтақсимкунии хотира метавонад ноком шавад, ки дар натиҷа истисно партофта мешавад std :: bad_alloc. Дар ин ҳолат, нишоннамо гум мешавад ва объекти сохташуда ҳеҷ гоҳ нест карда намешавад.

Як ҳалли бехатар эҷод аст беназир_ptrки пеш аз он ки вектор хотираро аз нав тақсим кунад, нишондодро соҳиб мешавад:

xxx.push_back(std::unique_ptr<X>(new X))

Азбаски C++14, шумо метавонед 'std::make_unique'-ро истифода баред:

xxx.push_back(std::make_unique<X>())

Ин навъи камбудӣ барои LLVM муҳим нест. Агар хотира ҷудо карда нашавад, компилятор танҳо қатъ мешавад. Бо вуҷуди ин, барои барномаҳои дароз вақти кор, ки танҳо дар сурати ноком шудани тақсимоти хотира қатъ карда наметавонад, ин метавонад як хатои воқеии бад бошад.

Ҳамин тавр, гарчанде ки ин код барои LLVM таҳдиди амалӣ надорад, ман муфид донистам, ки дар бораи ин хатогӣ сӯҳбат кунам ва таҳлилгари PVS-Studio муайян кардани онро ёд гирифт.

Дигар огоҳиҳои ин навъи:

  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери "Гузаришҳо" нишондиҳандаи бе соҳиби он илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. PassManager.h 546
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "AAs" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. AliasAnalysis.h 324
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери 'Entries' бо усули 'emplace_back' илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. DWARFDebugFrame.cpp 519
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "AllEdges" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. CFGMST.h 268
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "VMaps" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. SimpleLoopUnswitch.cpp 2012
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери 'Records' бо усули 'emplace_back' илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. FDRLogBuilder.h 30
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "PendingSubmodules" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. ModuleMap.cpp 810
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Объектҳо" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. DebugMap.cpp 88
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Strategies" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-isel-fuzzer.cpp 60
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 685
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 686
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 688
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 689
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 690
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 691
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 692
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 693
  • V1023 [CWE-460] Бо усули 'emplace_back' ба контейнери 'Modifiers' нишондиҳандаи бе соҳиб илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. llvm-stress.cpp 694
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Операндҳо" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Stash" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] Нишондиҳандаи бидуни соҳиб ба контейнери "Matchers" бо усули "emplace_back" илова карда мешавад. Дар сурати истисно ихроҷи хотира рух медиҳад. GlobalISelEmitter.cpp 2702

хулоса

Ман ҳамагӣ 60 огоҳӣ додам ва баъд қатъ кардам. Оё камбудиҳои дигаре ҳастанд, ки таҳлилгари PVS-Studio дар LLVM ошкор мекунад? Бале, ман дорам. Аммо, вақте ки ман порчаҳои кодро барои мақола менависам, бегоҳ, дурусттараш, шаб буд ва ман қарор додам, ки вақти он расидааст, ки онро як рӯз даъват кунем.

Умедворам, ки шумо онро ҷолиб ёфтед ва мехоҳед таҳлилгари PVS-Studio-ро санҷед.

Шумо метавонед анализаторро зеркашӣ кунед ва калиди киштии минаро дар ин ҷо дастрас кунед ин саҳифа.

Муҳимтар аз ҳама, мунтазам таҳлили статикиро истифода баред. Санҷишҳои яквақта, ки аз ҷониби мо бо мақсади маъмул гардонидани методологияи таҳлили статикӣ амалӣ карда мешавад ва PVS-Studio як сенарияи муқаррарӣ нест.

Дар баланд бардоштани сифат ва эътимоднокии коди худ барори кор!

Ҷустуҷӯи хатогиҳо дар LLVM 8 бо истифода аз таҳлилгари PVS-Studio

Агар шумо хоҳед, ки ин мақоларо бо шунавандагони англисзабон мубодила кунед, лутфан истиноди тарҷумаро истифода баред: Андрей Карпов. Ҷустуҷӯи хатогиҳо дар LLVM 8 бо PVS-Studio.

Манбаъ: will.com

Илова Эзоҳ