گنجه

# tail -f /var/log/experience

مبنای بحث در این مطلب، زبان‌های C++‎ و C هستند، ولی مطالعهٔ آن برای برنامه‌نویسان هر زبانی که در معرض ایراد0های فساد حافظه1 است و حتی هر برنامه‌نویسی، احتمالاً خالی از سود نخواهد بود.

برنامه‌ای نوشته‌اید که ایراد داره. اون رو حسابی آزموده‌اید و هر ایراد منطقی2 رو که فکر می‌کنید ممکن هست وجود داشته باشه بررسی و رفع کرده‌اید، ولی هنوز برنامه ایراد داره!
برنامهٔ شما رفتارهای عجیبی از خودش نشون می‌ده. مثلاً اگر در حالت ایرادزدایی3 بسازیدش4 کار می‌کنه، ولی در حالت انتشار5 یا اشتباه کار می‌کنه، یا کار نمی‌کنه و دچار سانحه6 می‌شه. یا مثلاً با ورودی‌های مختلف، در جاهای کاملاً متفاوت و نسبتاً بی‌ربط از کد دچار سانحه می‌شه. یا مثلاً همیشه در پایان یک تابع7 بعد از همهٔ عملیات، ولی قبل از بازگشت (یعنی دقیقاً روی { !!!) دچار سانحه می‌شه.
در چنین شرایطی هست که شما حدس می‌زنید برنامه‌تون دچار ایراد فساد حافظه1 شده.
اگر برنامه همیشه در یک تابع خاص دچار سانحه می‌شه، حدس می‌زنیم که در یکی از متغیرهای محلی همون تابع خراب‌کاری شده و پشته8 خراب شده؛ به همین دلیل در هنگام جمع کردن قاب پشتهٔ9 تابع از روی پشته، به علت فساد نشانی بازگشت10، برنامه دچار سانحه می‌شه11.12 معمولاً با خوندن دقیق همون تابع، ایراد یافت و حل می‌شه. اگر نشد، متغیرهای محلی که روی پشته هستند رو به کومه13 منتقل می‌کنیم (با استفاده از new یا malloc) و می‌ریم به سراغ روش‌های مربوط به فساد کومه که الان می‌خواهیم بگیم.
اولین قدم برای یافتن ایرادهای فساد حافظهٔ کومه، استمداد از حضرت Valgrind است (که در دبین14 بسته‌اش valgrind است)):

% valgrind --leak-check=full --leak-resolution=high ./buggy

برنامه با سرعتی بسیار کم‌تر از حد معمول اجرا می‌شه و هر دست‌رسی به حافظهٔ کومه که خارج از حافظهٔ تخصیص‌یافته15 باشه، با نام تابع و (در حالت ایرادزدایی) شمارهٔ خط کد منبع16 گزارش می‌شه. البته Valgrind بسیار جای حرف و معرفی و ستایش و غیره داره که از موضوع این مطلب خارجه!
اگر Valgrind مشکل رو یافت و ایراد رفع شد که خدا رو شکر می‌کنیم! اما اگر نه، با یک مورد بدخیم (!) طرف هستیم. یعنی دست‌رسی‌هایی داریم که به رغم ایراد داشتنشون، داخل حافظهٔ تخصیص‌یافته قرار گرفته‌اند. مثلاً دو آرایهٔ ۱۰۰تایی پشت سر هم در کومه گرفته‌ایم و به عنصر ۱۲۵ام از آرایهٔ اول دست زده‌ایم! دست‌رسی هنوز داخل حافظهٔ پردازهٔ17 خودمان است، ولی نادرست و ایراددار. اگر کسی تا این جای مطلب رو خونده باشه تعجب می‌کنم! البته کسی به جز خودم!
ان‌شاء الله در مطلب بعدی شیوه‌ای برای یافتن این موارد بدخیم معرفی خواهد شد که از یکی از هم‌کاران باتجربه‌ترم (حفظه الله) آموخته‌ام.

  1. Bug []
  2. Memory corruption [] []
  3. Logical []
  4. Debug []
  5. Build []
  6. Release []
  7. Crash []
  8. Function []
  9. Stack []
  10. Stack frame []
  11. Return address []
  12. نوعی سرریز میان‌گیر (Buffer overflow) []
  13. البته این رفتار سانحه‌آمیز (!) بستگی به هم‌گردان داره، ولی هم‌گردان‌های جدید مثل GCCهای ۴ به بعد (و شاید بعضی قدیمی‌ترها)، به علت داشتن روش‌هایی برای مقابله با خرابی پشته، عمداً برنامه‌ای تولید می‌کنند که در این شرایط دچار سانحه بشه []
  14. Heap []
  15. Debian []
  16. Allocated []
  17. Source code []
  18. Process []

۶ نظر به “مقابله با ایرادهای فساد حافظه”

  1. همکار می گوید:

    سلام
    با تشکر از زحمات شما در مستندسازی تجربیات
    ولی بهتر نیست که شبها رو بخوابی و روز روشن ما را از این نوشته ها بهره مند کنی ;-)

    موفق باشی
    یک دیگر از همکاران شما !

    پاسخ

    ابراهیم پاسخ:

    سلام،
    قابل نداره.
    در مورد شب‌کاری: :-D

    پاسخ

  2. حمزه می گوید:

    من خوندم تا آخرش؛
    این “سانحه” را خوب اومده ای. آدم یاد اورژانس میفته.
    D:

    پاسخ

    ابراهیم پاسخ:

    چه خوب‌تر بود اگر تصحیح و تکمیل می‌فرمودید حاج‌آقا. حتما شما در اون دانش‌گاه (همون پروژهٔ معروف!) چیزها آموخته‌اید که حالاحالاها به تور امثال من نمی‌افته.

    پاسخ

    حمزه پاسخ:

    برادر میدانی که ما از شدت کرامات و مقامات مکتسبه در آن دانشگاه، به علومی دست یافته ایم که شهودی است؛ نه حصولی!
    و وبلاگ منصه ظهور علوم حصولی است؛ نه عرصه بروز علوم شهودی.

    و البته من این همه نیستم!

    پاسخ

  3. بهنام توکلی می گوید:

    سلام ابراهیم جان،
    لطفا آخر ارسال های وبلاگت یک قرص استامینوفن هم بذار. بعضی ها با خواندن جملات اصیل کاملا فارسی سر درد می گیرند :)

    موفق باشی

    پاسخ

نظر شما


بسم الله الرحمن الرحیم

راه‌رو گر صد هنر دارد توکل بایدش

برگه‌ها

آمار

در کل 76 بیننده برای این صفحه
امروز 3 بیننده
در کل 2599 بیننده
از 2008/11/21