Un Heisenbug arall heibio'r crocodeil

Un Heisenbug arall heibio'r crocodeil

$> set -o pipefail

$> fortune | head -1 > /dev/null && echo "ПовСзло!" || echo "Π’Ρ‹ ΠΏΡ€ΠΎΠΈΠ³Ρ€Π°Π»ΠΈ"
ПовСзло!

$> fortune | head -1 > /dev/null && echo "ПовСзло!" || echo "Π’Ρ‹ ΠΏΡ€ΠΎΠΈΠ³Ρ€Π°Π»ΠΈ"
Π’Ρ‹ ΠΏΡ€ΠΎΠΈΠ³Ρ€Π°Π»ΠΈ

Yma fortune rhaglen amodol heb exit(rand()).

Allwch chi esbonio? beth sy'n bod yma?

Digression telynegol-hanesyddol

Deuthum yn gyfarwydd Γ’'r Heisenbug hwn gyntaf chwarter canrif yn Γ΄l. Yna ar gyfer y porth yn FaxNET roedd angen creu sawl cyfleustodau trwy pibellau "chwarae siecwyr" o dan FreeBSD. Yn Γ΄l y disgwyl, roeddwn yn ystyried fy hun yn rhaglennydd datblygedig a gweddol brofiadol. Felly, roeddwn yn bwriadu gwneud popeth mor ofalus a gofalus Γ’ phosibl, gan roi sylw arbennig i drin gwallau ...

Ychwanegodd fy mhrofiad blaenorol o ddelio Γ’ bygiau mewn sendmail ac uucp/uupc at fy niwydrwydd wrth β€œdrin gwallau trwyadl.” Nid oes diben plymio i fanylion y stori honno, ond bΓ»m yn cael trafferth gyda'r Heisenbug hwn am bythefnos am 10-14 awr. Felly, Cofiwyd, a ddoe arhosodd yr hen gydnabod hwn i ymweld eto.

TL; DR Ateb

Cyfleustodau head Gall cau'r sianel o fortune ar unwaith cyn gynted ag y darlleno y llinell gyntaf. Os fortune yn allbynnu mwy nag un llinell, yna'r alwad gyfatebol write() yn dychwelyd gwall neu'n adrodd bod llai o beit yn cael ei allbwn nag y gofynnwyd amdano. Yn ei dro, wedi'i ysgrifennu gan drin gwallau yn ofalus fortune yr hawl i adlewyrchu'r sefyllfa hon yn ei statws ymadael. Yna oherwydd gosod set -o pipefail bydd yn gweithio || echo "Π’Ρ‹ ΠΏΡ€ΠΎΠΈΠ³Ρ€Π°Π»ΠΈ".

Fodd bynnag, head efallai na fydd yn ei wneud mewn pryd cau o'r blaen fortune yn gorffen allbynnu data. Yna bydd yn gweithio && echo "ПовСзло!".

Yn un o fy heddiw GNUMakefile mae un darniad:

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

Wedi'i gyfieithu i ddynol

Mae'n gyffredin yma am GNU Gwneud ΠΈ bash yn y ffordd casglwr gan ddefnyddio'r opsiwn --version mae'n gofyn pwy ydyw, ac os na chefnogir yr opsiwn, yna gosodir bonyn "Defnyddiwch casglwr cydnaws GCC neu CLANG".

Fel plΓ’t boeler i'w gael yn unrhyw le. Ymddangosodd yn y lle hwn amser maith yn Γ΄l a gweithiodd yn berffaith ym mhobman (Linux, Solaris, OSX, FreeBSD, WSL ac ati). Ond ddoe yn altlinux ar y platfform Elbrus 2000 (E2K) Sylwais:

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

A dweud y gwir, wnes i ddim adnabod fy hen β€œgydnabod.” Ar ben hynny, mae'r prosiect eisoes wedi'i brofi sawl gwaith ar Elbrus ac o dan lawer o wahanol ddosbarthiadau, gan gynnwys Alt. Gyda chasglwyr amrywiol, fersiynau o GNU Make a bash. Felly, doeddwn i ddim eisiau gweld fy nghamgymeriad yma.

Wrth geisio atgynhyrchu'r broblem a/neu ddeall beth oedd yn digwydd, dechreuodd pethau rhyfeddach ddigwydd.
Sillafu llinell orchymyn:

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

O bryd i'w gilydd byddai'n cynhyrchu testun ychwanegol, yna ddim... Yn aml byddai un o'r opsiynau yn aros am amser eithaf hir, ond pe byddech chi'n pocio'n hirach, roedd gennych chi'r ddau bob amser!

Wrth gwrs, strace ein popeth! Ac ar Γ΄l teipio tirade strace, ond heb gael amser i bwyso Enter, fe wnes i adnabod fy hen ffrind Mr Heisenbug, a'r datblygwyr crynhoydd fy hun 25 mlynedd yn Γ΄l, Nostalgie… A phenderfynais fod yn drist ac ysgrifennu'r nodyn hwn πŸ˜‰

Gyda llaw, fel unrhyw hunan-barch Heisenbug, dan strace well ganddo beidio ag atgynhyrchu.

Felly beth sy'n mynd ymlaen?

  • Cyfleustodau head Γ’'r hawl (neu yn hytrach yn cael ei orfodi hyd yn oed) i gau'r sianel sy'n cael ei darllen cyn gynted ag y bydd yn darllen y nifer o linellau y gofynnwyd amdanynt.
  • Ysgrifennwr y rhaglen cynhyrchu data (yn yr achos hwn cc) Gall argraffu llinellau lluosog a rhydd gwneud hyn trwy alwadau lluosog write().
  • Os bydd gan y darllenydd amser i gau'r sianel ar ei ochr cyn diwedd y recordio ar ochr yr awdur, yna bydd yr awdur yn derbyn gwall.
  • Rhaglen awdur mae ganddo'r hawl mae'r ddau yn anwybyddu gwall ysgrifennu'r sianel ac yn ei adlewyrchu yn eich cod cwblhau.
  • Oherwydd gosod set -o pipefail bydd cod cwblhau'r biblinell yn ddi-sero (gwallus) os yw'r canlyniad yn ddi-sero o un elfen o leiaf, ac yna bydd yn gweithio || echo "Please use GCC or CLANG compatible compiler".

Efallai y bydd amrywiadau yn dibynnu ar sut mae'r rhaglen awdur yn gweithio gyda signalau. Er enghraifft, gall y rhaglen ddod i ben yn annormal (gyda chynhyrchu statws terfynu di-sero/gwall yn awtomatig), neu write() yn dychwelyd canlyniad ysgrifennu llai o beit nag y gofynnwyd amdano ac a osodwyd errno = EPIPE.

Pwy sydd ar fai?

Yn yr achos a ddisgrifir ychydig bach o bopeth. Gwall wrth drin yn cc (lcc:1.23.20:Sepβ€”4-2019:e2k-v3-linux) ddim segur. Mewn llawer o achosion mae'n well bod yn ofalus, er bod hyn yn amlygu diffygion sydyn mewn plΓ’t boeler sydd wedi'i gynllunio ar gyfer ymddygiad traddodiadol.

Beth i'w wneud?

Anghywir:

fortune | head -1 && echo "ПовСзло, Π½ΠΎ Π²Ρ‹ рискуСтС!" || echo "WTF?"

Yn gywir:

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

    Yma, bydd cau pibell yn gynnar yn cael ei drin gan y cyfieithydd gorchymyn wrth wasanaethu'r biblinell nythu ("o fewn" y cromfachau). Yn unol Ò hynny, os fortune yn adrodd gwall yn ysgrifenedig i sianel gaeedig yn y statws, yna'r allbwn || echo "Ошибка" ni fydd yn cyrraedd unrhyw le, gan fod y sianel eisoes ar gau.

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

    Dyma'r cyfleustodau cat yn gweithredu fel damper oherwydd ei fod yn anwybyddu'r gwall EPIPE wrth dynnu'n Γ΄l. Mae hyn yn ddigon am y tro casgliad fortune bach (sawl llinell) ac yn ffitio yn y byffer sianel (o 512 beit i β‰ˆ64K, yn y rhan fwyaf o OS β‰₯4K). Fel arall, efallai y bydd y broblem yn dychwelyd.

Sut i brosesu'n gywir EPIPE a gwallau cofnodi eraill?

Nid oes un ateb cywir, ond mae yna argymhellion syml:

  • EPIPE yn ofynnol rhaid ei brosesu (ac a adlewyrchir yn y statws ymadael) wrth allbynnu data sy'n gofyn am gywirdeb. Er enghraifft, yn ystod gweithrediad archifwyr neu gyfleustodau wrth gefn.
  • EPIPE well anwybyddu wrth arddangos gwybodaeth a negeseuon ategol. Er enghraifft, wrth arddangos gwybodaeth am opsiynau --help neu --version.
  • Os gellir defnyddio'r cod sy'n cael ei ddatblygu ar y gweill o'r blaen | head, Yna EPIPE Mae'n well anwybyddu, fel arall mae'n well prosesu a myfyrio yn y statws ymadael.

Hoffwn achub ar y cyfle hwn i fynegi fy niolch i’r timau MCST ΠΈ altlinux am waith cynhyrchiol gwych. Mae eich penderfyniad yn anhygoel!
Daliwch ati Camaradau, i fyny cyfarfodydd yn y cwymp!

Diolch berez ar gyfer cywiro teipiau a gwallau.
KDPV oddi wrth George A.

Ffynhonnell: hab.com

Ychwanegu sylw