ابزار دیباگی که دستکم گرفته میشه: کاهندهی تستکیس
خلاصهٔ کاملتر
نویسنده میگه ایدهی پشت کاهندهی تستکیس انقدر سادهست که آدم باورش نمیشه کار کنه. فرض کن یه برنامه روی یه ورودی بزرگ کرش میکنه و نمیدونی کدوم بخش ورودی مقصره. کوچیکتر کردن ورودی تقریباً همیشه فهمیدن مشکل رو سادهتر میکنه. میشه دستی این کارو کرد، ولی آدمها زود خسته میشن و کلی فرصت کاهش رو از دست میدن؛ مخصوصاً وقتی حذف همزمانِ دو بخشِ جدا از هم لازم باشه، فضای جستوجو میترکه.
کاهندهی تستکیس همین فرایند رو خودکار میکنه. سه تا ورودی میگیره: برنامه، ورودی، و یه «تست جالببودن» (interestingness test). ابزار نسخههای همیشه کوتاهتری از ورودی رو امتحان میکنه و این تست بهش میگه که نسخهی کوچیکشده هنوز مشکل موردنظر رو نشون میده یا نه. قرارداد رایج اینه که اگه ورودی هنوز جالبه (یعنی همون خطا رو دربیاره) تست مقدار 0 برگردونه و اگه نه، یه مقدار غیرصفر.
نویسنده میگه برای اینکه نشون بده این ابزار جادو نیست، خودش یه کاهندهی خیلی ساده نوشته. منطقش اینه: ورودی رو خطبهخط میخونه، تو یه حلقه هر بار یه خط رو حذف میکنه، ورودی نامزد رو تو یه فایل موقت مینویسه و تست جالببودن رو روش اجرا میکنه؛ اگه نتیجه 0 بود همون نسخهی کوچیکتر رو نگه میداره وگرنه میره سراغ خط بعدی. هستهی این حلقه اینطوریه:
while i < len(cur):
cnd = cur[:]
del cnd[i]
# نوشتن cnd تو فایل موقت و اجرای تست جالببودن
if subprocess.run([sys.argv[1], p.name]).returncode == 0:
cur = cnd
else:
i += 1نکتهی کلیدی به گفتهی نویسنده اینه که این ابزار هیچ درکی از تست جالببودن یا برنامهی زیرین نداره؛ همین نادونی رازِ موفقیتشه. واسه همین میشه روی هر فایل متنی اجراش کرد. نویسنده برای آزمایش از یه LLM خواسته یه برنامهی C تولید کنه که توش با دو پیکربندی مختلف دو خروجی متفاوت میده، و کاهندهی سادهش تو کمتر از ۱۰ ثانیه ۳۰٪ از خطهای کد رو کم کرده. با یه تغییر کوچیک (شروع دوباره از خط اول بعد از هر کاهش موفق) نتیجه بهتر هم میشه.
نویسنده ابزار آمادهی Shrink Ray رو پیشنهاد میده که قانونهای کاهش قدرتمندتری داره و کار رو موازی اجرا میکنه. روی همون مثال C با گزینهی --no-clang-delta (که نمیذاره از دانش خاصش دربارهی زبان C استفاده کنه) بعد از حدود ۱۵ دقیقه ورودی رو بیش از ۶۰٪ کوچیک کرده. یکی از ترفندهای جالبش اینه که عددها رو به مقدارهای کوچیکتر تبدیل میکنه و گاهی چند کاهشِ بهظاهر کوچیک، کلی کاهش دیگه رو باز میکنه؛ نویسنده میگه یه بار بعد از ۲۰ دقیقه، ابزار ورودی رو ۹۹٪ کوچیک کرد و یهو باگ جلوی چشمش پرید بیرون.
بخش بعدی دربارهی اینکه نوشتن تست جالببودن میتونه سخت باشه. خطر اصلی «کاهش بیش از حد»ـه؛ خیلی راحت میشه تستی نوشت که چیزایی رو قبول کنه که نباید، و اونوقت کاهنده از مرز دلخواه عبور میکنه. واسه همین Shrink Ray صراحتاً چک میکنه که تست، ورودی خالی رو قبول نکنه. درس دوم سرعته: هرچی تست سریعتر اجرا بشه کل کاهش سریعتره، چون ممکنه صدها هزار بار اجرا بشه. نویسنده میگه یه بار با خاموشکردن ساختِ خودکار فایلهای core dump، تستش رو حدود سه برابر سریعتر کرده.
قشنگترین کاربرد به گفتهی نویسنده استفاده از این تست برای کمکردن نامعینبودنه. تصور کن یه باگ فقط تو حدود یکسوم اجراها رخ میده (مثلاً تقسیم بر صفری که پشت یه شرط تصادفی پنهونه). اگه کاهنده اون فراخوانی تصادفی رو حذف کنه، باگِ نامعین رو به یه باگِ معین تبدیل میکنه که فهمیدن و رفعش خیلی سادهتره. کاهنده در اصل یه الگوریتم تپهنوردیه که طولِ ورودی رو معیار «بهتر بودن» میگیره، ولی میشه با نوشتن هوشمندانهی تست جالببودن — مثلاً اجرای چندبارهی ورودی و قبولش وقتی خطا دستکم یه بار رخ بده — عاملهای دیگهای مثل فراوانی خطا یا تعداد دستورها رو هم وارد جستوجو کرد.
نکات کلیدی:
- کاهندهی تستکیس بهطور خودکار ورودیِ بزرگِ کرشکننده رو کوچیک میکنه، اغلب ۹۵ تا ۹۹ درصد
- هستهی کار یه «تست جالببودن»ـه که میگه ورودیِ کوچیکشده هنوز همون خطا رو داره یا نه
- ابزار هیچ درکی از معنای برنامه نداره و همین نادونی رازِ کارآمدیشه
- Shrink Ray یه کاهندهی آماده با قانونهای قوی و اجرای موازیه
- میشه با تست هوشمندانه یه باگ نامعین رو به یه باگ معین و قابلتکرار تبدیل کرد




