Periksa pegangan penunjuk valid

Saya ingin mengimplementasikan perpustakaan Microsoft CryptographicServiceProvider dan saat ini saya memikirkan cara terbaik untuk menangani konteks yang saya buat.

Pertanyaan saya khusus untuk kasus ini tetapi pendekatan desain dapat digunakan dalam situasi lain.

Saya berasal dari latar belakang kode terkelola dan saya tidak 100% yakin tentang penanganan penunjuk multithread di C/C++.

Secara umum ada dua fungsi yang bertanggung jawab menangani pembuatan dan penghancuran (CryptAcquireContext, CryptReleaseContext), dan semua fungsi CSP selanjutnya menggunakan pegangan yang dikembalikan oleh fungsi pembuat.

Saya tidak menemukan informasi atau spesifikasi konkrit dari Microsoft yang memberikan pendekatan desain atau aturan bagaimana melakukannya. Namun saya melakukan riset dengan penyedia CSP lain yang dibuat oleh Microsoft untuk mengetahui aturan desainnya, yaitu:

  • Fungsinya harus aman untuk thread
  • Pegangan konteks tidak akan dibagikan antar thread
  • Jika pegangan konteks tidak valid, kembalikan dengan kesalahan

Penyedia MS CSP lainnya akan mengembalikan pointer yang valid sebagai pegangan, atau NULL jika tidak.

Saya tidak berpikir bahwa aplikasi pemanggil akan melewati sampah total tetapi bisa saja aplikasi tersebut melewati pegangan yang telah dirilis dan perpustakaan saya akan kembali dengan kesalahan.

Hal ini membawa saya pada tiga ide bagaimana menerapkannya:

  1. Cukup alokasikan memori struct konteks saya dengan malloc atau new dan kembalikan pointer mentah sebagai pegangan.

    Saya berharap aplikasi yang memanggil perpustakaan saya akan melewati pegangan yang valid. Tetapi jika tidak, perpustakaan saya akan mengalami perilaku tidak terdefinisi. Jadi saya perlu solusi yang lebih baik.

  2. Tambahkan pointer yang saya buat ke daftar (std::list, std::map). Jadi saya bisa mengulangi daftar untuk memeriksa apakah penunjuknya ada. Akses ke daftar dilindungi dengan mutex.

    Ini harusnya aman dan penggunaan API reguler tidak boleh menjadi masalah kinerja. Namun dalam skenario Terminal Server bisa saja demikian. Dalam hal ini proses Windows lsass.exe dibuat untuk setiap pengguna yang ingin masuk ke konteks CSP di thread terpisah dan membuat sekitar 10 panggilan API per konteks.

    Tujuan desainnya adalah perpustakaan saya harus mampu menangani 300 klien secara paralel. Saya tidak tahu berapa banyak utas yang dibuat oleh Windows dalam kasus ini.

    Jadi jika memungkinkan saya lebih memilih implementasi tanpa kunci.

  3. Saya mengalokasikan struct dasar yang menyimpan nilai pemeriksaan dan penunjuk data aktual. Gunakan penunjuk struct ini sebagai pegangan konteks.

    typedef struct CSPHandle  
    {  
        int Type; // (eg. magic number CSPContext=0xA1B2C3D4)  
        CSPContextPtr pCSPContext;  
    };
    

    Jadi saya bisa membaca byte pertama dari pointer yang diteruskan dan memeriksa apakah datanya sama dengan tipe yang saya tentukan. Dan saya memiliki kendali penuh atas penunjuk data aktual, yang disetel ke NULL jika konteksnya dilepaskan. Apakah ini ide yang baik atau buruk?

Apa pendapat Anda tentang kasus ini? Haruskah saya menggunakan salah satu pendekatan ini atau adakah solusi lain?

Terima kasih


person Stephan Weitlaner    schedule 04.03.2015    source sumber
comment
I can expect that the applications which call my library will pass a valid handle. But if not my library will run into an undefined behaviour. Asumsikan Anda menemukan bahwa pegangan yang diberikan tidak valid. Apa yang akan dilakukan kode Anda? Selain itu, Anda juga harus mempertimbangkan keuntungan dan kerugian dari mencoba terlalu banyak berpegangan tangan. Jika pengguna API Anda adalah pemrogram berpengalaman, mungkin mendokumentasikan bahwa mereka perlu memberikan pegangan yang valid, atau hal buruk akan terjadi, mungkin sudah cukup.   -  person PaulMcKenzie    schedule 04.03.2015


Jawaban (1)


Saya menemukan solusi dan akan menjawab pertanyaan saya.

Saya mengabaikan detail kecil tapi penting

Di CSP tidak ada panggilan API langsung ke dll (memuat perpustakaan, mendapatkan penunjuk fungsi, memanggil fungsi) karena panggilan fungsi diteruskan oleh Microsoft CSP yang memuat perpustakaan CSP berdasarkan nama.

Jadi Microsoft CSP perlu mengetahui dan memeriksa konteks yang diteruskan untuk mendapatkan pemetaan yang benar ke perpustakaan tertentu.

Contoh:
1. client->cryptacquirecontext(in cspname, out ctx)
2. MS CSP->memuat libray dari cspname
3 . MS CSP->memanggil penunjuk fungsi perpustakaan yang dimuat
4. CSP LIB->cryptacquirecontext membuat konteks baru
5. MS CSP->menerima pegangan csp yang dikembalikan dan menyimpannya ke pemetaan dll
6. MS CSP->mengembalikan hasilnya ke aplikasi pemanggil
7. client->cryptsetprovparam(ctx) // yang telah dibuat sebelumnya
8. MS CSP->memeriksa apakah konteksnya ada dan perpustakaan mana yang bertanggung jawab
9. MS CSP->jika konteks yang diberikan tidak dapat dipetakan ke csp dll, kesalahan akan muncul, karena MS CSP tidak mengetahui penunjuk fungsi mana yang harus dipanggil.

Jadi dalam hal ini seharusnya cukup mengalokasikan memori saja. Jika aplikasi klien melewati pegangan konteks yang tidak valid, aplikasi tersebut tidak akan pernah masuk ke perpustakaan csp.

Saya pikir MS CSP menggunakan daftar dengan mutex guard untuk menyimpan pemetaan konteks. Karena konteksnya bisa berupa apa saja, mulai dari angka acak hingga penunjuk yang valid.

person Stephan Weitlaner    schedule 05.03.2015