هڪ وڌيڪ Heisenbug مگرمچرچھ کان گذري ويو

هڪ وڌيڪ Heisenbug مگرمچرچھ کان گذري ويو

$> set -o pipefail

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли

اهو آهي fortune بغير مشروط پروگرام exit(rand()).

ڇا توھان وضاحت ڪري سگھو ٿا؟ هتي ڇا غلط آهي?

شعري-تاريخي تحرڪ

مان پهريون ڀيرو هن هيزن بگ سان هڪ چوٿون صدي اڳ واقف ٿيس. پوءِ FaxNET ۾ گيٽ وي لاءِ ان جي ذريعي ڪيترن ئي افاديت کي ٺاهڻ ضروري هو پائپون مفت بي ايس ڊي جي تحت "چيڪر کيڏڻ". جيئن توقع ڪئي وئي، مون پاڻ کي هڪ ترقي يافته ۽ منصفانه تجربي وارو پروگرامر سمجهيو. تنهن ڪري، مون ارادو ڪيو ته هر شي کي احتياط ۽ احتياط سان ممڪن طور تي، خاص ڌيان ڏيڻ جي غلطي کي سنڀالڻ تي ...

منھنجو اڳوڻو تجربو موڪلڻ واري ميل ۽ uucp/uupc ۾ بگ سان معاملو ڪرڻ جو "مڪمل غلطي سنڀالڻ" ۾ منھنجي محنت ۾ اضافو ٿيو. ان ڪهاڻي جي تفصيلن ۾ ڊائيونگ ڪرڻ جو ڪو به مطلب ناهي، پر مون هن Heisenbug سان ٻن هفتن تائين 10-14 ڪلاڪن تائين جدوجهد ڪئي. تنهن ڪري، اهو ياد اچي ويو، ۽ ڪالهه اهو پراڻي واقفڪار ٻيهر گهمڻ لاء روانو ٿيو.

TL؛ DR جواب

افاديت head ڪري سگهي ٿو کان چينل بند ڪريو fortune فوري طور تي جيئن ئي هو پهرين سٽ پڙهي. جيڪڏهن fortune ھڪڙي لڪير کان وڌيڪ ٻاھر ڪڍندو آھي، پوء لاڳاپيل ڪال write() هڪ غلطي واپس ڪندو يا رپورٽ ڪري ٿو ته گهٽ بائٽس گهربل آهن. موڙ ۾، محتاط غلطي سنڀالڻ سان لکيو ويو fortune هن صورتحال کي ان جي نڪرڻ واري حالت ۾ ظاهر ڪرڻ جو حق آهي. پوء تنصيب جي ڪري set -o pipefail ڪم ڪندو || echo "Вы проиграли".

جڏهن ته، head وقت ۾ نه ٿي سگھي اڳ بند ڪريو fortune ڊيٽا کي ختم ڪري ڇڏيندو. پوء اهو ڪم ڪندو && echo "Повезло!".

منهنجي اڄ جي هڪ ۾ GNUMakefile اهڙو آهي ٽڪرو:

echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'

انسان ۾ ترجمو ڪيو ويو

اهو هتي لاء عام آهي جي اين يو ٺاهيو и ڪشادو اختيار کي استعمال ڪندي گڏ ڪرڻ واري طريقي سان --version اهو پڇي ٿو ته هو ڪير آهي، ۽ جيڪڏهن آپشن سپورٽ نه آهي، پوء هڪ اسٽب داخل ڪيو ويو آهي "مهرباني ڪري استعمال ڪريو GCC يا CLANG مطابقت رکندڙ مرتب ڪندڙ".

پسند ڪريو بوائلر پليٽ ڪٿي به ملي سگهي ٿو. اهو هن جڳهه تي گهڻو وقت اڳ ظاهر ٿيو ۽ مڪمل طور تي هر جڳهه ڪم ڪيو (لينڪس، سولاريس، او ايس ايڪس، فري بي ايس ڊي، WSL وغيره). پر ڪالهه ۾ الٽڪسينڪس پليٽ فارم تي ايلبرس 2000 (E2K) مون نوٽ ڪيو:

#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"

سچ پچ، مون کي فوري طور تي منهنجي پراڻي "واقف" کي سڃاڻي نه سگهيو. ان کان علاوه، پروجيڪٽ اڳ ۾ ئي ايلبرس تي ڪيترائي ڀيرا آزمايا ويا آهن ۽ ڪيترن ئي مختلف تقسيم جي تحت، Alt سميت. مختلف گڏ ڪرڻ وارن سان، GNU ميڪ ۽ بيش جا ورجن. ان ڪري، مان هتي پنهنجي غلطي ڏسڻ نه ٿي چاهيان.

جڏهن مسئلو ٻيهر پيدا ڪرڻ جي ڪوشش ڪئي وئي ۽ / يا سمجهي رهيو هو ته ڇا ٿي رهيو آهي، وڌيڪ عجيب شيون ٿيڻ شروع ٿي.
ڪمانڊ لائن اسپيل:

echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"

هر وقت ۽ پوءِ اهو اضافي ٽيڪسٽ پيدا ڪندو، پوءِ نه... اڪثر اختيارن مان هڪ هڪ ڪافي وقت لاءِ قائم رهندو، پر جيڪڏهن توهان گهڻي وقت تائين پکڙيو، توهان کي هميشه ٻنهي کي ملي ويندو!

يقينن، strace اسان جو سڀ ڪجهه! ۽ هڪ strace tirade ٽائيپ ڪرڻ تي، پر Enter کي دٻائڻ جو وقت نه هجڻ ڪري، مون پنهنجي پراڻي دوست مسٽر هيزن بگ ۽ ڊولپرز کي سڃاڻي ورتو. گڏ ڪرڻ وارو مان 25 سال اڳ، يادگيريون… ۽ مون اداس ٿيڻ جو فيصلو ڪيو ۽ هي نوٽ لکڻ 😉

رستي جي ذريعي، ڪنهن به خود اعتمادي وانگر هائيسن بگ، هيٺ strace ٻيهر پيدا ڪرڻ کي ترجيح نه ڏيندو.

پوءِ ڇا پيو ٿئي؟

  • افاديت head کي حق حاصل آهي (يا بلڪه، مجبور به آهي) ته جيئن ئي پڙهيل چينل کي بند ڪري ڇڏي، جيئن ئي اهو پڙهيل لائينن جو گهربل نمبر پڙهي.
  • ڊيٽا پيدا ڪندڙ پروگرام ليکڪ (هن صورت ۾ cc) ڪري سگهي ٿو پرنٽ گھڻن لائنن ۽ واندو اهو ڪيترن ئي ڪالن ذريعي ڪريو write().
  • ته ليکڪ جي پاسي تي رڪارڊنگ ختم ٿيڻ کان اڳ پڙهندڙ کي پنهنجي پاسي واري چينل کي بند ڪرڻ جو وقت هوندو، پوء ليکڪ کي غلطي ملي ويندي.
  • ليکڪ پروگرام صحيح آهي ٻئي چينل لکڻ جي غلطي کي نظر انداز ڪريو ۽ ان کي توهان جي مڪمل ٿيڻ واري ڪوڊ ۾ ظاهر ڪريو.
  • تنصيب جي ڪري set -o pipefail پائپ لائن مڪمل ڪرڻ جو ڪوڊ غير صفر هوندو (غلط) جيڪڏهن نتيجو گهٽ ۾ گهٽ هڪ عنصر کان غير صفر آهي، ۽ پوء اهو ڪم ڪندو || echo "Please use GCC or CLANG compatible compiler".

اتي مختلف ٿي سگھي ٿو ان تي منحصر ڪري ٿو ته ليکڪ پروگرام سگنلن سان ڪيئن ڪم ڪري ٿو. مثال طور، پروگرام غير معمولي طور تي ختم ٿي سگھي ٿو (غير صفر / غلطي ختم ٿيڻ واري صورتحال جي خودڪار نسل سان)، يا write() گذارش ۽ سيٽ کان گهٽ بائيٽ لکڻ جو نتيجو واپس ڪندو errno = EPIPE.

ڏوهه ڪير؟

بيان ڪيل صورت ۾ هر شيء جو ٿورو. غلطي سنڀالڻ ۾ cc (lcc:1.23.20:Sep—4-2019:e2k-v3-linux) نه آهي بيڪار ڪيترين ئي صورتن ۾ اهو بهتر آهي ته احتياط جي پاسي کان غلطي ڪريو، جيتوڻيڪ اهو روايتي رويي لاء ٺهيل بوائلر پليٽ ۾ اوچتو خامين کي ظاهر ڪري ٿو.

آئون ڇا ڪريان؟

غلط:

fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"

صحيح طور تي

  1. (fortune && echo "Успешно" || echo "Ошибка") | head -1

    هتي، پائپ جي شروعاتي بندش کي ڪمانڊ مترجم طرفان سنڀاليو ويندو جڏهن نيسٽ ٿيل پائپ لائن ("اندر" قوس جي خدمت ڪندي). مطابق، جيڪڏهن fortune اسٽيٽس ۾ بند چينل تي لکڻ ۾ غلطي جي رپورٽ ڪندو، پوءِ ٻاھر || echo "Ошибка" اهو ڪٿي به نه ملندو، ڇو ته چينل اڳ ۾ ئي بند آهي.

  2. fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"

    هتي جي افاديت آهي cat damper طور ڪم ڪري ٿو ڇاڪاڻ ته اهو غلطي کي نظر انداز ڪري ٿو EPIPE واپسي تي. ھاڻي نتيجي لاءِ اھو ئي ڪافي آھي fortune ننڍيون (ڪيترائي لائينون) ۽ چينل بفر ۾ فٽ ٿين ٿيون (512 بائيٽ کان ≈64K تائين، اڪثر OS ≥4K ۾). ٻي صورت ۾ مسئلو واپس ٿي سگهي ٿو.

صحيح طريقي سان ڪيئن عمل ڪجي EPIPE ۽ ٻيون رڪارڊنگ غلطيون؟

ڪو به واحد صحيح حل ناهي، پر هتي سادي سفارشون آهن:

  • EPIPE گھربل عمل ٿيڻ گهرجي (۽ نڪرڻ واري حالت ۾ ظاهر ٿئي ٿو) جڏهن ڊيٽا کي ٻاھر ڪڍيو وڃي ٿو جيڪو سالميت جي ضرورت آھي. مثال طور، آرڪائيورز يا بيڪ اپ افاديت جي آپريشن دوران.
  • EPIPE نظر انداز ڪرڻ بهتر آهي جڏهن معلومات ۽ معاون پيغام ڏيکاريندي. مثال طور، جڏهن اختيارن تي معلومات ڏيکاري ٿي --help يا --version.
  • جيڪڏهن ڪوڊ ترقي ڪئي پئي وڃي ته اڳ ۾ هڪ پائيپ لائين ۾ استعمال ڪري سگهجي ٿو | head، پوء EPIPE اهو نظر انداز ڪرڻ بهتر آهي، ٻي صورت ۾ اهو بهتر آهي ته عمل ڪرڻ ۽ ٻاهر نڪرڻ واري حالت ۾ ڌيان ڏيڻ.

مان هن موقعي تي ٽيمن جي مهرباني جو اظهار ڪرڻ چاهيان ٿو ايم سي ايس ٽي и الٽڪسينڪس عظيم پيداواري ڪم لاءِ. توهان جو عزم شاندار آهي!
ڪيمريڊس، مٿي رکو زوال ۾ ملاقاتون!

Спасибо بيرز ٽائپس ۽ غلطين کي درست ڪرڻ لاء.
KDPV کان جارج اي.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو