Ee méi Heisenbug laanscht de Krokodil

Ee méi Heisenbug laanscht de Krokodil

$> set -o pipefail

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

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

et ass fortune bedingt Programm ouni exit(rand()).

Kënnt Dir erklären? wat ass hei falsch?

Lyresch-historeschen Ausdrock

Ech hunn dës Heisenbug fir d'éischt virun engem Véierel Joerhonnert kennegeléiert. Dann fir de Paart am FaxNET war et néideg e puer Utilities ze kreéieren iwwer ëmgeluecht "Spillen Checkers" ënner FreeBSD. Wéi erwaart hunn ech mech als fortgeschratt an zimlech erfuerene Programméierer ugesinn. Dofir hunn ech geduecht alles sou virsiichteg a virsiichteg wéi méiglech ze maachen, besonnesch Opmierksamkeet op Fehlerhandhabung ze bezuelen ...

Meng fréier Erfahrung mam Ëmgang mat Bugs am Sendmail an uucp / uupc huet zu menger Diligence am "gräifend Fehlerhandhabung" bäigefüügt. Et huet kee Sënn fir an d'Detailer vun där Geschicht ze tauchen, mee ech hu mat dëser Heisenbug zwou Woche fir 10-14 Stonnen gekämpft. Dofir gouf et drun erënnert, a gëschter war dësen ale Bekannten nach eng Kéier op Besuch.

TL; DR Äntwert

Utility head kann zoumaachen de Kanal vun fortune сразу soubal hien déi éischt Zeil liest. Wann fortune Ausgab méi wéi eng Zeil, dann de entspriechende Uruff write() wäert e Feeler zréckginn oder bericht datt manner Bytes erausginn wéi ugefrot. Am Tour, schrëftlech mat virsiichteg Feeler Ëmgank fortune huet d'Recht dës Situatioun a sengem Austrëttstatus ze reflektéieren. Dann wéinst Installatioun set -o pipefail wäert schaffen || echo "Вы проиграли".

Awer, head kann et net zu Zäit maachen no virun fortune wäert d'Daten ausginn. Da wäert et schaffen && echo "Повезло!".

An engem vun mengem haut GNUMakefile et gëtt esou Fragmenter:

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

Op Mënsch iwwersat

Et ass hei allgemeng fir GNU Maacht и ze brong am Compiler Manéier benotzt d'Optioun --version et freet wien hien ass, a wann d'Optioun net ënnerstëtzt gëtt, da gëtt e Stéck agebaut "Benotzt w.e.g. GCC oder CLANG kompatibel Compiler".

wëll boilerplate kann iwwerall fonnt ginn. Et ass viru laanger Zäit op dëser Plaz opgetaucht an huet perfekt iwwerall geschafft (Linux, Solaris, OSX, FreeBSD, WSL etc.). Awer gëschter am altlinux op der Plattform Elbrus 2000 (E2K) Ech hu festgestallt:

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

Éierlech gesot, ech hunn meng al "Bekannten" net direkt erkannt. Ausserdeem gouf de Projet scho vill Mol op Elbrus getest an ënner ville verschiddene Verdeelungen, dorënner Alt. Mat verschiddene Compileren, Versioune vu GNU Make a bash. Dofir wollt ech mäi Feeler hei net gesinn.

Wann Dir probéiert de Problem ze reproduzéieren an / oder ze verstoen wat lass war, hunn méi komesch Saachen ugefaang ze geschéien.
Kommandozeil Zauber:

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

Heiansdo géif et extra Text produzéieren, dann net ... Dacks géif eng vun den Optiounen zimlech laang bleiwen, awer wann Dir méi laang gepickt hutt, kritt Dir ëmmer béid!

Natiirlech, strace eis alles! An ech hunn eng Strace Tirade getippt, awer keng Zäit fir Enter ze drécken, hunn ech mäi ale Frënd Här Heisenbug erkannt, an d'Entwéckler compiler ech selwer virun 25 Joer, Nostalgie… An ech hu beschloss traureg ze sinn an dës Notiz ze schreiwen 😉

Iwwregens, wéi all Self-Respekt Heisenbug, ënner strace léiwer net reproduzéieren.

Also wat ass lass?

  • Utility head huet d'Recht (oder besser gesot, ass souguer gezwongen) de Kanal zouzemaachen, dee gelies gëtt, soubal et déi ugefrote Unzuel vun Zeilen liest.
  • Den Date-generéierende Programm-Schrëftsteller (an dësem Fall cc) kann Drécken MÉI Linnen an fräi maachen dëst duerch Multiple Uruff write().
  • wann de Lieser wäert Zäit hunn de Kanal op senger Säit virum Enn vun der Opnam op der Säit vum Schrëftsteller zouzemaachen, da kritt de Schrëftsteller e Feeler.
  • Schrëftsteller Programm Recht op souwuel ignoréieren de Kanal Schreiffehler a reflektéieren et an Ärem Ofschlosscode.
  • Wéinst Installatioun set -o pipefail de Pipeline Fäerdegstellungscode wäert net null sinn (fehlerhaft) wann d'Resultat net null ass vun mindestens engem Element, an da funktionnéiert et || echo "Please use GCC or CLANG compatible compiler".

Et kann Variatioune ginn je wéi de Schrëftsteller Programm Wierker mat Signaler. Zum Beispill kann de Programm abnormal ophalen (mat automatesch Generatioun vun engem Net-Null/Fehlerterminatiounsstatus), oder write() wäert d'Resultat zréckginn fir manner Bytes ze schreiwen wéi gefrot a gesat errno = EPIPE.

Wien ass schëlleg?

Am beschriwwene Fall bëssen vun allem. Feeler Ëmgank an cc (lcc:1.23.20:Sep—4-2019:e2k-v3-linux) ass net iwwerflësseg. A ville Fäll ass et besser op der Säit vu Vorsicht ze falschen, obwuel dëst plötzlech Mängel an engem Kesselplack entworf fir traditionell Verhalen aussetzt.

Wat soll ech maachen?

Falsch:

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

Richteg:

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

    Hei gëtt fréi Schließung vun enger Päif vum Kommando-Interpreter gehandhabt wann Dir déi nested Pipeline servéiert ("bannent" de Klammern). Deementspriechend, wann fortune wäert e Feeler schrëftlech zu engem zougemaach Kanal am Status Rapport, dann den Ausgang || echo "Ошибка" et wäert net iwwerall kommen, well de Kanal scho zou ass.

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

    Hei ass den Utility cat wierkt als Dämpfer well et de Feeler ignoréiert EPIPE beim Austrëtt. Dëst ass genuch fir elo Conclusioun fortune kleng (puer Linnen) a passt am Kanal Prellbock (vu 512 Bytes ze ≈64K, am meeschte OS ≥4K). Soss kann de Problem zréckkommen.

Wéi richteg veraarbecht EPIPE an aner Opnam Feeler?

Et gëtt keng eenzeg richteg Léisung, awer et ginn einfach Empfehlungen:

  • EPIPE erfuerderlech sinn muss veraarbecht ginn (a reflektéiert am Ausgangsstatus) wann Dir Daten ausginn déi Integritéit erfuerderen. Zum Beispill, während der Operatioun vun Archiver oder Backup Utilities.
  • EPIPE besser ze ignoréieren wann Dir Informatioun an Hëllefsmeldungen weist. Zum Beispill, wann Dir Informatioun iwwer Optiounen weist --help oder --version.
  • Wann de Code entwéckelt, kann an enger Pipeline benotzt ginn ier | head, dann EPIPE Et ass besser ze ignoréieren, soss ass et besser ze veraarbecht an am Ausgangsstatus ze reflektéieren.

Ech wëll vun dëser Geleeënheet profitéieren fir d'Equipen meng Dankbarkeet auszedrécken MCST и altlinux fir grouss produktiv Aarbecht. Är Entschlossenheet ass erstaunlech!
Weider sou Camarades, weider Reuniounen am Hierscht!

Spass berez fir Tippfeeler a Feeler ze korrigéieren.
KDPV aus Georgie A.

Source: will.com

Setzt e Commentaire