Rumah > pembangunan bahagian belakang > C++ > TIL CAnnex K wujud tetapi anda tidak sepatutnya menggunakannya

TIL CAnnex K wujud tetapi anda tidak sepatutnya menggunakannya

DDD
Lepaskan: 2024-11-03 13:58:03
asal
403 orang telah melayarinya

TIL CAnnex K exists but you shouldn

Lampiran K ialah nama teknikal. Kata kunci biasa lain ialah __STDC_LIB_EXT1__ dan __STDC_WANT_LIB_EXT1__. Lampiran K mentakrifkan perkara akhiran _s "selamat" seperti sprintf_s() dan scanf_s().

Juga lihat pengalaman Lapangan dengan Lampiran K (2015) dan pemeriksaan Bounds - dokumentasi teknikal cppreference.com.

Matlamatnya

Apakah gunanya fungsi _s()? Mereka menyemak hujah mereka untuk lebih banyak invarian seperti "akan memanggil pengendali kekangan jika strim adalah batal, rentetan adalah batal, bufsz adalah sifar, atau penimbal akan menulis di luar sempadan melebihi panjang yang ditentukan". Itu nampaknya idea yang bagus, bukan? Yeah! Memang betul!

Intinya ialah anda boleh/boleh melakukan ini:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}
Salin selepas log masuk
Salin selepas log masuk

Bagaimanakah itu dibandingkan dengan cara biasa melakukan sesuatu tanpa __STDC_WANT_LIB_EXT1__?

Selamat jalan

FILE *file = fopen("hello.txt", "r");
// file is OK.
Salin selepas log masuk
FILE *file;
errno_t err = fopen_s(&file, "hello.txt", "r");
// file is OK
Salin selepas log masuk

Laluan yang menyedihkan

FILE *file = fopen("notexist.txt", "r");
// file is NULL, errno is set.
Salin selepas log masuk
FILE *file;
errno_t err = fopen_s(&file, "notexist.txt", "r");
// file is NULL, err is set.
Salin selepas log masuk

Laluan buruk

FILE *file = fopen(NULL, NULL);
// idk.
Salin selepas log masuk
FILE *file;
errno_t err = fopen_s(&file, NULL, NULL);
// Constraint violated. Abort with message.
Salin selepas log masuk

Ya, anda boleh menyesuaikan pengendali kekangan untuk hanya log masuk ke fail dan meneruskan seolah-olah tiada apa yang berlaku.

set_constraint_handler_s(ignore_handler_s);
set_constraint_handler_s(abort_handler_s);
set_constraint_handler_s(my_awesome_handler);
Salin selepas log masuk

Perhatikan bagaimana fopen() normal mempunyai nilai pulangan yang sama (mungkin errno berbeza) untuk menunjukkan tahap keburukan ralat yang berbeza? Itulah yang cuba diperbaiki oleh fopen_s() ini. Sekurang-kurangnya, itulah bacaan saya. Saya menganggapnya seperti panik Rust!() vs Result. Ia juga mungkin membantu menghentikan beberapa serangan limpahan penimbal dengan menyediakan argumen size_of_dest untuk mengelak daripada melimpah sebarang penimbal dest seperti strcpy_s() dan gets_s().

char* gets( char* str ); // (removed in C11)
char* gets_s( char* str, rsize_t n ); // (since C11, annex K)
Salin selepas log masuk

Membaca stdin ke dalam tatasusunan aksara yang ditunjuk oleh str sehingga aksara baris baharu ditemui atau fail akhir berlaku. Aksara null ditulis sejurus selepas aksara terakhir dibaca ke dalam tatasusunan. Aksara baris baharu dibuang tetapi tidak disimpan dalam penimbal.

Fungsi gets() tidak melakukan semakan sempadan, oleh itu fungsi ini sangat terdedah kepada serangan buffer-overflow. Ia tidak boleh digunakan dengan selamat (melainkan program berjalan dalam persekitaran yang menyekat perkara yang boleh muncul pada stdin). Atas sebab ini, fungsi tersebut telah ditamatkan dalam korigendum ketiga kepada standard C99 dan dialih keluar sama sekali dalam standard C11. fgets() dan gets_s() ialah penggantian yang disyorkan.

AMARAN: Jangan sesekali gunakan gets().

// BAD
char buffer[1000];
gets(buffer);
// ⚠️ Could write >1000 chars to `buffer`!
Salin selepas log masuk
// GOOD
char buffer[1000];
gets_s(buffer, sizeof(buffer));
// This will stop at 1000 chars.
Salin selepas log masuk

Fungsi _s() nampaknya bagus untuk menghentikan tempat biasa di mana limpahan penimbal boleh berlaku.

Masalahnya

Ia tidak dilaksanakan di mana-mana sahaja. Fungsi _s() ialah sambungan yang tidak tersedia dalam pelaksanaan libc seperti glibc GNU. Terdapat isu kecil lain seperti ia tidak ergonomik untuk multithreading dan kesilapan biasa untuk melakukan sizeof(src) dan bukannya sizeof(dest) untuk perkara seperti strcpy_s(), tetapi itu semua tidak bermakna jika dibandingkan dengan masalah ketersediaan.

Kebanyakan maklumat dalam talian yang saya temui nampaknya menunjukkan bahawa MSVC ialah satu-satunya pengkompil/libc utama yang telah melaksanakan Lampiran K.

Memandangkan fungsi _s() mewah ini tidak terdapat di mana-mana yang perlu dihimpunkan oleh kod anda, anda perlu menulis kod seperti ini:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}
Salin selepas log masuk
Salin selepas log masuk

...untuk setiap contoh yang anda mahu lakukan strlen_s() atau fopen_s() atau strcpy_s(). Itulah cara yang baik untuk menjadi gila.

Jadi jelas sekali anda tidak akan menulis kod yang bergantung pada platform hanya untuk melakukan printf() asas dan strcpy() tetapi bagaimana pula dengan membungkus semua #ifdef __STDC_LIB_EXT1__ #barang lain dalam perpustakaan?

Terdapat dua perpustakaan yang kelihatan menjanjikan yang saya temui melalui carian Google pantas:

  • safec: Laman web Safe C Library halaman GitHub ⭐335
  • sbaresearch/slibc: Pelaksanaan C11 Annex K "Antara muka semak sempadan" ISO/IEC 9899:2011 ⭐14

Jadi... jika anda mahu (atau dikehendaki oleh perkara keselamatan) menggunakan fungsi _s() tetapi juga tidak mahu mengehadkan diri anda kepada MSVC sahaja maka anda boleh menggunakan salah satu daripada ☝ perpustakaan tersebut.

? Untuk membaca lebih lanjut, lihat Pengalaman Lapangan dengan Lampiran K (2015) dan pemeriksaan Bounds - dokumentasi teknikal cppreference.com.

Atas ialah kandungan terperinci TIL CAnnex K wujud tetapi anda tidak sepatutnya menggunakannya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan