Bagaimana penganalisa PVS-Studio mulai menemukan lebih banyak kesalahan dalam proyek Unity

image1.png


Saat mengembangkan penganalisa statis PVS-Studio, kami mencoba mengembangkannya ke berbagai arah. Jadi, tim kami sedang mengerjakan plugin untuk IDE (Visual Studio, Rider), meningkatkan integrasi dengan CI, dll. Meningkatkan efisiensi analisis proyek untuk Unity juga merupakan salah satu tujuan prioritas kami. Kami percaya bahwa analisis statis akan memungkinkan pemrogram menggunakan mesin permainan ini untuk meningkatkan kualitas kode sumber mereka dan menyederhanakan pekerjaan di proyek apa pun. Oleh karena itu, saya ingin meningkatkan popularitas PVS-Studio di antara perusahaan yang mengembangkan Unity. Salah satu langkah pertama dalam implementasi ide ini adalah menulis anotasi untuk metode yang didefinisikan dalam mesin. Ini memungkinkan Anda untuk mengontrol kebenaran kode yang terkait dengan panggilan ke metode beranotasi.



pengantar



Anotasi adalah salah satu mekanisme analisa yang paling penting. Mereka memberikan berbagai informasi tentang argumen, nilai balik, dan fitur internal metode yang tidak dapat dipecahkan secara otomatis. Pada saat yang sama, pemrogram penjelasan dapat mengasumsikan perkiraan struktur internal dari metode dan spesifik operasinya, berdasarkan pada dokumentasi dan akal sehat.



Misalnya, memanggil metode GetComponent terlihat sedikit aneh jika nilai yang dikembalikannya tidak digunakan. Kesalahan omong kosong? Tidak semuanya. Tentu saja, ini mungkin hanya sebuah tantangan ekstra, dilupakan dan ditinggalkan oleh semua orang. Atau mungkin beberapa tugas penting tidak ada. Anotasi dapat membantu penganalisa menemukan kesalahan serupa dan banyak lainnya.



Tentu saja, kami telah menulis banyak anotasi untuk penganalisa. Sebagai contoh, metode kelas dari System namespace diberi penjelasan . Selain itu, ada juga mekanisme untuk anotasi otomatis dari beberapa metode. Anda dapat membaca lebih lanjut tentang ini di sini . Perhatikan bahwa artikel ini memberi tahu lebih banyak tentang bagian dari PVS-Studio yang bertanggung jawab untuk menganalisis proyek dalam C ++. Namun, tidak ada perbedaan nyata dalam cara kerja anotasi untuk C # dan C ++.



Menulis anotasi untuk metode Persatuan



Kami berusaha keras untuk meningkatkan kualitas tinjauan kode proyek yang menggunakan Unity, dan oleh karena itu diputuskan untuk menjelaskan metode mesin ini.



Gagasan asli adalah untuk mencakup semua metode Persatuan dengan anotasi secara umum, namun, ada banyak dari mereka. Sebagai hasilnya, kami memutuskan untuk memulai dengan menjelaskan metode dari kelas yang paling umum digunakan.



Pengumpulan informasi



Pertama, perlu untuk mengetahui kelas mana yang lebih sering digunakan daripada yang lain. Selain itu, aspek penting adalah kemampuan untuk mengumpulkan hasil anotasi - kesalahan baru yang akan ditemukan oleh penganalisa dalam proyek nyata berkat anotasi tertulis. Karena itu, langkah pertama adalah mencari proyek sumber terbuka yang sesuai. Namun, ini ternyata tidak mudah.



Masalahnya adalah bahwa banyak proyek yang ditemukan cukup kecil dalam hal kode sumber. Jika ada kesalahan seperti itu, maka jumlahnya tidak terlalu banyak, dan bahkan ada lebih sedikit peluang untuk menemukan pemicu yang terkait dengan metode dari Unity di sana. Terkadang ada proyek yang secara praktis tidak menggunakan (atau tidak menggunakan sama sekali) kelas khusus-Unity, meskipun menurut deskripsi mereka entah bagaimana terhubung dengan mesin. Temuan seperti itu sama sekali tidak cocok untuk tugas tersebut.



Tentu saja, kadang saya beruntung. Misalnya, permata dalam koleksi ini adalah MixedRealityToolkit . Sudah ada kode yang layak di dalamnya, yang berarti bahwa statistik yang dikumpulkan tentang penggunaan metode Persatuan dalam proyek semacam itu akan lebih lengkap.



Dengan demikian, 20 proyek direkrut menggunakan kemampuan mesin. Untuk menemukan kelas yang paling umum digunakan, utilitas berbasis Roslyn ditulis untuk menghitung panggilan metode dari Unity. Omong-omong, program semacam itu juga bisa disebut penganalisa statis. Lagipula, jika Anda memikirkannya, dia benar-benar menganalisis sumbernya tanpa harus meluncurkan proyek itu sendiri.



"Analisis" tertulis memungkinkan untuk menemukan kelas-kelas, frekuensi rata-rata penggunaan yang dalam proyek-proyek yang ditemukan adalah yang tertinggi:



  • UnityEngine.Vector3
  • UnityEngine.Mathf
  • UnityEngine.Debug
  • UnityEngine.GameObject
  • UnityEngine. Bahan
  • UnityEditor.EditorGUILayout
  • UnityEngine.Component
  • UnityEngine.Object
  • UnityEngine.GUILayout
  • UnityEngine.Quaternion
  • Dll


Tentu saja, ini tidak berarti bahwa kelas-kelas ini benar-benar sering digunakan oleh pengembang - setelah semua, statistik berdasarkan sampel proyek yang kecil tidak dapat diandalkan. Namun, untuk memulainya, informasi ini cukup untuk memastikan bahwa metode kelas yang digunakan di suatu tempat diberi catatan.



Anotasi



Setelah mendapatkan informasi yang Anda butuhkan, sekarang saatnya untuk memulai dengan anotasi yang sebenarnya. Dokumentasi dan editor Unity, tempat proyek uji coba dibuat , adalah pembantu yang setia dalam masalah ini . Ini diperlukan untuk memverifikasi beberapa poin yang tidak ditentukan dalam dokumentasi. Sebagai contoh, itu jauh dari selalu jelas apakah melewati nol dalam argumen apa pun akan menyebabkan kesalahan, atau apakah program akan terus berjalan tanpa masalah. Tentu saja, melewati null biasanya tidak terlalu baik, tetapi dalam kasus ini kami menganggap hanya kesalahan yang mengganggu aliran eksekusi, atau dicatat oleh editor Unity sebagai kesalahan.



Selama pemeriksaan tersebut, fitur menarik dari pekerjaan beberapa metode ditemukan. Misalnya, menjalankan kode



MeshRenderer renderer = cube.GetComponent<MeshRenderer>();
Material m = renderer.material;
List<int> outNames = null;
m.GetTexturePropertyNameIDs(outNames);


mengarah ke fakta bahwa editor Unity itu sendiri crash, meskipun biasanya dalam kasus seperti itu eksekusi skrip saat ini terputus dan kesalahan yang sesuai dicatat. Tentu saja, tidak mungkin pengembang sering menulis ini, tetapi fakta bahwa editor Unity dapat mengalami crash dengan menjalankan skrip biasa tidak terlalu baik. Hal yang sama terjadi pada setidaknya satu kasus lagi:



MeshRenderer renderer = cube.GetComponent<MeshRenderer>();
Material m = renderer.material;
string keyWord = null;
bool isEnabled = m.IsKeywordEnabled(keyWord);


Masalah yang ditunjukkan relevan untuk editor Unity 2019.3.10f1.



Mengumpulkan hasil



Setelah anotasi selesai, Anda perlu memeriksa bagaimana ini akan memengaruhi peringatan yang dihasilkan. Sebelum menambahkan anotasi untuk masing-masing proyek yang dipilih, log dengan kesalahan dihasilkan, yang kami sebut referensi. Kemudian anotasi baru dibangun ke dalam analisa dan proyek diperiksa ulang. Daftar peringatan yang dihasilkan, berkat anotasi, akan berbeda dari yang referensi.



Prosedur pengujian anotasi dilakukan secara otomatis menggunakan program CSharpAnalyserTester yang ditulis khusus untuk kebutuhan ini. Ini meluncurkan analisis pada proyek, setelah itu membandingkan log yang dihasilkan dengan yang referensi dan menghasilkan file yang berisi informasi tentang perbedaan.



Pendekatan yang dijelaskan juga digunakan untuk mencari tahu perubahan apa yang muncul pada log saat menambahkan yang baru atau mengubah diagnostik yang ada.



Seperti disebutkan sebelumnya, sulit untuk menemukan proyek open source besar untuk Unity. Ini tidak menyenangkan, karena bagi mereka penganalisa dapat menghasilkan respons yang lebih menarik. Pada saat yang sama, akan ada lebih banyak perbedaan antara log referensi dan log yang dihasilkan setelah anotasi.



Namun demikian, anotasi tertulis membantu mengidentifikasi beberapa momen mencurigakan dalam proyek yang sedang dipertimbangkan, yang juga merupakan hasil pekerjaan yang menyenangkan.



Misalnya, panggilan yang agak aneh ke GetComponent ditemukan :



void OnEnable()
{
  GameObject uiManager = GameObject.Find("UIRoot");

  if (uiManager)
  {
    uiManager.GetComponent<UIManager>();
  }
}


Peringatan Analyzer : V3010 Nilai kembali fungsi 'GetComponent' diperlukan untuk digunakan. - TAMBAHAN DI UIEditorWindow.cs LANCAR 22



Berdasarkan dokumentasi , logis untuk menyimpulkan bahwa nilai yang dikembalikan oleh metode ini entah bagaimana harus digunakan. Oleh karena itu, ketika dijelaskan, itu ditandai sesuai. Segera, hasil dari panggilan tersebut tidak ditugaskan untuk apa pun, yang terlihat agak aneh.



Dan di sini adalah contoh lain dari pemicu analisa tambahan:



public void ChangeLocalID(int newID)
{
  if (this.LocalPlayer == null)                          // <=
  {
    this.DebugReturn(
      DebugLevel.WARNING, 
      string.Format(
        ...., 
        this.LocalPlayer, 
        this.CurrentRoom.Players == null,                // <=
        newID  
      )
    );
  }

  if (this.CurrentRoom == null)                          // <=
  {
    this.LocalPlayer.ChangeLocalID(newID);               // <=
    this.LocalPlayer.RoomReference = null;
  }
  else
  {
    // remove old actorId from actor list
    this.CurrentRoom.RemovePlayer(this.LocalPlayer);

    // change to new actor/player ID
    this.LocalPlayer.ChangeLocalID(newID);

    // update the room's list with the new reference
    this.CurrentRoom.StorePlayer(this.LocalPlayer);
  }
}


Peringatan Analyzer :



  • V3095 Objek 'this.CurrentRoom' digunakan sebelum diverifikasi terhadap nol. Periksa baris: 1709, 1712. - TAMBAHAN DALAM SAAT INI LoadBalancingClient.cs 1709
  • V3125 Objek 'this.LocalPlayer' digunakan setelah diverifikasi terhadap null. Periksa baris: 1715, 1707. - TAMBAHAN DALAM SAAT INI LoadBalancingClient.cs 1715


Perhatikan bahwa PVS-Studio tidak memperhatikan lewat LocalPlayer ke string.Format , karena hal ini tidak akan menyebabkan kesalahan. Dan kodenya sepertinya sengaja ditulis.



Dalam hal ini, efek anotasi tidak begitu jelas. Namun, merekalah yang menyebabkan terjadinya hal-hal positif ini. Muncul pertanyaan - mengapa peringatan ini tidak ada sebelumnya?



Faktanya adalah bahwa beberapa panggilan dilakukan dalam metode DebugReturn , yang, secara teori, dapat mempengaruhi nilai properti CurrentRoom :



public virtual void DebugReturn(DebugLevel level, string message)
{
  #if !SUPPORTED_UNITY
  Debug.WriteLine(message);
  #else
  if (level == DebugLevel.ERROR)
  {
    Debug.LogError(message);
  }
  else if (level == DebugLevel.WARNING)
  {
    Debug.LogWarning(message);
  }
  else if (level == DebugLevel.INFO)
  {
    Debug.Log(message);
  }
  else if (level == DebugLevel.ALL)
  {
    Debug.Log(message);
  }
  #endif
}


Penganalisa tidak mengetahui kekhasan dari metode yang disebut, yang berarti bahwa tidak tahu bagaimana mereka akan mempengaruhi situasi. Jadi, PVS-Studio mengasumsikan bahwa nilai ini.CurrentRoom bisa saja berubah ketika metode DebugReturn berjalan , jadi pemeriksaan selanjutnya dilakukan.



Anotasi memberikan informasi bahwa metode yang disebut di dalam DebugReturn tidak akan memengaruhi nilai variabel lainnya. Oleh karena itu, menggunakan variabel sebelum memeriksa null dapat dianggap mencurigakan.



Kesimpulan



Ringkasnya, perlu dikatakan bahwa penjelasan metode khusus Unity, tanpa keraguan, akan memungkinkan menemukan lebih banyak kesalahan yang berbeda dalam proyek-proyek menggunakan mesin ini. Namun, cakupan anotasi dari semua metode yang tersedia akan memakan banyak waktu. Lebih efektif akan memberikan anotasi terutama yang paling umum digunakan. Namun, untuk memahami kelas mana yang lebih sering digunakan, Anda memerlukan proyek yang sesuai dengan basis kode yang besar. Selain itu, proyek-proyek besar memberi Anda kontrol yang lebih baik atas kinerja anotasi. Kami akan terus melakukan semua ini dalam waktu dekat.



Penganalisa terus berkembang dan disempurnakan. Menambahkan anotasi untuk metode Unity hanyalah salah satu contoh memperluas kemampuannya. Dengan demikian, seiring waktu, efisiensi PVS-Studio semakin meningkat. Karena itu, jika Anda belum mencoba PVS-Studio, sekarang saatnya untuk memperbaikinya dengan mengunduhnya dari halaman yang sesuai . Di sana Anda juga bisa mendapatkan kunci percobaan untuk penganalisa untuk berkenalan dengan kemampuannya dengan memeriksa berbagai proyek.





Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan terjemahan: Nikita Lipilin. Bagaimana penganalisa PVS-Studio mulai menemukan lebih banyak kesalahan dalam proyek Unity .



All Articles