PVS- स्टूडियो विश्लेषक RunUO चेक

चित्र 1

यह लेख PVS-Studio स्थिर विश्लेषक का उपयोग करके RunUO प्रोजेक्ट की जाँच करने के लिए समर्पित है। RunUO अल्टिमा ऑनलाइन के लिए एक सर्वर सॉफ्टवेयर एमुलेटर है, एक ऐसा गेम जिसने एक बार कई MMORPG प्रशंसकों का दिल जीत लिया।

परिचय


RunUO MMORPG अल्टिमा ऑनलाइन के लिए एक सर्वर सॉफ्टवेयर एमुलेटर है। इस परियोजना का लक्ष्य स्थिर सॉफ़्टवेयर बनाना है जो ईए गेम्स के आधिकारिक सर्वर के साथ प्रतिस्पर्धा करने में सक्षम होगा। RunUO 2002 में वापस बनाया गया था, लेकिन यह प्रासंगिकता नहीं खोता है और आज तक सक्रिय रूप से उपयोग किया जाता है।

परियोजना सत्यापन का उद्देश्य स्थैतिक विश्लेषण के विषय को लोकप्रिय बनाना है। हम विभिन्न परियोजनाओं की जाँच करते हैं - खेल ( उदाहरण ), पुस्तकालय ( उदाहरण ), संदेशवाहक ( उदाहरण ), ब्राउज़र ( उदाहरण ) और बहुत कुछ ( उदाहरण , उदाहरण , उदाहरण)) एक विविध दर्शकों का ध्यान आकर्षित करने के लिए। इन लेखों के साथ, हम विकास में स्थैतिक विश्लेषण का उपयोग करने के महत्व पर ध्यान आकर्षित करने की कोशिश कर रहे हैं। स्थैतिक विश्लेषण कोड को अधिक विश्वसनीय और सुरक्षित बनाता है। साथ ही, इसके नियमित उपयोग से, आप शुरुआती चरणों में त्रुटियों को पा सकते हैं और समाप्त कर सकते हैं। यह डेवलपर्स के समय और प्रयास को बचाता है, क्योंकि कोई भी उस त्रुटि की खोज में 50 घंटे बिताना नहीं चाहता है जो विश्लेषक पा सकता है।

हम खुले स्रोत वाले समुदाय की भी मदद करते हैं। त्रुटियों के साथ लेख के माध्यम से, हम ओपन-सोर्स के विकास में योगदान करते हैं। हालांकि, लेखों में हम सभी चेतावनियों का विश्लेषण नहीं करते हैं। कुछ चेतावनियाँ हमें लेख में आने के लिए बहुत उबाऊ लग रही थीं, कुछ झूठी सकारात्मकता की ओर ले गईं, आदि। इसलिए, हम ओपन सोर्स प्रोजेक्ट के लिए मुफ्त लाइसेंस देने के लिए तैयार हैं इसके अलावा, जो हमें लेख के लिए उबाऊ लग रहा था वह परियोजना के डेवलपर्स के लिए काफी दिलचस्प लग सकता है, क्योंकि परियोजना के डेवलपर्स अभी भी अधिक जागरूक हैं कि कौन सी समस्याएं सबसे महत्वपूर्ण हैं।

कोड के टुकड़े जिन्होंने विश्लेषक की रिपोर्ट की जांच करते समय ध्यान आकर्षित किया


PVS- स्टूडियो चेतावनी: V3010 फ़ंक्शन 'इंटर्न' के रिटर्न मान का उपयोग किया जाना आवश्यक है। BasePaintedMask.cs 49

public static string Intern( string str )
{
  if ( str == null )
    return null;
  else if ( str.Length == 0 )
    return String.Empty;

  return String.Intern( str );
}

public BasePaintedMask( string staffer, int itemid )
                            : base( itemid + Utility.Random( 2 ) )
{
  m_Staffer = staffer;

  Utility.Intern( m_Staffer );
}

इंटर्न () विधि का रिटर्न मूल्य कहीं भी खाते में नहीं लिया जाता है, जैसा कि विश्लेषक द्वारा इंगित किया गया है। शायद यह एक बग या निरर्थक कोड है।

PVS-Studio चेतावनी: V3017 एक पैटर्न का पता लगाया गया था: (आइटम BasePotion है) || ((आइटम BasePotion है) और& ...)। अभिव्यक्ति अत्यधिक है या तार्किक त्रुटि है। क्लीनअप .cs 137

public static bool IsBuggable( Item item )
{
  if ( item is Fists )
    return false;

  if ( item is ICommodity || item is Multis.BaseBoat
    || item is Fish || item is BigFish
    || item is BasePotion || item is Food || item is CookableFood
    || item is SpecialFishingNet || item is BaseMagicFish
    || item is Shoes || item is Sandals
    || item is Boots || item is ThighBoots
    || item is TreasureMap || item is MessageInABottle
    || item is BaseArmor || item is BaseWeapon
    || item is BaseClothing
    || ( item is BaseJewel && Core.AOS )
    || ( item is BasePotion && Core.ML )
  {
    ....
  }
}

ऐसे सबएक्सप्रेस हैं जिन्हें सरल बनाया जा सकता है। मैं उन्हें बाहर लिखूंगा ताकि यह अधिक स्पष्ट हो:
if (item is BasePotion || ( item is BasePotion && Core.ML ))

मान लीजिए, आइटम BasePotion = to true है , तो Core.ML के बावजूद स्थिति सही है यदि आइटम BasePotion = to false है , तो स्थिति झूठी है, फिर भी मान Core.ML की परवाह किए बिना इस तरह के कोड सबसे अधिक बार बेमानी होते हैं, लेकिन इससे भी बदतर हालात होते हैं जब प्रोग्रामर ने एक गलती की और दूसरे कंपकंपी में गलत चर लिखा।

PVS-Studio चेतावनी: V3031 एक अत्यधिक जाँच को सरल बनाया जा सकता है। '' '' ऑपरेटर विपरीत भावों 'bPlayerOnly' और 'bPlayerOnly' से घिरा हुआ है। BaseCreature.cs 3005

public virtual double GetFightModeRanking( Mobile m,
                                           FightMode acqType,
                                           bool bPlayerOnly )
{
  if ( ( bPlayerOnly && m.Player ) ||  !bPlayerOnly )
  {
    ....
  }
  ....
}

यह कोड अनावश्यक या गलत है। उसकी समस्या यह है कि दोनों तरफ '|| सब-डेप्रिसिएशन के अर्थ में भिन्न हैं। अगर हम इसे इस तरह से काटें:

if ( m.Player || !bPlayerOnly )

तब कुछ भी नहीं बदलेगा।

PVS-Studio चेतावनी: V3001 समान उप-अभिव्यक्तियाँ हैं 'डीड है SmallBrickHouseDeed' बाईं और दाईं ओर '' || ऑपरेटर। RealEstateBroker.cs 132

public int ComputePriceFor( HouseDeed deed )
{
  int price = 0;

  if ( deed is SmallBrickHouseDeed ||    // <=
       deed is StonePlasterHouseDeed ||
       deed is FieldStoneHouseDeed ||
       deed is SmallBrickHouseDeed ||    // <=
       deed is WoodHouseDeed ||
       deed is WoodPlasterHouseDeed ||
       deed is ThatchedRoofCottageDeed )
      ....
}

मुझे लगता है कि यहाँ, अगले या गलत, या अनावश्यक कोड के बारे में कुछ भी समझाना सार्थक नहीं है।

PVS-Studio चेतावनी: V3067 यह संभव है कि 'और' ब्लॉक को भूल गया या टिप्पणी नहीं की गई, इस प्रकार कार्यक्रम के संचालन लॉगिक्स को बदल दिया गया। बेसहोस.के 1558

private void SetLockdown( Item i, bool locked, bool checkContains )
{
  if ( m_LockDowns == null )
    return;

  #region Mondain's Legacy
  if ( i is BaseAddonContainer )
    i.Movable = false;
  else
  #endregion

  i.Movable = !locked;
  i.IsLockedDown = locked;

  ....
}

काफी दुर्लभ चेतावनी। एनालाइज़र को #endregion निर्देश के बाद कोड फ़ॉर्मेटिंग का संदेह था यदि आप कोड नहीं पढ़ते हैं, तो यह एक लाइन की तरह दिखता है

i.Movable = !locked;

किसी भी मामले में क्रियान्वित किया जाएगा, भले ही चर iशायद घुंघराले ब्रेसिज़ यहां भूल गए थे ... सामान्य तौर पर, डेवलपर्स को इस कोड की जांच करनी चाहिए।

पीवीएस-स्टूडियो चेतावनी: V3043 कोड का परिचालन तर्क इसके प्रारूपण के अनुरूप नहीं है। कथन सही के लिए प्रेरित है, लेकिन इसे हमेशा निष्पादित किया जाता है। यह संभव है कि घुंघराले कोष्ठक गायब हैं। भूकंप ।cs 57

public override void OnCast()
{
  if ( Core.AOS )
  {
    damage = m.Hits / 2;

    if ( !m.Player )
      damage = Math.Max( Math.Min( damage, 100 ), 15 );
      damage += Utility.RandomMinMax( 0, 15 );            // <=

  }
  else
  {
    ....
  }
}

इस कोड में घुंघराले ब्रेसिज़ गायब हो सकते हैं। यह निष्कर्ष शरीर के कोड के अजीब स्वरूपण के कारण बनाया जा सकता है अगर (! M.Payer)

PVS-Studio चेतावनी: V3083 इवेंट 'ServerStarted' का असुरक्षित मंगलाचरण, NullReferenceException संभव है। इसे लागू करने से पहले एक स्थानीय चर को घटना असाइन करने पर विचार करें। EventSink.cs 921

public static void InvokeServerStarted()
{
  if ( ServerStarted != null )
    ServerStarted();
}

यह विधि RefreshStarted ईवेंट हैंडलर के लिए संभावित असुरक्षित कॉल का उपयोग करती है , जैसा कि विश्लेषक इंगित करता है।

यह खतरनाक क्यों है? इस स्थिति की कल्पना करें। ServerStarted ईवेंट में केवल एक ग्राहक है। और इस समय null के लिए जाँच करने और सीधे दूसरे धागे में ServerStarted () ईवेंट हैंडलर को कॉल करने के बीच , इस ईवेंट से एक सदस्यता समाप्त कर दी गई थी। यह एक NullReferenceException को फेंक देगा

इस स्थिति को रोकने का सबसे आसान तरीका है ''? '' संचालक का उपयोग करके एक सुरक्षित ईवेंट कॉल प्रदान करना।

public static void InvokeServerStarted()
{
  ServerStarted?.Invoke();
}

पीवीएस-स्टूडियो चेतावनी: V3054 संभावित रूप से असुरक्षित डबल-चेकिंग लॉकिंग। इससे बचने के लिए वाष्पशील चर (ओं) या सिंक्रोनाइज़ेशन प्राइमेटिव का उपयोग करें। आइटम .cs 1624
private Packet m_RemovePacket;
....
private object _rpl = new object();
public Packet RemovePacket
{
  get
  {
    if (m_RemovePacket == null)
    {
      lock (_rpl)
      {
        if (m_RemovePacket == null)
        {
          m_RemovePacket = new RemoveItem(this);
          m_RemovePacket.SetStatic();
        }
      }
    }

    return m_RemovePacket;
  }
}

विश्लेषक चेतावनी डबल चेक किए गए लॉकिंग पैटर्न के असुरक्षित उपयोग से जुड़ा हुआ है। जैसा कि आप ऊपर दिए गए कोड से देख सकते हैं, जेनरेटरी पैटर्न - लोनर्स को लागू करने के लिए एक डबल-चेक लॉक लगाया गया था। जब हम RemovePacket प्रॉपर्टी तक पहुंचकर पैकेट वर्ग का एक उदाहरण प्राप्त करने का प्रयास करते हैं , तो गेटर शून्य के लिए समानता के लिए m_RemovePacket फ़ील्ड की जांच करता है। यदि चेक पास हो जाता है, तो हम लॉक स्टेटमेंट के शरीर में पहुंच जाते हैं , जहां m_RemovePacket फ़ील्ड को इनिशियलाइज़ किया जाता है । एक दिलचस्प स्थिति उस समय पैदा होती है जब मुख्य धागा ने पहले से ही निर्माण के माध्यम से m_RemovePacket चर को इनिशियलाइज़ किया है , लेकिन अभी तक विधि को नहीं बुलाया हैसेटस्टैटिक ()। सैद्धांतिक रूप से, एक और धागा बहुत असुविधाजनक क्षण पर RemovePacket संपत्ति तक पहुंच सकता है शून्य के लिए समानता के लिए m_RemovePacket की जाँच करना अब विफल नहीं होगा, और कॉलिंग थ्रेड को अपूर्ण तैयार-टू- यूज़ ऑब्जेक्ट का लिंक प्राप्त होगा। इस समस्या को हल करने के लिए, आप लॉक स्टेटमेंट के बॉडी में पैकेट क्लास का एक इंटरमीडिएट वैरिएबल बना सकते हैं , इसे कंस्ट्रक्टर कॉल और सेटस्टैटिक () विधि के माध्यम से इनिशियलाइज़ कर सकते हैं , और फिर इसे m_RemovePacker वेरिएबल में असाइन कर सकते हैं । इस मामले में, लॉक स्टेटमेंट की बॉडी इस तरह दिख सकती है:

lock (_rpl)
{
  if (m_RemovePacket == null)
  {
    Packet instance = new RemoveItem(this);
    instance.SetStatic();
    m_RemovePacket = instance;
  }
}

समस्या तय हो गई है और कोड उम्मीद के मुताबिक काम करेगा। लेकिन यह ऐसा नहीं है।

एक और बिंदु है: विश्लेषक केवल अस्थिर कीवर्ड का उपयोग करने का सुझाव नहीं देता है । प्रोग्राम के रिलीज़ संस्करण में, कंपाइलर ऑप्टिमाइज़ कर सकता है और कॉल की पंक्तियों को सेटस्टैटिक () विधि से पुन: व्यवस्थित कर सकता है और उदाहरण चर को m_RemovePacket फ़ील्ड (संकलक के दृष्टिकोण से, कार्यक्रम के शब्दार्थों का उल्लंघन नहीं किया जाएगा) को असाइन करेगा। और हम फिर से उसी बिंदु पर लौटते हैं जहां हमने शुरू किया था - अन-इनिशियलाइज्ड वेरिएबल m_RemovePacket प्राप्त करने की संभावना। यह वास्तव में कहना असंभव है कि यह पुन: व्यवस्थित कब हो सकता है, और क्या यह बिल्कुल भी होगा: यह सीएलआर संस्करण, उपयोग किए गए प्रोसेसर की वास्तुकला, आदि से प्रभावित हो सकता है। यह अभी भी इस तरह के परिदृश्य से बचाने के लायक है, और समाधान में से एक (हालांकि, सबसे अधिक उत्पादक नहीं) अस्थिर कीवर्ड का उपयोग करना होगा । एक वैरिएबल जिसे वाष्पशील संशोधक के साथ घोषित किया जाएगा, संकलक द्वारा अनुकूलन के दौरान क्रमपरिवर्तन के अधीन नहीं होगा। अंत में एक निश्चित कोड इस तरह दिख सकता है:

private volatile Packet m_RemovePacket;
....
private object _rpl = new object();
public Packet RemovePacket
{
  get
  {
    if (m_RemovePacket == null)
    {
      lock (_rpl)
      {
        if (m_RemovePacket == null)
        {
          Packet instance = new RemoveItem(this);
          instance.SetStatic();
          m_RemovePacket = instance;
        }
      }
    }

    return m_RemovePacket;
  }
}

कभी-कभी ऐसे क्षेत्र तक पहुँचने के ओवरहेड के कारण एक अस्थिर क्षेत्र का उपयोग करना अवांछनीय हो सकता है। हम इस विषय पर विस्तार से ध्यान नहीं देंगे, केवल यह देखते हुए कि उदाहरण में, विचाराधीन परमाणु क्षेत्र के रिकॉर्ड की आवश्यकता केवल एक बार (जब संपत्ति पहली बार पहुंची हो), हालांकि, क्षेत्र को अस्थिर घोषित करने से कंपाइलर को अपने परमाणु पढ़ने और लिखने का कारण होगा। प्रदर्शन के मामले में यह इष्टतम नहीं हो सकता है।

इसलिए, इस विश्लेषक की चेतावनी को सही करने के लिए एक और तरीका जो अतिरिक्त क्षेत्र को एक अस्थिर क्षेत्र घोषित करने से बचने के लिए है, वह है Lazy <T> प्रकार का उपयोग करने के लिए m_RemovePacket फ़ील्ड का समर्थन करना।बजाय डबल चेक लॉकिंग के। इस मामले में, गेटर बॉडी को इनिशलाइज़र विधि द्वारा प्रतिस्थापित किया जा सकता है, जो कि आलसी <<> उदाहरण के निर्माणकर्ता को दिया जाएगा :

private Lazy<Packet> m_RemovePacket = new Lazy<Packet>(() =>
  {
    Packet instance = new RemoveItem(this);
    instance.SetStatic();
    return instance;
  }, LazyThreadSafetyMode.ExecutionAndPublication);

....
public Packet RemovePacket
{
  get
  {
    return m_RemovePacket.Value;
  }
}

प्रारंभिक विधि को एक बार बुलाया जाएगा, जब पहली बार आलसी प्रकार तक पहुँचा जाता है, और एक ही समय में कई थ्रेड्स से संपत्ति तक पहुंचने के मामले में स्ट्रीमिंग सुरक्षा की गारंटी आलसी <टी> प्रकार (थ्रेड सुरक्षा मोड आलसी निर्माता के दूसरे पैरामीटर द्वारा नियंत्रित होती है) द्वारा की जाएगी

PVS-Studio चेतावनी: V3131 'IAxe' प्रकार के साथ संगतता के लिए 'लक्षित' अभिव्यक्ति की जाँच की जाती है, लेकिन 'आइटम' प्रकार में डाली जाती है। HarvestTarget.cs 61

protected override void OnTarget( Mobile from, object targeted )
{
  ....
  else if ( m_System is Lumberjacking &&
            targeted is IAxe && m_Tool is BaseAxe )
  {
    IAxe obj = (IAxe)targeted;
    Item item = (Item)targeted;
    ....
  }
  ....
}

IAxe टाइप करने के लिए लक्षित चर की जाँच की गई थी , लेकिन किसी ने भी आइटम से संबंधित किसी भी चीज़ की जाँच नहीं की, जैसा कि विश्लेषक रिपोर्ट करते हैं। PVS-Studio चेतावनी: 'm_LastMobile' वैरिएबल को प्रारंभ करते समय V3070 Uninitialized चर 'शून्य' का उपयोग किया जाता है। क्रमिक। 29


public struct Serial : IComparable, IComparable<Serial>
{
  private int m_Serial;

  private static Serial m_LastMobile = Zero;                // <=
  private static Serial m_LastItem = 0x40000000;

  public static Serial LastMobile { .... }
  public static Serial LastItem { .... }

  public static readonly Serial MinusOne = new Serial( -1 );
  public static readonly Serial Zero = new Serial( 0 );     // <=
  ....
  private Serial( int serial )
  {
    m_Serial = serial;
  }
  ....
}

जैसे, यहाँ कोई गलती नहीं है, हालाँकि, यह लिखना बहुत अच्छा नहीं है। Uninitialized जीरो के मान को m_LastMobile के असाइनमेंट के कारण , डिफॉल्ट कंस्ट्रक्टर सीरियल () के साथ एक स्ट्रक्चर बनाया जाएगा, जो m_Serial = 0 के इनिशियलाइजेशन को बढ़ावा देगा । और यह, बदले में, नए सीरियल (0) को कॉल करने के बराबर है । वास्तव में, डेवलपर्स भाग्यशाली हैं कि धारावाहिक 0 के बराबर होना चाहिए , अगर कोई अन्य मूल्य होना चाहिए था, तो यह एक त्रुटि का कारण होगा।

पीवीएस-स्टूडियो चेतावनी: V3063 सशर्त अभिव्यक्ति का एक हिस्सा हमेशा सही होता है यदि इसका मूल्यांकन किया जाता है: m_Serial <= 0x7FFFFFFF। धारावाहिक। 83३

public bool IsItem
{
  get
  {
    return ( m_Serial >= 0x40000000 && m_Serial <= 0x7FFFFFFF );
  }
}

0x7FFFFFFF अधिकतम संभव मान है जो Int32 में हो सकता है इसलिए, m_Serial चर का जो भी मूल्य है , वह किसी भी स्थिति में 0x7FFFFFFF से कम या बराबर होगा

PVS-Studio चेतावनी: V3004 'तत्कालीन' कथन 'और' कथन के बराबर है। क्रमांकन। 1571

public override void WriteDeltaTime( DateTime value )
{
  ....
  try 
  { 
    d = new TimeSpan( ticks-now ); 
  }
  catch 
  {
    if( ticks < now ) 
      d = TimeSpan.MaxValue; 
    else 
      d = TimeSpan.MaxValue;
  }
  ....
}

एनालाइज़र कोड के एक संदिग्ध टुकड़े के बारे में चेतावनी देता है जिसमें इफ स्टेटमेंट की सच्ची और झूठी शाखाएं पूरी तरह से मेल खाती हैं। शायद शाखाओं में से एक के पास TimeSpan.MinValue होना चाहिए एक ही कोड कई स्थानों पर पाया गया:

V3004 'तत्कालीन' कथन 'और' कथन के बराबर है। आइटम .cs 2103

public virtual void Serialize( GenericWriter writer )
{
  ....
  
  if( ticks < now ) 
    d = TimeSpan.MaxValue; 
  else 
    d = TimeSpan.MaxValue;
  
  ....
}

V3004 'तत्कालीन' कथन 'और' कथन के बराबर है। क्रमांकन। 383

public override void WriteDeltaTime( DateTime value )
{
  ....
  
  if( ticks < now ) 
    d = TimeSpan.MaxValue; 
  else 
    d = TimeSpan.MaxValue;
  
  ....
}

मैंने एक कारण के लिए "इस" का उपयोग किया, यह बहुत संभावना है कि, अन्य बातों के अलावा, यह कॉपी-पेस्ट के बिना नहीं कर सकता था, ये कोड टुकड़े बहुत दर्दनाक लगते हैं।

चेतावनी PVS-Studio: V3051 एक अत्यधिक प्रकार की कास्ट। ऑब्जेक्ट पहले से ही 'आइटम' प्रकार का है। मोबाइल .cs 11237

public Item Talisman
{
  get
  {
    return FindItemOnLayer( Layer.Talisman ) as Item;
  }
}
public Item FindItemOnLayer( Layer layer )
{
  ....
}

अगर वहाँ के अत्यधिक उपयोग है इस विश्लेषक चेतावनी प्राप्त किया जा सकता के रूप में ऑपरेटर कोड के इस भाग में कोई त्रुटि नहीं है, लेकिन यह ऑब्जेक्ट को अपने प्रकार में डालने का भी कोई मतलब नहीं है। PVS-

स्टूडियो चेतावनी : V3148 कास्टिंग 'संभावित' अशक्त 'मान' का मान एक प्रकार के लिए 'NullReferenceException' को जन्म दे सकता है। गुण .cs 502

public static string ConstructFromString( .... )
{
  object toSet;
  bool isSerial = IsSerial( type );

  if ( isSerial ) // mutate into int32
    type = m_NumericTypes[4];

  ....
  else if ( value == null )
  {
    toSet = null;
  }
  ....

  if ( isSerial ) // mutate back
    toSet = (Serial)((Int32)toSet);

  constructed = toSet;
  return null;
}

कोड के इस खंड में, हम मामले में रुचि रखने वाले कर रहे हैं जब चर मूल्य है अशक्तफिर सेटट चर भी शून्य हैइसके अलावा, यदि वैरिएबल सेरिअल == सत्य है , तो इंसेट को Int32 में डाला जाता है , जो NRE को ले जाएगा

आप इस कोड को जोड़कर ठीक कर सकते हैं, उदाहरण के लिए, डिफ़ॉल्ट रूप से 0:

toSet = (Serial)((Int32)(toSet ?? 0));

PVS-Studio चेतावनी: V3031 एक अत्यधिक जाँच को सरल बनाया जा सकता है। '' '' ऑपरेटर विपरीत भावों 'pack == null' और 'pack! = null' से घिरा होता है। BODBuyGump.cs 64
public override void OnResponse(Server.Network.NetState sender, RelayInfo info)
{
  ....
  if ( (pack == null) ||
       ((pack != null) &&
        (!pack.CheckHold(
                m_From,
                item,
                true,
                true,
                0,
                item.PileWeight + item.TotalWeight)) ) )
  {
    pv.SayTo(m_From, 503204);
    m_From.SendGump(new BOBGump(m_From, m_Book, m_Page, null));
  }
  ....
}

इस कोड को सरलीकृत किया जा सकता है, क्योंकि विश्लेषक रिपोर्ट करते हैं:

if ((pack == null) || ((pack != null) && (!pack.CheckHold(....))))

ऑपरेटर के बाईं और दाईं ओर '|| ऐसे भाव हैं जो अर्थ में विपरीत हैं। यहाँ चेक पैक! = अशक्त निरर्थक है, क्योंकि इससे पहले विपरीत स्थिति पैक == नल की जाँच की जाती है , और इन अभिव्यक्तियों को ऑपरेटर द्वारा अलग किया जाता है '||' इस लाइन को निम्न प्रकार से छोटा किया जा सकता है:

if (pack == null || !pack.CheckHold(....))

पीवीएस-स्टूडियो चेतावनी: V3080 संभावित अशक्तता। 'विजेता' का निरीक्षण करने पर विचार करें। CTF.cs 1302

private void Finish_Callback()
{
  ....
  CTFTeamInfo winner = ( teams.Count > 0 ? teams[0] : null );

  .... 

  m_Context.Finish( m_Context.Participants[winner.TeamID] as Participant );
}

चलो का कहना है कि teams.Count है 0 । फिर विजेता = अशक्त। और कोड में आगे, विजेताTIDID संपत्ति को शून्य के लिए जाँच किए बिना एक्सेस किया जाता है , जिसके परिणामस्वरूप एक शून्य संदर्भ द्वारा एक्सेस किया जाएगा।

PVS-Studio चेतावनी: V3041 अभिव्यक्ति को 'int' प्रकार से 'डबल' प्रकार में डाला गया था। एक आंशिक भाग के नुकसान से बचने के लिए एक स्पष्ट प्रकार के कलाकारों का उपयोग करने पर विचार करें। एक उदाहरण: डबल ए = (डबल) (एक्स) / वाई ;; स्टॉर्मसिए.के। 87

public static void Gain( Mobile from, Skill skill ) 
{
  ....
  if ( from.Player && 
     ( skills.Total / skills.Cap ) >= Utility.RandomDouble())
  ....
}

इस कोड के टुकड़े में वैरिएबल स्किल्स को विभाजित करने का ऑपरेशन शामिल है। तकनीकी और स्किल्स। कैप , जो कि टाइप इंट के होते हैं , और फिर परिणाम को स्पष्ट रूप से टाइप डबल में बदल दिया जाता है।

PVS-Studio चेतावनी: V3085 नेस्टेड प्रकार में 'typeofObject' फ़ील्ड का नाम अस्पष्ट है। बाहरी प्रकार में समरूप क्षेत्र समरूप नाम के साथ होता है। PropsGump.cs 744

private static Type typeofObject = typeof( object );
....
private class GroupComparer : IComparer
{
  ....
  private static Type typeofObject = typeof( Object );
  ....
}

नेस्टेड क्लास में कोड के इस सेक्शन में वेरिएबल टाइपऑफबजेक्ट बनाया गया था । इसकी समस्या यह है कि बाहरी वर्ग में एक ही नाम के साथ एक चर है, और इसके कारण त्रुटियां हो सकती हैं। इनटेशन के कारण ऐसी त्रुटियों की संभावना को कम करने के लिए इसे अनुमति नहीं देना बेहतर है।

PVS-Studio चेतावनी: V3140 प्रॉपर्टी एक्सेसर्स विभिन्न बैकिंग फ़ील्ड का उपयोग करते हैं। WallBanner.cs 77

private bool m_IsRewardItem;

[CommandProperty( AccessLevel.GameMaster )]
public bool IsRewardItem
{
  get{ return m_IsRewardItem; }
  set{ m_IsRewardItem = value; InvalidateProperties(); }
}

private bool m_East;

[CommandProperty( AccessLevel.GameMaster )]
public bool East
{
  get{ return m_East; }
  set{ m_IsRewardItem = value; InvalidateProperties(); }
}

और यहाँ एक गलती है जो कॉपी-पेस्ट के कारण दिखाई देती है। पूर्व संपत्ति का सेट एक्सेस तरीका m_East के लिए मान निर्दिष्ट करना था , m_IsRewardItem नहीं PVS-Studio चेतावनियाँ : V3012 '?:' संचालक, चाहे उसकी सशर्त अभिव्यक्ति हो, हमेशा एक और एक ही मूल्य देता है: 0xe7f। ट्रेजरचैस्टवेल 2.cs 52 V3012 '?:' संचालक, चाहे उसकी सशर्त अभिव्यक्ति की परवाह किए बिना, हमेशा एक और एक ही मूल्य देता है: 0xe77। ट्रेजरचैस्टवेल 2.के 57







private void SetChestAppearance()
{
  bool UseFirstItemId = Utility.RandomBool();

  switch( Utility.RandomList( 0, 1, 2, 3, 4, 5, 6, 7 ) )
  {
    ....
    case 6:// Keg
      this.ItemID = ( UseFirstItemId ? 0xe7f : 0xe7f );
      this.GumpID = 0x3e;
      break;

    case 7:// Barrel
      this.ItemID = ( UseFirstItemId ? 0xe77 : 0xe77 );
      this.GumpID = 0x3e;
      break;
  }
}

पसंद का :) का मूल्य की परवाह किए बिना भ्रम के कुछ प्रकार UseFirstItemId , this.ItemID या तो हो जाएगा 0xe7f पहले मामले में, या 0xe77 दूसरे में।

चेतावनी PVS-Studio: V3066 संभावित गलत आदेश 'OnSwing' विधि: 'डिफेंडर' और 'हमलावर' को पारित किए गए। BaseWeapon.cs 1188

public virtual int AbsorbDamageAOS( Mobile attacker,
                                    Mobile defender,
                                    int damage )
{
  ....
  if ( weapon != null )
  {
    defender.FixedParticles(0x3779,
                            1,
                            15,
                            0x158B,
                            0x0,
                            0x3,
                            EffectLayer.Waist);
    weapon.OnSwing( defender, attacker );
  }
  ....
}

public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender )
{
  return OnSwing( attacker, defender, 1.0 );
}

विश्लेषक को यह संदेहास्पद लगा कि OnSwing () विधि को उल्टे क्रम में तर्क दिया गया था शायद यह किसी त्रुटि के कारण है।

पीवीएस-स्टूडियो चेतावनी: सशर्त अभिव्यक्तियों के भीतर V3092 रेंज चौराहे संभव हैं। उदाहरण: अगर (A> 0 && A <5) {...} और यदि (A> 3 && A <9) {...}। हाउसफाउंडेशन। 1883

public static bool IsFixture( int itemID )
{
  ....
  else if( itemID >= 0x319C && itemID < 0x31B0 ) 
    return true;
  // ML doors
  else if( itemID == 0x2D46 ||
           itemID == 0x2D48 ||
           itemID == 0x2FE2 ||
           itemID == 0x2FE4 )
    return true;
  else if( itemID >= 0x2D63 && itemID < 0x2D70 )
    return true;
  else if( itemID >= 0x319C && itemID < 0x31AF ) 
    return true;
  ....
}

परिस्थतियों को अन्तर्विरोधों के तहत परखा गया। यह विश्लेषक को संदिग्ध लग रहा था। यहां तक ​​कि अगर यह कोड का टुकड़ा सही ढंग से काम करता है, तो भी इसे ठीक करने के लायक है। एक ऐसी स्थिति की कल्पना करें जहां हमें आखिरी के शरीर को फिर से लिखने की आवश्यकता थी यदि ऐसा है, तो यदि स्थिति सही है, तो विधि झूठी हैयदि Itemid है बराबर करने के लिए, कहते हैं, 0x319C , पद्धति अभी भी वापस आ जाएगी सचयह, बदले में, त्रुटियों की खोज करने के लिए समय की हानि को पूरा करेगा।

निष्कर्ष


RunUO एक लंबे समय से पहले बनाया गया था, बहुत सारे काम किए गए हैं, हालांकि, इस परियोजना के उदाहरण का उपयोग करके आप इतिहास के साथ परियोजनाओं पर स्थैतिक विश्लेषण का उपयोग करने के लाभ देख सकते हैं। प्रोजेक्ट कोड की 543 हजार लाइनों के लिए विश्लेषक ने लगभग 500 चेतावनियां ( निम्न स्तर की गिनती नहीं ) जारी कीं , जिनमें से अधिकांश अपनी एकरूपता के कारण लेख में दिखाई नहीं दिए। अधिक विस्तार से विश्लेषण के परिणाम से परिचित होने के लिए, मैं खुले स्रोत परियोजनाओं के लिए एक मुफ्त लाइसेंस का उपयोग करने का सुझाव देता हूं



यदि आप इस लेख को अंग्रेजी बोलने वाले दर्शकों के साथ साझा करना चाहते हैं, तो कृपया अनुवाद के लिंक का उपयोग करें: एकातेरिना निकिफोरोवा। PVU-Studio विश्लेषक द्वारा RunUO चेक

Source: https://habr.com/ru/post/undefined/


All Articles