PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM 8 හි දෝෂ සොයා ගැනීම

PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM 8 හි දෝෂ සොයා ගැනීම
අපගේ PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM ව්‍යාපෘතියේ අවසාන කේත පරීක්ෂාවෙන් වසර දෙකකට වැඩි කාලයක් ගතවී ඇත. PVS-Studio විශ්ලේෂකය තවමත් දෝෂ සහ විභව දුර්වලතා හඳුනා ගැනීම සඳහා ප්‍රමුඛ මෙවලමක් බව සහතික කර ගනිමු. මෙය සිදු කිරීම සඳහා, අපි LLVM 8.0.0 නිකුතුවේ නව දෝෂ පරීක්ෂා කර සොයා බලමු.

ලිවිය යුතු ලිපිය

ඇත්තම කිව්වොත් මට මේ ලිපිය ලියන්න ඕන වුණේ නැහැ. අප දැනටමත් කිහිප වතාවක් පරීක්ෂා කර ඇති ව්‍යාපෘතියක් ගැන ලිවීම සිත්ගන්නා සුළු නොවේ (1, 2, 3) අලුත් දෙයක් ගැන ලිවීම වඩා හොඳය, නමුත් මට විකල්පයක් නැත.

LLVM හි නව අනුවාදයක් නිකුත් කරන හෝ යාවත්කාලීන කරන සෑම අවස්ථාවකම ක්ලැන්ග් ස්ථිතික විශ්ලේෂකය, අපගේ තැපෑලෙන් අපට පහත ආකාරයේ ප්‍රශ්න ලැබේ:

බලන්න, Clang Static Analyzer හි නව අනුවාදය නව දෝෂ සොයා ගැනීමට ඉගෙන ගෙන ඇත! PVS-Studio භාවිතා කිරීමේ අදාළත්වය අඩුවෙමින් පවතින බව මට පෙනේ. ක්ලැන්ග් පෙරට වඩා වැඩි දෝෂ සොයාගෙන PVS-Studio හි හැකියාවන් ලබා ගනී. මේ ගැන ඔබ මොනවද හිතන්නේ?

මේ සඳහා මට සෑම විටම මෙවැනි දෙයකට පිළිතුරු දීමට අවශ්‍යයි:

අපිත් නිකන් ඉන්නේ නැහැ! අපි PVS-Studio විශ්ලේෂකයේ හැකියාවන් සැලකිය යුතු ලෙස වැඩිදියුණු කර ඇත. ඒ නිසා බය වෙන්න එපා අපි පෙර පරිදිම ඉදිරියට යනවා.

අවාසනාවට, මෙය නරක පිළිතුරකි. එහි කිසිදු සාක්ෂියක් නොමැත. ඒ වගේම තමයි මම දැන් මේ ලිපිය ලියන්නේ. එබැවින්, LLVM ව්‍යාපෘතිය නැවත වරක් පරීක්ෂා කර ඇති අතර එහි විවිධ දෝෂ සොයාගෙන ඇත. මට සිත්ගන්නාසුළු යැයි පෙනෙන ඒවා මම දැන් නිරූපණය කරමි. ක්ලැන්ග් ස්ථිතික විශ්ලේෂකයට මෙම දෝෂ සොයාගත නොහැක (නැතහොත් එහි ආධාරයෙන් එය කිරීම අතිශයින් අපහසු වේ). නමුත් අපට පුළුවන්. එපමණක්ද නොව, මම එක් සවස් වරුවේ මෙම සියලු දෝෂ සොයාගෙන ලියා තැබුවෙමි.

නමුත් ලිපිය ලිවීමට සති කිහිපයක් ගත විය. මේ සියල්ල පෙළට දැමීමට මට සිතාගත නොහැකි විය :).

මාර්ගය වන විට, දෝෂ සහ විභව අවදානම් හඳුනා ගැනීම සඳහා PVS-Studio විශ්ලේෂකයේ භාවිතා කරන තාක්ෂණයන් ගැන ඔබ උනන්දු වන්නේ නම්, මම මේ පිළිබඳව දැන හඳුනා ගැනීමට යෝජනා කරමි. සටහන.

නව සහ පැරණි රෝග විනිශ්චය

දැනටමත් සඳහන් කර ඇති පරිදි, වසර දෙකකට පමණ පෙර LLVM ව්යාපෘතිය නැවත වරක් පරීක්ෂා කරන ලද අතර, සොයාගත් දෝෂ නිවැරදි කරන ලදී. දැන් මෙම ලිපිය නව දෝෂ සමූහයක් ඉදිරිපත් කරනු ඇත. නව දෝෂ සොයා ගත්තේ ඇයි? මේ සඳහා හේතු 3 ක් ඇත:

  1. LLVM ව්‍යාපෘතිය පරිණාමය වෙමින් පවතින අතර, පැරණි කේතය වෙනස් කරමින් සහ නව කේතයක් එක් කරයි. ස්වාභාවිකවම, නවීකරණය කරන ලද සහ ලිඛිත කේතයේ නව දෝෂ තිබේ. මෙය පැහැදිලිව පෙන්නුම් කරන්නේ ස්ථිතික විශ්ලේෂණය නිතිපතා භාවිතා කළ යුතු අතර ඉඳහිට නොවේ. අපගේ ලිපි PVS-Studio විශ්ලේෂකයේ හැකියාවන් හොඳින් පෙන්නුම් කරයි, නමුත් මෙය කේතයේ ගුණාත්මකභාවය වැඩි දියුණු කිරීම සහ දෝෂ නිවැරදි කිරීමේ පිරිවැය අඩු කිරීම සමඟ කිසිදු සම්බන්ධයක් නැත. ස්ථිතික කේත විශ්ලේෂකය නිතිපතා භාවිතා කරන්න!
  2. අපි දැනට පවතින රෝග විනිශ්චය අවසන් කර වැඩිදියුණු කරමින් සිටිමු. එමනිසා, විශ්ලේෂකය පෙර ස්කෑන් කිරීමේදී එය නොදැන සිටි දෝෂ හඳුනා ගත හැකිය.
  3. වසර 2 කට පෙර නොතිබූ PVS-Studio හි නව රෝග විනිශ්චයන් දර්ශනය වී ඇත. 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.

Fragment 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))

මාර්ගය වන විට, ත්රිත්ව ක්රියාකරු ඉතා භයානක වන අතර තාර්කික දෝෂයන් අවුලුවයි. එය ඉතා පරිස්සම් වන්න, වරහන් සමඟ කෑදර නොවන්න. මම මෙම මාතෘකාව වඩාත් විස්තරාත්මකව බැලුවෙමි මෙහි, පරිච්ෙඡ්දය තුළ “පරෙස්සම් වන්න?: ක්‍රියාකරු සහ වරහන් තුළ එය වසන්න.”

Fragment N4, N5: Null pointer

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] null pointer 'LHS' හි dereferencing සිදු විය හැක. TGParser.cpp 2152

දර්ශකය නම් එල්එච්එස් ශුන්‍ය වේ, අනතුරු ඇඟවීමක් නිකුත් කළ යුතුය. කෙසේ වෙතත්, ඒ වෙනුවට, මෙම null pointer එකම dereference කරනු ඇත: LHS->getAsString().

කිසිවෙක් ඒවා පරීක්‍ෂා නොකරන බැවින්, දෝෂ හසුරුවන්නෙහි දෝෂයක් සඟවා ඇති විට මෙය ඉතා සාමාන්‍ය තත්ත්වයකි. ස්ථිතික විශ්ලේෂක එය කොපමණ වාර ගණනක් භාවිතා කළත් ළඟා විය හැකි සියලුම කේතයන් පරීක්ෂා කරයි. ස්ථිතික විශ්ලේෂණය අනෙකුත් පරීක්ෂණ සහ දෝෂ ආරක්ෂණ ක්‍රමවේද සම්පූර්ණ කරන ආකාරය පිළිබඳ මෙය ඉතා හොඳ උදාහරණයකි.

සමාන පොයින්ටර් හැසිරවීමේ දෝෂයක් ආර් පහත කේතයෙන් අවසර දී ඇත: V522 [CWE-476] 'RHS' ශුන්‍ය ලක්ෂ්‍යය ඉවත් කිරීම සිදු විය හැක. TGParser.cpp 2186

Fragment 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' ශුන්‍ය ලක්ෂ්‍යය ඉවත් කිරීම සිදු විය හැක. Miscompilation.cpp 601

ආරම්භයේ දී ස්මාර්ට් දර්ශකයක් ProgClone වස්තුව අයිති කර ගැනීම නවත්වයි:

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

ඇත්ත වශයෙන්ම, දැන් ProgClone null pointer වේ. එබැවින්, null pointer dereference එකක් පහතින් සිදුවිය යුතුය:

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

නමුත් යථාර්ථයේ දී මෙය සිදු නොවනු ඇත! ලූපය ඇත්ත වශයෙන්ම ක්‍රියාත්මක නොවන බව සලකන්න.

කන්ටේනරය ආරම්භයේ දී වැරදි සම්පාදනය කරන ලද කාර්යයන් නිෂ්කාශනය:

MiscompiledFunctions.clear();

ඊළඟට, මෙම කන්ටේනරයේ ප්‍රමාණය ලූප් තත්වයේ භාවිතා වේ:

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

ලූපය ආරම්භ නොවන බව දැකීම පහසුය. මම හිතන්නේ මේකත් bug එකක් නිසා code එක වෙනස් විදියට ලියන්න ඕනේ.

එම ප්‍රසිද්ධ දෝෂ සමානාත්මතාවයට අප මුහුණ දී ඇති බව පෙනේ! එක වැරැද්දක් තවත් වැස්මකි :).

Fragment 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] ශුන්‍ය දර්ශකය 'පරීක්‍ෂණය' ඉවත් කිරීම සිදු විය හැක. Miscompilation.cpp 709

නැවතත් එම තත්ත්වයම. මුලදී, වස්තුවේ අන්තර්ගතය චලනය වන අතර, පසුව එය කිසිවක් සිදු නොවූ ලෙස භාවිතා කරයි. C++ හි චලන අර්ථකථන දර්ශනය වූ පසු වැඩසටහන් කේතයේ මෙම තත්වය වැඩි වැඩියෙන් මම දකිමි. මේ නිසා මම C++ භාෂාවට ආදරෙයි! ඔබේම කකුලෙන් වෙඩි තැබීමට වැඩි වැඩියෙන් නව ක්රම තිබේ. PVS-Studio විශ්ලේෂකය සැමවිටම වැඩ ඇත :).

Fragment N8: Null pointer

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] null pointer 'type' හි dereferencing සිදු විය හැක. PrettyFunctionDumper.cpp 233

දෝෂ හසුරුවන්නන්ට අමතරව, නිදොස් කිරීමේ මුද්‍රණ කාර්යයන් සාමාන්‍යයෙන් පරීක්‍ෂා නොකෙරේ. අප ඉදිරියේ ඇත්තේ එවැනි නඩුවක් පමණි. කාර්යය පරිශීලකයා බලා සිටින අතර, ඔහුගේ ගැටළු විසඳීම වෙනුවට එය නිවැරදි කිරීමට බල කෙරෙනු ඇත.

නිවැරදිව:

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

Fragment N9: Null pointer

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

ආරම්භයේ ඉතා සැක සහිත ක්රියාකරුවෙක් සිටී බිඳීම. ඔබට මෙහි තවත් යමක් ලිවීමට අමතකද?

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

PVS-Studio අනතුරු ඇඟවීම: V595 [CWE-476] 'Callee' දර්ශකය nullptr ට එරෙහිව සත්‍යාපනය කිරීමට පෙර භාවිතා කරන ලදී. පිරික්සුම් රේඛා: 172, 174. AMDGPUInline.cpp 172

දර්ශකය කැලී ආරම්භයේ දී ශ්‍රිතය කැඳවන අවස්ථාවේ දී dereference කරනු ලැබේ getTTI.

එවිට මෙම දර්ශකය සමානාත්මතාවය සඳහා පරීක්ෂා කළ යුතු බව පෙනී යයි nullptr:

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

ඒත් පරක්කු වැඩියි...

Fragment N13 - N...: dereferencing කිරීමෙන් පසු දර්ශකයක් පරීක්ෂා කිරීම

පෙර කේත ඛණ්ඩයේ සාකච්ඡා කළ තත්වය අද්විතීය නොවේ. එය මෙහි දිස්වේ:

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] nullptr ට එරෙහිව සත්‍යාපනය කිරීමට පෙර 'U' දර්ශකය භාවිතා කරන ලදී. පිරික්සුම් රේඛා: 404, 407. DWARFormValue.cpp 404
  • V595 [CWE-476] 'ND' දර්ශකය nullptr ට එරෙහිව සත්‍යාපනය කිරීමට පෙර භාවිතා කරන ලදී. පිරික්සුම් රේඛා: 2149, 2151. SemaTemplateInstantiate.cpp 2149

එවිට මම V595 අංකය සහිත අනතුරු ඇඟවීම් අධ්‍යයනය කිරීමට උනන්දු නොවෙමි. එබැවින් මෙහි ලැයිස්තුගත කර ඇති ඒවාට අමතරව තවත් සමාන දෝෂ තිබේදැයි මම නොදනිමි. බොහෝ විට එහි තිබේ.

Fragment 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-bit අගය බිට් මාරු කිරීම. AArch64AddressingModes.h 260

එය දෝෂයක් නොවිය හැකි අතර කේතය හරියටම අපේක්ෂිත පරිදි ක්‍රියා කරයි. නමුත් මෙය පැහැදිලිවම ඉතා සැක සහිත ස්ථානයක් වන අතර එය පරීක්ෂා කළ යුතුය.

විචල්‍යය කියමු තරම 16 ට සමාන වන අතර, පසුව කේතයේ කතුවරයා එය විචල්යයකින් ලබා ගැනීමට සැලසුම් කර ඇත නිම්ස් අගය:

1111111111111111111111111111111111111111111111111111111111100000

කෙසේ වෙතත්, යථාර්ථයේ දී ප්රතිඵලය වනුයේ:

0000000000000000000000000000000011111111111111111111111111100000

කාරණය නම් සියලුම ගණනය කිරීම් සිදුවන්නේ 32-bit අත්සන් නොකළ වර්ගය භාවිතා කරමිනි. එවිට පමණක්, මෙම 32-bit අත්සන් නොකළ වර්ගය ව්‍යංගයෙන් ව්‍යාප්ත වනු ඇත uint64_t. මෙම අවස්ථාවේදී, වඩාත්ම වැදගත් බිටු ශුන්ය වනු ඇත.

ඔබට මේ ආකාරයට තත්වය නිවැරදි කළ හැකිය:

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

සමාන තත්වයක්: V629 [CWE-190] 'Immr << 6' ප්‍රකාශනය පරීක්ෂා කිරීම සලකා බලන්න. 32-බිට් වර්ගයට පසුව විස්තාරණයක් සමඟ 64-bit අගය බිට් මාරු කිරීම. AArch64AddressingModes.h 269

Fragment 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] යෙදුමේ තර්කනය පරීක්ෂා කිරීම සලකා බලන්න. 'වෙනත්' මූල පදය අස්ථානගත වී තිබිය හැක. AMDGPUAsmParser.cpp 5655

මෙහි වරදක් නැත. පළමු කොටසේ එවකට-බ්ලොක් එකේ සිට if අවසන් වේ දිගටම, එහෙනම් කමක් නෑ Keyword එකක් තියෙනවා වෙන නැත්ද. ඕනෑම ආකාරයකින් කේතය එකම ලෙස ක්‍රියා කරයි. තවමත් මග හැරුණි වෙන කේතය වඩාත් අපැහැදිලි සහ භයානක කරයි. අනාගතයේ නම් දිගටම අතුරුදහන් වේ, කේතය සම්පූර්ණයෙන්ම වෙනස් ලෙස වැඩ කිරීමට පටන් ගනී. මගේ මතය අනුව එකතු කිරීම වඩා හොඳය වෙන.

Fragment 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] නූල් සම්බන්ධ කර ඇති නමුත් ඒවා භාවිතා නොවේ. 'ප්‍රතිඵලය + "(ObjC පන්තිය)" + Name.str()' ප්‍රකාශනය පරීක්ෂා කිරීම සලකා බලන්න. Symbol.cpp 35
  • V655 [CWE-480] නූල් සම්බන්ධ කර ඇති නමුත් ඒවා භාවිතා නොවේ. 'ප්‍රතිඵලය + "(ObjC Class EH) " + Name.str()' ප්‍රකාශනය පරීක්ෂා කිරීම සලකා බලන්න. Symbol.cpp 38
  • V655 [CWE-480] නූල් සම්බන්ධ කර ඇති නමුත් ඒවා භාවිතා නොවේ. 'ප්‍රතිඵලය + "(ObjC IVar)" + Name.str()' ප්‍රකාශනය පරීක්ෂා කිරීම සලකා බලන්න. Symbol.cpp 41

අහම්බෙන්, += ක්‍රියාකරු වෙනුවට + ක්‍රියාකරු භාවිතා වේ. එහි ප්‍රතිඵලය වන්නේ තේරුමක් නැති නිර්මාණයි.

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

භයානක කේතය ඔබම සොයා ගැනීමට උත්සාහ කරන්න. පිළිතුර වහාම නොබලන ලෙස අවධානය වෙනතකට යොමු කිරීම සඳහා මෙය පින්තූරයකි:

PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM 8 හි දෝෂ සොයා ගැනීම

PVS-Studio අනතුරු ඇඟවීම: V708 [CWE-758] භයානක ඉදිකිරීම් භාවිතා වේ: 'FeaturesMap[Op] = FeaturesMap.size()', 'FeaturesMap' යනු 'සිතියම' පන්තියයි. මෙය නිර්වචනය නොකළ හැසිරීමකට හේතු විය හැක. RISCVCompressInstEmitter.cpp 490

ගැටළු රේඛාව:

FeaturesMap[Op] = FeaturesMap.size();

මූලද්රව්යය නම් Op හමු නොවේ, එවිට සිතියමේ නව මූලද්‍රව්‍යයක් සාදනු ලබන අතර මෙම සිතියමේ ඇති මූලද්‍රව්‍ය ගණන එහි ලියා ඇත. කාර්යය කැඳවනු ලබන්නේද යන්න නොදන්නා කරුණකි විශාලත්වය නව අංගයක් එකතු කිරීමට පෙර හෝ පසුව.

Fragment 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

Fragment 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] 'Alinment' විචල්‍යයට අනුපිළිවෙලින් දෙවරක් අගයන් පවරනු ලැබේ. සමහර විට මෙය වැරදීමක් විය හැකිය. පිරික්සුම් රේඛා: 1158, 1160. LoadStoreVectorizer.cpp 1160

මෙය පැහැදිලිවම තාර්කික දෝෂයක් අඩංගු ඉතා අමුතු කේතයකි. ආරම්භයේදී, විචල්ය මෙතැන් පටන්ය කොන්දේසිය අනුව අගයක් පවරනු ලැබේ. එවිට පැවරුම නැවතත් සිදු වේ, නමුත් දැන් කිසිදු පරීක්ෂාවකින් තොරව.

සමාන තත්වයන් මෙහි දැකිය හැකිය:

  • V519 [CWE-563] 'Effects' විචල්‍යයට අනුපිළිවෙලින් දෙවරක් අගයන් පවරනු ලැබේ. සමහර විට මෙය වැරදීමක් විය හැකිය. පිරික්සුම් රේඛා: 152, 165. WebAssemblyRegStackify.cpp 165
  • V519 [CWE-563] 'ExpectNoDerefChunk' විචල්‍යයට අනුපිළිවෙලින් දෙවරක් අගයන් පවරනු ලැබේ. සමහර විට මෙය වැරදීමක් විය හැකිය. පිරික්සුම් රේඛා: 4970, 4973. SemaType.cpp 4973

Fragment 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

පරීක්ෂා කිරීම තේරුමක් නැත. විචල්ය ඊළඟ බයිට් සෑම විටම වටිනාකමට සමාන නොවේ 0x90, එය පෙර චෙක්පතෙන් පහත දැක්වේ. මෙය එක්තරා ආකාරයක තාර්කික දෝෂයකි.

Fragment N29 - N...: සැමවිටම සත්‍ය/අසත්‍ය තත්ත්වයන්

විශ්ලේෂකය සමස්ත තත්ත්වය (අ) බවට බොහෝ අනතුරු ඇඟවීම් නිකුත් කරයි.V547) හෝ එහි කොටසක් (V560) සෑම විටම සත්‍ය හෝ අසත්‍ය වේ. බොහෝ විට මේවා සැබෑ දෝෂයන් නොවේ, නමුත් සරලව sloppy code, macro expansion හි ප්රතිඵලය සහ ඒ හා සමාන ය. කෙසේ වෙතත්, වරින් වර අව්‍යාජ තාර්කික දෝෂ ඇති වන බැවින් මෙම සියලු අනතුරු ඇඟවීම් දෙස බැලීම අර්ථවත් කරයි. උදාහරණයක් ලෙස, මෙම කේතයේ කොටස සැක සහිත ය:

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, එවිට ශ්රිතය එහි ක්රියාත්මක කිරීම සම්පූර්ණ කරනු ඇත.

V547 සහ V560 හැඳුනුම්පත් සමඟ තවත් බොහෝ අනතුරු ඇඟවීම් තිබුනා, නමුත් සමග V595, මම මෙම අනතුරු ඇඟවීම් අධ්‍යයනය කිරීමට උනන්දු නොවෙමි. ලිපියක් ලිවීමට ප්‍රමාණවත් ද්‍රව්‍ය මා සතුව ඇති බව දැනටමත් පැහැදිලි විය :). එබැවින්, PVS-Studio භාවිතයෙන් LLVM හි මෙම වර්ගයේ දෝෂ කීයක් හඳුනාගත හැකිද යන්න නොදනී.

මෙම ප්‍රේරක අධ්‍යයනය කිරීම නීරස වන්නේ මන්දැයි මම ඔබට උදාහරණයක් දෙන්නම්. පහත කේතය සඳහා අනතුරු ඇඟවීමක් නිකුත් කිරීමේදී විශ්ලේෂකය සම්පූර්ණයෙන්ම නිවැරදිය. නමුත් මෙය වරදක් නොවේ.

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

මෙය දෝෂයක් හෝ කේතයක් කියවන ක්‍රමලේඛකයින්ට යමක් පැහැදිලි කිරීමට අදහස් කරන විශේෂිත තාක්ෂණයකි. මෙම නිර්මාණය මට කිසිවක් පැහැදිලි නොකරන අතර ඉතා සැක සහිත ලෙස පෙනේ. එහෙම නොලියා ඉන්න එක හොඳයි :).

මහන්සිද? එවිට තේ හෝ කෝපි සෑදීමට කාලයයි.

PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM 8 හි දෝෂ සොයා ගැනීම

නව රෝග විනිශ්චය මගින් හඳුනාගත් දෝෂ

මම හිතන්නේ පැරණි රෝග විනිශ්චය ක්‍රියාත්මක කිරීම් 30 ක් ප්‍රමාණවත්. පසුව විශ්ලේෂකයේ දර්ශනය වූ නව රෝග විනිශ්චය සමඟ සොයාගත හැකි රසවත් දේවල් මොනවාදැයි අපි දැන් බලමු පෙර චෙක්පත්. මෙම කාලය තුළ, C++ විශ්ලේෂකය වෙත සමස්ත පොදු කාර්ය රෝග විනිශ්චය 66ක් එක් කරන ලදී.

Fragment 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 කවදාවත් නිෂ්කාශනය වෙන්නේ නැහැ.

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

ඇත්ත වශයෙන්ම, මෙම කේතය ළඟා විය නොහැක. සියලුම නඩු වල ස්විච්චය ක්රියාකරුගේ ඇමතුමකින් අවසන් වේ ආපසු. දැන් තේරුමක් නැති තනියම බිඳීම එතරම් හානිකර නොවන බව පෙනේ! සමහර විට එක් ශාඛාවක් අවසන් විය යුතුය බිඳීමක්‍රියාත්මක නොවේ ආපසු?

Fragment 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)

~(8u-1)

0xFFFFFFFF8u

දැන් එම විචල්‍යය බව සලකන්න දත්ත ප්රමාණය 64-bit අත්සන් නොකළ වර්ගයක් ඇත. DataSize & 0xFFFFFFF8u මෙහෙයුම සිදු කරන විට, ඉහළ පෙළේ බිටු තිස් දෙක ශුන්‍යයට යළි පිහිටුවනු ලැබේ. බොහෝ දුරට ඉඩ, මෙය ක්‍රමලේඛකයාට අවශ්‍ය නොවේ. ඔහුට ගණනය කිරීමට අවශ්‍ය වූ බව මම සැක කරමි: DataSize & 0xFFFFFFFFFFFFFFF8u.

දෝෂය නිවැරදි කිරීම සඳහා, ඔබ මෙය ලිවිය යුතුය:

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

එසේ නැතහොත් එසේ

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

Fragment 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-බිට් ප්‍රතිඵලය වර්ගයට විස්තීරණය වේ. size_t.

Fragment 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

මෙම නව රසවත් රෝග විනිශ්චය මඟින් කේත කැබැල්ලක් පිටපත් කර ඇති අතර එහි සමහර නම් වෙනස් කිරීමට පටන් ගෙන ඇති නමුත් එක් ස්ථානයක ඔවුන් එය නිවැරදි නොකළ අවස්ථා හඳුනා ගනී.

දෙවන කොටසේදී ඒවා වෙනස් වූ බව කරුණාවෙන් සලකන්න Op0 මත Op1. නමුත් එක තැනක ඔවුන් එය නිවැරදි කළේ නැත. බොහෝ දුරට එය මෙසේ ලියා තිබිය යුතුය:

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

Fragment 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

Functionargument වලට class Members ගේ නම් වලින්ම දෙන එක හරිම භයානකයි. ව්යාකූල වීම ඉතා පහසුයි. අප ඉදිරියේ ඇත්තේ එවැනි නඩුවක් පමණි. මෙම ප්රකාශනය තේරුමක් නැත:

Mode &= Mask;

කාර්යය තර්කය වෙනස් වේ. එච්චරයි. මෙම තර්කය තවදුරටත් භාවිතා නොවේ. බොහෝ විට ඔබ එය මෙසේ ලියා තිබිය යුතුය:

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

Fragment 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] 'ප්‍රමාණය' විචල්‍යය පවරා ඇති නමුත් ශ්‍රිතයේ අවසානය වන විට භාවිතා නොවේ. Object.cpp 424

තත්වය පෙර පැවති තත්වයට සමාන වේ. එය ලිවිය යුතුය:

this->Size += this->EntrySize;

Fragment 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

විචල්ය Ptr සමාන විය හැක 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

එවැනි දෝෂ වලින් ඔබව ආරක්ෂා කර ගන්නේ කෙසේද? කේත-සමාලෝචනය පිළිබඳ වඩාත් අවධානයෙන් සිටින්න සහ ඔබේ කේතය නිතිපතා පරීක්ෂා කිරීමට 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

Fragment 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] හිමිකරු නොමැති දර්ශකයක් 'Emplace_back' ක්‍රමය මගින් 'Strategies' කන්ටේනරයට එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. llvm-isel-fuzzer.cpp 58

වැනි කන්ටේනරයක කෙළවරට මූලද්‍රව්‍යයක් එක් කිරීමට std::දෛශිකය > ඔබට නිකම්ම ලියන්න බැහැ xxx.push_back(නව X), සිට ව්‍යංග පරිවර්තනයක් නොමැති බැවින් X* в std::unique_ptr.

පොදු විසඳුමක් ලිවීමයි xxx.emplace_back(නව X)එය සම්පාදනය කරන බැවින්: ක්රමය emplace_back තර්ක වලින් සෘජුවම මූලද්‍රව්‍යයක් ගොඩනඟයි, එබැවින් පැහැදිලි නිර්මාපක භාවිතා කළ හැක.

එය ආරක්ෂිත නොවේ. දෛශිකය පිරී තිබේ නම්, මතකය නැවත වෙන් කරනු ලැබේ. මතකය නැවත ස්ථානගත කිරීමේ මෙහෙයුම අසාර්ථක විය හැක, එහි ප්‍රතිඵලයක් ලෙස ව්‍යතිරේකයක් විසි වේ 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' ක්‍රමය මගින් 'Passes' බහාලුමට එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. PassManager.h 546
  • V1023 [CWE-460] හිමිකරු නොමැති දර්ශකයක් 'AMplace_back' ක්‍රමය මගින් 'AAs' කන්ටේනරයට එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. 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' ක්‍රමය මගින් 'Objects' කන්ටේනරය වෙත හිමිකරු නොමැති දර්ශකයක් එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. DebugMap.cpp 88
  • V1023 [CWE-460] හිමිකරු නොමැති දර්ශකයක් 'Emplace_back' ක්‍රමය මගින් 'Strategies' බහාලුමට එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. 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] හිමිකරු නොමැති දර්ශකයක් 'Operands' බහාලුමට 'emplace_back' ක්‍රමය මගින් එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. GlobalISelEmitter.cpp 1911
  • V1023 [CWE-460] 'emplace_back' ක්‍රමය මගින් 'Stash' කන්ටේනරය වෙත හිමිකරු නොමැති දර්ශකයක් එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. GlobalISelEmitter.cpp 2100
  • V1023 [CWE-460] හිමිකරු නොමැති දර්ශකයක් 'Matchers' කන්ටේනරයට 'emplace_back' ක්‍රමය මගින් එක් කෙරේ. ව්යතිරේකයක දී මතක කාන්දුවක් සිදුවනු ඇත. GlobalISelEmitter.cpp 2702

නිගමනය

මම සම්පූර්ණ අනතුරු ඇඟවීම් 60 ක් නිකුත් කර පසුව නතර කළෙමි. LLVM හි PVS-Studio විශ්ලේෂකය හඳුනා ගන්නා වෙනත් දෝෂ තිබේද? ඔව් මට තියනවා. කෙසේ වෙතත්, මම ලිපිය සඳහා කේත කොටස් ලියන විට, එය සවස හෝ බොහෝ විට රාත්‍රිය වූ අතර, එය දිනයක් ලෙස හැඳින්වීමට කාලය පැමිණ ඇති බව මම තීරණය කළෙමි.

ඔබට එය සිත්ගන්නාසුළු යැයි මම විශ්වාස කරන අතර PVS-Studio විශ්ලේෂකය උත්සාහ කිරීමට අවශ්‍ය වනු ඇත.

ඔබට විශ්ලේෂකය බාගත කර බිම් බෝම්බ ඉවත් කිරීමේ යතුර ලබා ගත හැකිය මෙම පිටුව.

වැදගත්ම දෙය නම්, ස්ථිතික විශ්ලේෂණය නිතිපතා භාවිතා කරන්න. එක් වරක් චෙක්පත්, ස්ථිතික විශ්ලේෂණ ක්‍රමවේදය ජනප්‍රිය කිරීම සඳහා අප විසින් සිදු කරන ලද අතර PVS-Studio යනු සාමාන්‍ය අවස්ථාවක් නොවේ.

ඔබගේ කේතයේ ගුණාත්මකභාවය සහ විශ්වසනීයත්වය වැඩිදියුණු කිරීමට වාසනාව!

PVS-Studio විශ්ලේෂකය භාවිතයෙන් LLVM 8 හි දෝෂ සොයා ගැනීම

ඔබට මෙම ලිපිය ඉංග්‍රීසි කතා කරන ප්‍රේක්ෂකයින් සමඟ බෙදා ගැනීමට අවශ්‍ය නම්, කරුණාකර පරිවර්තන සබැඳිය භාවිතා කරන්න: Andrey Karpov. PVS-Studio සමඟ LLVM 8 හි දෝෂ සෙවීම.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න