DeepCode: tampilan samping

Gambar 1

Belum lama berselang, DeepCode, penganalisa statis berbasis pembelajaran mesin, mulai mendukung validasi proyek C dan C ++. Dan sekarang kita dapat melihat dalam praktek bagaimana hasil analisis statis klasik dan analisis statis berdasarkan pembelajaran mesin berbeda.

Kami telah menyebutkan DeepCode dalam artikel kami " Menggunakan Machine Learning dalam Analisis Statis dari Kode Sumber Program ." Dan segera mereka menerbitkan artikel " DeepCode menambahkan dukungan analisis kode statis berbasis AI untuk C dan C ++ " dengan pengumuman dukungan untuk analisis proyek yang ditulis dalam C dan C ++.

Untuk melihat hasil analisis DeepCode, saya memutuskan untuk memeriksa proyek PhysX. Saya tidak punya tujuan di sini untuk menyajikan analisis kesalahan yang ditemukan oleh PVS-Studio atau DeepCode dalam proyek ini, tetapi saya hanya ingin mengambil beberapa proyek pihak ketiga dan melihat contohnya, bagaimana analisis akan bekerja.

Menjalankan analisis DeepCode sangat sederhana. Analisis proyek yang diposting di GitHub dimulai secara otomatis. Meskipun ada masalah, karena seluruh repositori diperiksa berturut-turut, meskipun berisi berbagai proyek, dan peringatan kepada mereka akhirnya dicampuradukkan. Juga, kecepatan analisis menunjukkan bahwa kode tidak dikompilasi dan banyak kesalahan mungkin disembunyikan dari penganalisa.

Hasil keseluruhan dari DeepCode adalah sebagai berikut:

Gambar 2

Ini tidak cukup mencerminkan jumlah perjalanan, karena mereka dikelompokkan menjadi satu peringatan, seperti yang akan saya tunjukkan nanti. Tentu saja, jelas bahwa analisis statis C / C ++ di DeepCode adalah sebuah inovasi, dan pengerjaan itu baru saja dimulai, tapi saya pikir sudah mungkin untuk menarik beberapa kesimpulan.

Mulai memeriksa pemicu DeepCode, saya menemukan peringatan berikut untuk kesalahan yang ditemui oleh penganalisis tidak kurang dari 31 kali:

Gambar 3

Tanggapan ini menarik perhatian saya, karena PVS-Studio memiliki diagnosis yang sama dan, terlebih lagi, saya memeriksa respons semacam itu di artikel saya yang lain . Ketika saya bertemu dengannya untuk pertama kalinya, saya merasa sangat sedikit orang yang menulis konstanta matematika “dengan tangan”.

Dan PVS-Studio juga menemukan penggunaan konstanta yang ceroboh, tetapi tidak ada yang lebih dari 31, tetapi ada 52 uji coba semacam ini. Hampir segera, ada saat di mana pembelajaran mesin lebih rendah daripada pendekatan klasik. Jika kode kesalahan setidaknya entah bagaimana berangkat dari kesalahan yang sangat tipikal dari jenis ini, menemukan itu menjadi jauh lebih sulit. Untuk analisis statis klasik, kesalahan tidak perlu terjadi berkali-kali - cukup bagi pengembang diagnostik untuk membuat prinsip umum tentang munculnya kesalahan.

Selain itu, diagnosa PVS-Studio bekerja tidak hanya pada nomor Pi atau konstanta yang sering digunakan lainnya, tetapi juga pada yang spesifik (misalnya, konstanta Landau-Ramanujan), penggunaan yang salah yang sulit untuk ditangkap berdasarkan pada bahkan basis pelatihan yang besar karena jarang digunakan. .

Karena DeepCode bekerja secara ketat pada konstanta bentuk 3.1415, saya menambahkan tidak tertarik di satu tempat dalam kode ke tempat desimal konstan 4 (3,14159263), dan operasi menghilang.

Gambar 7

PVS-Studio bekerja pada berbagai opsi untuk pembulatan konstanta.

Gambar 8

Termasuk ada respons terhadap bagian yang diubah:

V624 Mungkin ada kesalahan cetak dalam konstanta '3.14159263'. Pertimbangkan untuk menggunakan konstanta M_PI dari <math.h>. Crab.cpp 219

Dan intinya di sini bukan bahwa ini adalah semacam kesalahan mengerikan / pembulatan kasar / kemungkinan membuat kesalahan ketik, tetapi itu menegaskan bahwa pelatihan pada kode akan terbatas pada kode ini dan, jika terjadi sesuatu keluar dari pola umum atau hanya muncul dalam kasus yang jarang terjadi, kesalahan atau kekurangan bisa lolos tanpa disadari.

Mari kita pertimbangkan satu operasi lagi. DeepCode mengeluarkan satu peringatan pada kode berikut:

bool Shader::loadShaderCode(const char* fragmentShaderCode, ....)
{
  ....
  if (mFragmentShaderSource != NULL)
    free(mFragmentShaderSource);

  ....

  if (mFragmentShaderSource != NULL)
    free(mFragmentShaderSource);
  ....
}

Gambar 10

PVS-Studio memiliki lebih banyak keluhan tentang kode ini:

  1. V809 Verifying that a pointer value is not NULL is not required. The 'if (mFragmentShaderSource != 0)' check can be removed. Shader.cpp 178
  2. V809 Verifying that a pointer value is not NULL is not required. The 'if (mFragmentShaderSource != 0)' check can be removed. Shader.cpp 194
  3. V774 The 'mFragmentShaderSource' pointer was used after the memory was released. Shader.cpp 194
  4. V586 The 'free' function is called twice for deallocation of the same memory space. Inspect the first argument. Check lines: 179, 195. Shader.cpp 195

Anda mungkin berpikir bahwa pemicu DeepCode ternyata singkat, dan PVS-Studio menghasilkan banyak pemicu yang tidak perlu, tetapi ini tidak demikian, dan masing-masing pemicu di sini memiliki arti tersendiri.

Dua operasi pertama terkait dengan pemeriksaan pointer berlebihan, karena pemeriksaan seperti itu tidak diperlukan untuk menggunakan fungsi free () . Aktuasi ketiga menunjukkan bahwa tidak aman untuk menggunakan pointer setelah dirilis. Bahkan jika pointer itu sendiri tidak dereferensi, tetapi hanya diperiksa, itu masih mencurigakan dan sering menunjukkan kesalahan ketik. Nah, operasi terakhir hanya menunjukkan masalah yang sama yang ditemukan DeepCode.

Gambar 11

Ada tangkapan layar di artikel DeepCode tentang permulaan dukungan C / C ++ , yang, menurut kami, mengandung false positive. Peringatan menunjukkan kemungkinan buffer overflow, tetapi memori untuk buffer dialokasikan dengan mempertimbangkan panjang rumah dan panjang garis, yang selanjutnya ditambahkan oleh + 1. Dengan demikian, ada cukup ruang di buffer untuk memastikan.

Masalahnya di sini mungkin adalah kurangnya verifikasi bahwa memori berhasil dialokasikan. Mungkin peringatan DeepCode dalam kasus ini mengatakan sesuatu yang lain: kalimat pertama dari peringatan tersebut tidak secara khusus membantu dalam memahami apa kesalahannya dan apa yang sebenarnya disumpah oleh penganalisa.

Dalam hal ini, mungkin faktor lain yang kami tulis dipicu - sulitnya membuat peringatan yang berarti. Entah peringatan setelah mengklasifikasikan respons dari penganalisa terlatih ditulis oleh orang-orang, atau dibentuk dari komentar pada komitmen / dokumentasi. Tetapi menghasilkan peringatan yang baik bisa sulit jika pola kesalahan disimpulkan melalui pembelajaran mesin, dan bukan oleh pengembang.

Saya bertanya-tanya apa yang perlu diubah dalam kode ini sehingga peringatan itu hilang. Tapi, anehnya, pada bagian kode yang benar-benar mirip di file baru, peringatan seperti itu tidak terjadi, dan yang lain muncul.

Gambar 5

Mungkin intinya adalah bahwa lingkungan yang dianalisa oleh penganalisa telah menghilang, atau saya melakukan sesuatu yang salah. Tetapi ketidakstabilan peringatan, fakta bahwa penampilan mereka tidak dapat diprediksi, dapat menyebabkan, menurut saya, ketidaknyamanan tidak hanya bagi pengguna, tetapi juga untuk pengembang alat analisa itu sendiri dan mempersulit proses pengembangan.

Secara umum, meskipun sebagian besar respons DeepCode belum salah, jumlah mereka sangat kecil sehingga hasil kerjanya saat ini agak langka daripada akurat. Sejumlah kecil positif palsu pada prinsipnya disertai dengan sejumlah kecil positif.

Saya akan memberi Anda beberapa kesalahan menarik yang ditemukan oleh PVS-Studio.

Fragmen N1

V773Fungsi itu keluar tanpa melepaskan pointer 'line'. Kebocoran memori dimungkinkan. PxTkBmpLoader.cpp 166

bool BmpLoader::loadBmp(PxFileHandle f)
{
  ....
  int lineLen = ....;
  unsigned char* line = static_cast<unsigned char*>(malloc(lineLen));
  for(int i = info.Height-1; i >= 0; i--)
  {
    num = fread(line, 1, static_cast<size_t>(lineLen), f);
    if (num != static_cast<size_t>(lineLen)) { fclose(f); return false; }
    ....
  }
  free(line);
  return true;
}

Di sini, dalam kasus pembacaan dari file terganggu, kebocoran memori terjadi, karena memori tidak dibebaskan sebelum kembali dari fungsi.

Fragmen N2

V595 Pointer 'gSphereActor' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 228, 230. SnippetContactReportCCD.cpp 228

void initScene()
{
  ....
  gSphereActor = gPhysics->createRigidDynamic(spherePose);
  gSphereActor->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, true);

  if (!gSphereActor)
    return;
  ....
}

Pointer gSphereActor didereferensi , tetapi segera setelah itu diperiksa untuk nullptr, dan fungsinya keluar. Yaitu, pointer nol dimungkinkan di sini, tetapi dereferencing masih terjadi. Ada 24 kesalahan semacam ini dalam proyek PhysX.

DeepCode hanya memberikan positif untuk jenis kasus tertentu (seperti yang saya mengerti), di mana pointer awalnya diinisialisasi ke nol, dan tidak ada tugas lain di bidang pandang. PVS-Studio tidak bekerja pada kode seperti itu, karena paling sering kebakaran seperti itu akan salah, karena penunjuk bisa mendapatkan nilai di unit terjemahan lain (sebagian besar kebakaran terjadi pada variabel global). Contoh ini menunjukkan bahwa lebih sedikit positif palsu dalam analisis statis terlatih tidak selalu benar.

Gambar 15

Gambar 13

Di sini DeepCode, kemungkinan besar, untuk beberapa alasan mengindikasikan inisialisasi yang salah. Alih-alih inisialisasi gCooking disorot inisialisasi gFoundation , meskipun indeks tidak diterangi lebih lanjut.

Fragmen N3

V517 Penggunaan pola 'jika (A) {...} else jika (A) {...}' terdeteksi. Ada kemungkinan kehadiran kesalahan logis. Periksa baris: 266, 268. AABox.cpp 266

bool AABox::initRT(int depthSamples, int coverageSamples)
{
  ....
  int query;
  ....
  if (....)  
  {
    ....
    if ( query < coverageSamples)
      ret = false;
    else if ( query > coverageSamples) 
      coverageSamples = query;
    ....
    if ( query < depthSamples)
      ret = false;
    else if ( query > depthSamples)
      depthSamples = query;
  }
  else {
    ....
    if ( query < depthSamples)
      ret = false;
    else if ( query < depthSamples) // <=
      depthSamples = query;
    ....
  }
  ....
}

Di sini tampaknya kesalahan salin-tempel telah masuk. Alat analisis mendeteksi kondisi yang sama jika dan yang lainnya . Dari if-else sebelumnya , Anda dapat melihat bahwa ">" di if dan "<" di lain biasanya diperiksa . Meskipun polanya terlihat sangat sederhana, saya tidak menemukan respons semacam itu di antara peringatan DeepCode, meskipun tampaknya itu adalah pola yang sangat sederhana untuk dideteksi.

Kesimpulan

Tentu saja, DeepCode baru saja mengumumkan dukungan untuk C / C ++ dan itu adalah bagian dari produk mereka yang baru saja mulai berkembang. Anda dapat mencobanya di proyek Anda juga, di layanan mereka jendela umpan balik yang nyaman telah diterapkan jika Anda telah diberi peringatan palsu.

Namun, kita sekarang dapat melihat kekurangan yang menyertai pembelajaran mesin dalam analisis statis. Oleh karena itu, kami skeptis terhadap gagasan untuk menambahkan pembelajaran mesin ke analisis statis, karena keuntungan diragukan: dukungan analisis yang sama persis, menulis atau mengedit dokumentasi, dan mengerjakan diagnosa itu sendiri diperlukan. Selain itu, masalah yang dihadapi selama pengembangan membutuhkan solusi yang lebih kompleks dan keterampilan khusus dari pengembang, yang mengurangi jumlah kandidat potensial ketika memperluas tim. Memang, pengembang dalam hal ini tidak hanya harus menjadi spesialis dalam bahasa yang dianalisis, tetapi juga memiliki pengetahuan di bidang pembelajaran mesin.


Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan terjemahan: Victoria Khanieva. DeepCode: Perspektif Luar .

All Articles