Боз як Heisenbug аз тимсоҳ гузашт

Боз як Heisenbug аз тимсоҳ гузашт

$> set -o pipefail

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

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

Ин аст, fortune барномаи шартӣ бе exit(rand()).

Метавонед шарҳ диҳед? дар ин ҷо чӣ шуд?

Баромади лирикй-таърихй

Ман бори аввал бо ин Гейзенбуг чорьяк аср пеш шинос шуда будам. Сипас барои шлюз дар FaxNET лозим буд, ки тавассути якчанд утилитаҳо эҷод кунед қубурҳо "бозии шашка" дар зери FreeBSD. Тавре интизор мерафт, ман худро барномасози пешрафта ва хеле ботаҷриба меҳисобидам. Аз ин рӯ, ман ният доштам, ки ҳама чизро то ҳадди имкон бодиққат ва бодиққат анҷом диҳам ва ба ҳалли хатогиҳо диққати махсус диҳам...

Таҷрибаи қаблии ман дар мубориза бо хатогиҳо дар sendmail ва uucp/uupc ба саъю кӯшиши ман дар “муомилоти ҳамаҷонибаи хатогӣ” илова кард. Ба тафсилоти он ҳикоя ғарқ шудан ҷоиз нест, аммо ман бо ин Ҳейзенбуг ду ҳафта 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')"'

Ба инсон тарҷума шудааст

Дар ин ҷо барои он маъмул аст GNU созед и bash ба таври компилятор бо истифода аз опсия --version аз он мепурсад, ки ӯ кист ва агар ин вариант дастгирӣ нашавад, нотача гузошта мешавад "Лутфан компилятори мувофиқи GCC ё CLANG -ро истифода баред".

Мисли дегдон дар хар чо ёфтан мумкин аст. Он дар ин ҷой кайҳо пеш пайдо шуда буд ва дар ҳама ҷо комилан кор мекард (Linux, Solaris, OSX, FreeBSD, WSL ғайра). Аммо дируз дар altlinux дар платформа Элбрус 2000 (E2K) Ман пай бурдам:

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

Рости ran, ман «ошнои» деринаамро дархол нашинохтам. Ғайр аз он, лоиҳа аллакай борҳо дар Элбрус ва дар доираи паҳнкунии гуногун, аз ҷумла Alt, санҷида шудааст. Бо компиляторҳои гуногун, версияҳои GNU Make ва bash. Аз ин рӯ, ман намехостам хатои худро дар ин ҷо бубинам.

Ҳангоми кӯшиши дубора тавлид кардани мушкилот ва / ё фаҳмидани он, ки чӣ рӯй дода истодааст, чизҳои аҷибтар ба амал омаданд.
Имлои сатри фармон:

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

Ҳар гоҳ ва гоҳ он матни иловагӣ эҷод мекард, пас не... Аксар вақт яке аз вариантҳо муддати тӯлонӣ мемонд, аммо агар шумо дарозтар кашед, шумо ҳамеша ҳардуро мегиред!

Албатта, strace ҳама чизи мо! Ва бо чоп кардани тирад, аммо вақти пахш кардани 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 ҳамчун дампер амал мекунад, зеро он хатогиро нодида мегирад EPIPE ҳангоми хуруҷ. Ҳоло барои хулосабарорӣ ин кофӣ аст fortune хурд (якчанд сатр) ва ба буфери канал мувофиқат мекунад (аз 512 байт то ≈64К, дар аксари OS ≥4K). Дар акси ҳол, мушкилот метавонад баргардад.

Чӣ тавр дуруст коркард кардан EPIPE ва дигар хатогиҳои сабт?

Ҳалли ягонаи дуруст вуҷуд надорад, аммо тавсияҳои оддӣ мавҷуданд:

  • EPIPE талаб карда мешавад бояд коркард карда шавад (ва дар ҳолати баромадан инъикос карда мешавад) ҳангоми баровардани маълумоте, ки якпорчагӣ талаб мекунад. Масалан, ҳангоми кори архивҳо ё утилитаҳои эҳтиётӣ.
  • EPIPE нодида гирифтан беҳтар аст ҳангоми намоиш додани маълумот ва паёмҳои ёрирасон. Масалан, ҳангоми намоиш додани маълумот оид ба вариантҳо --help ё --version.
  • Агар коди таҳияшаванда метавонад дар як лӯлаи пеш истифода шавад | head, он гоҳ EPIPE Беҳтар аст, ки сарфи назар кунед, вагарна беҳтар аст, ки коркард ва инъикос дар ҳолати баромад.

Аз фурсат истифода бурда, мехоҳам ба дастаҳо миннатдории худро баён намоям MCST и altlinux барои кори бузурги пурмахсул. Азми шумо аҷиб аст!
Онро давом диҳед Камарадес, боло вохӯриҳо дар тирамоҳ!

Спасибо берез барои ислоҳи хатогиҳо ва хатогиҳо.
KDPV аз Георгий А.

Манбаъ: will.com

Илова Эзоҳ