S segmentirovkadagi xatolarni bartaraf qilish uchun C/C ++ da kattalik hajmini tekshirish

Shunday qilib, C xotiraga kirishda biron bir qator chegaralarni tekshirmaydi. Agar siz int myArray [3] deb boshlaganingizda, myArray [7] deb atagan bo'lsangiz, dastur himoyalangan xotira tufayli segfault va qulashga ega bo'ladi.

Endi myFunc (int * yourArray) kabi funktsiyada dalillar mavjud bo'lsa, lekin siz qatorda kamida 8 ta bo'sh joy kerakligini bilsangiz, myArray [ 7] maxsus xatoga yo'l qo'yish uchun oldindan noqonuniy hisoblanadi:

"Sorry, yourArray is too small for this function. We need 8 ints of space."

dan ko'ra

"Segmentation fault."
5
@lxrec: boshqa usulda. C/C ++ bunga mos emas.
qo'shib qo'ydi muallif Calum, manba
std :: array ni tekshirish mumkin. >
qo'shib qo'ydi muallif Vincent Peres, manba
Yakuniy ovoz berishga kelsak: Menimcha, bu erda ham, SOda ham mavzu. Shunday qilib, javob C/C ++ ning bunga yordam berishi yoki qila olmasligi ehtimoldan yiroq emas. Bu yerda, javob bunday xususiyatni kontseptual deb hisoblash mumkinmi, agar bo'lmasa, xuddi shu maqsadga erishish mumkin.
qo'shib qo'ydi muallif Ixrec, manba

5 javoblar

Siz istagan kabi qator qatori tekshiruvi dasturga xosdir, chunki bufer toshishi , aniqlanmagan xatti-harakatlar (va bu , UB nima uchun juda yomon bo'lishi mumkinligini tushuntiradi).

Bundan tashqari, umuman, noaniq muammo . Osonlik bilan statik ravishda topishga ( statik dastur tahlil , Masalan, C ++ manba kodi dasturni ishlamasdan) har bir tampon to'lib toshishi muammolarni hal qilish a>. Shuningdek, Rays teoremasi haqida o'qing.

Shu bilan birga, bir nechta (qisman) amaliy vositalar mavjud (ayniqsa Linuxda):

  • you could add assert or static_assert-s in your code, and/or runtime checks.

  • you might find and use a static code analyzer à la Frama-C (it works for C code currently).

  • you could customize your GCC compiler using MELT.

  • You should compile your code with all warnings & debug info, e.g. g++ -Wall -Wextra -g if using GCC.

  • You might run your program with valgrind, at least for tests.

  • you could use the address sanitizer, e.g. add -fsanitize=address to your compilation flags (when testing)

  • notably in C (and sometimes in C++) it is a good convention to pass both array pointers and their size (like e.g. snprintf(3) or strncmp(3) do). In C, you might also use flexible array members in struct and store the flexible array's size inside the struct

BTW C va C ++ belgilarining arifmetik qobiliyatlari buferi to'ldirishni yanada qiyinlashtiradi.

C ++ 11 da siz tekis chiziqlar va xom ashyoning oldini olishingiz va standart konteynerlardan foydalanishingiz mumkin va aqlli ko'rsatkichlar .

9
qo'shib qo'ydi
@Ixrec: Siz bilasiz strcpy va boshqalar strncpy - shiddat bilan yomon misol? strncpy satrlarni nusxa ko'chirmaydi, u n-0 bo'lmagan baytni manba-satrdan va 0-noldan n-baytga ko'chiradi. Va baribir, agar siz buffer uzunligini taqdim qilsangiz, siz kesilgan (odatda juda ko'p emas, balki ) bo'lishi kerak, yoki siz muvaffaqiyatsiz signal berishingiz kerak.
qo'shib qo'ydi muallif Shizam, manba
@Ixrec: strlcpy strcpy strncpy versiyasidan "ba'zi bir senaryolar uchun yanada xavfsizroq" hisoblanadi, faqatgina juda ixtisoslashgan butunlay boshqa vositadir. Ha, ammo buni bilmagan juda ko'p odamlar bor, bu ham yomon misoldir.
qo'shib qo'ydi muallif Shizam, manba
statik so'zi kalit: Agar to'xtab turish muammosiga pasayish faqat chegaradan chiqib ketadigan barcha dasturlarni bekor qilmoqchi bo'lsak, faqat dasturni ishga tushirmagan holda ishlaydi. Agar ish vaqtidagi tekshiruvlarga ruxsat berilsa, muammo deyarli ahamiyatga ega emas, u faqat ish vaqti bilan bajariladi (va juda katta, soddalashtirilgan yechim uchun). Xuddi shunday, chegaralaridan chiqib ketadigan barcha dasturlarni ham rad eting. (qiyin qism deyarli foydali bo'lganlarni rad etmaydi).
qo'shib qo'ydi muallif Paul Muir, manba
Men qo'shmoqchi bo'lgan yagona narsa: C da, har doim qatorni uzunligi qatori (a la strcpy vs strncpy) bilan birga, shuning uchun C ++ da xom qator o'rniga konteynerdan foydalansangiz.
qo'shib qo'ydi muallif Ixrec, manba
@Deduplicator Men faqat "aniq uzunlikni qabul qiladigan versiya xavfsizroq/yaxshi deb hisoblangan" misolini taqdim qilmoqchi edim, bu
qo'shib qo'ydi muallif Ixrec, manba
@Deduplicator Siz haqlisiz, aniq aytmoqchi bo'lsam, men S-Basilda yaxshiroq namuna bo'ldim, shuning uchun hech bo'lmaganda sharhning asosiy maqsadi qo'lga kiritildi.
qo'shib qo'ydi muallif Ixrec, manba
Muammoni hal qilishda qiziqarli voqea! Men bu haqda hech o'ylamagan edim, lekin kompilyatsiya masalalari bo'yicha siz haqsiz.
qo'shib qo'ydi muallif SteveVaiProdigy, manba

Javob juda chindan ham juda oson: agar siz xavfsizlikni xohlasangiz, aslida uni ta'minlaydigan biror narsani foydalaning - bu C emas, balki C-uslubidagi arraylarni emas.

C ning asosiy uslubidan va xom qatorlardan juda uzoqqa ketmasdan C ++ va std :: vector yordamida [i] .at ( i) ni tanlang va chegara tekshiruvini oling.

Buning o'rniga std :: vector ni ishlatish, massivlar bilan bog'liq muammolar ko'pini osonlashtiradi. Vektorning hozirgi hajmini .size() a'zo funktsiyasi bilan tekshirishingiz mumkin. Ko'pincha, buni amalga oshirishning hojati yo'q, chunki siz unga biror narsa qo'shishni xohlasangiz, .push_back() a'zo funktsiyasidan foydalanishingiz mumkin.

Hech bo'lmaganda nazariy jihatdan bir xil turdagi narsalarni amalga oshirishingiz mumkin, ammo bunday qilish nisbatan nochor bo'ladi. Agar (masalan,) struct -ga ishora qiluvchi va joriy ajratish hajmini qo'yadigan qoplama belgilash juda qiyin bo'lmasa-da, sizda barcha manipulyatsiyani bajarish uchun funktsiyalarni belgilash kerak, mavjud kodning qanday ishlatilishini bilmasligini yoki u bilan shug'ullanishni bilmasligi bilan yashash kerak. Men buni bir necha marta qildim, agar sizga kerak bo'lsa, uni ishga sola olasiz - lekin men bundan oldin og'riqqa dosh berishga qaror qildim.

4
qo'shib qo'ydi

Tegishli qator uzunligi ko'rsatuvchi belgisi olgan funktsiya. Siz aniq ravishda parametr sifatida o'tishingiz kerak:

void myFunc(int *yourArray, size_t yourArrayLen)

Buni qilganingizdan so'ng, xatoga yo'l qo'yib bo'lmaydi.

Albatta, bu sizning chaqiruvchingizning noto'g'ri uzunligini berishi ehtimoli bor. Buni, albatta, oldini olish mumkin emas:

  • implementing a custom data type to store arrays and then making sure the length stays in-sync with the true length at all times using encapsulation, or
  • allowing static arrays only, e.g.

    void myFunc(int (*yourArray)[8]);
    
4
qo'shib qo'ydi

S (++) tugmachalaridan qatorni uzunligini birinchi elementga qadar olish uchun hech qanday usul yo'q. (MSVCRT da _msize kabi platformaga xos funktsiyalar mavjud, lekin bu < em> faqat kodi malloc ustida ishlaydi.)

Funktsiyalarga massivlarni o'tkazish vaqtida odatda nima bajariladi, chegaralarni belgilash bilan ishlash vaqtida bajarilishi uchun ko'rsatgich bilan birga uzunlikni uzatish kerak.

void myFunc(int* yourArray, int length)
{
    if (length < 8)
    {
        puts("Sorry, yourArray is too small for this function. We need 8 ints of space.");
        return;
    }

   //...
}

void caller()
{
    int arr[LEN];
    myFunc(arr, LEN);
}
1
qo'shib qo'ydi
malloc va boshqa hech qachon so'ralganidan ko'proq joy bermaydigan hech qanday kafolatlar topa olmayapman.
qo'shib qo'ydi muallif Shizam, manba
Bu aslida yaxlitlash tufayli keng tarqalgan, lekin siz bunday qo'shimcha joy (doim mavjud bo'lganda) har doim uninitialized ekanligini tushunishingiz kerak.
qo'shib qo'ydi muallif Calum, manba

Malloc uchun maxsus sarmoyadordan foydalaning (yoki o'zingizni yozing), u ajratadigan bloklar haqida qo'shimcha ma'lumotni saqlaydi. Foydalanadigan men har bir ajratish uchun bir necha "xavfsizlik bytesini" qo'shib qo'yadi, ajratish vaqtini [-1] qilib belgilaydi va ajratilgan paytda xavfsizlik baytlarini va boshqa narsalarni tekshiradi.

0
qo'shib qo'ydi
Bu faqat biron bir qator faqat xotira blokining faqat bir qismini ishlatmasa yordam beradi ...
qo'shib qo'ydi muallif Shizam, manba
Agar I degani bo'lsa, men nimani bo'shatishim kerakligini unutib qo'yaman yoki keyinchalik kerak bo'lgan boshqa ma'lumotlarga rioya qilmayman. Lekin bu sizning ishlatishingiz kabi ko'rinmaydi, bu sizning xatoingiz.
qo'shib qo'ydi muallif Shizam, manba
Agar siz xotira qismlarini ajratish odatiy holatda bo'lsangiz, unda ba'zi qismlarini o'zgacha pointer bilan aloqani yo'qotadigan maxsus usullardan foydalansangiz, sizga yaxshi uslublar kerak bo'ladi.
qo'shib qo'ydi muallif ddyer, manba
Opning so'rovi C tomonidan ajratilgan chiziqli qatorlarni oldini olishga yordam berishdir. Birinchi qadam dasturning qaysi qismini "xotiraga" egalik qilishni yo'qotish kabi yomon amallardan qochishdir. Xotirali noma'lum xotira ishlatadigan kodni yozib qo'ymoq minalar o'rnatmoqda.
qo'shib qo'ydi muallif ddyer, manba