Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: hazardrok 09. 03. 2020, 08:19:08

Název: Segmentation fault
Přispěvatel: hazardrok 09. 03. 2020, 08:19:08
Ahoj chtěl bych se zeptat na problém se kterým si nevím rady. Napsal jsem si TCP server v Cčku. Občas se mi stane a je to čistě náhodný proces, že mi server spadne. Někdy se to nestane týdny a někdy se to děje několikrát denně. Nebyl jsem schopen dostat z návratové chyby víc než "Segmentation fault" tak jsem zpusil použít GDB. Díky němu mám lepší výpis toho co se tam děje:
Kód: [Vybrat]
Thread 2 "main" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff49e8700 (LWP 30711)]
_int_malloc (av=av@entry=0x7ffff0000020, bytes=bytes@entry=128)
    at malloc.c:3779
3779    malloc.c: No such file or directory.

Z tohodle také moc moudrej nejsem, protože osobně se funkci malloc vyhejbám. Používám jí velice zřídka a snažím se co nejdůsledněji kontrolovat její použití. Kód dokonce spadne v momentě, kdy ani nejsem v bloku jejího volání. Napadá mě tedy jediné a to je, že to způsobuje nějaká knihovna třetí strany. Používám pro řízení filedescriptorů epool což mi zde na fóru někdo poradil a také SQLlite.

Neřešil jste někdo něco podobného nebo nemáte nápad jak se tohoto problému zbavit?
Dík.

Název: Re:Segmentation fault
Přispěvatel: JanoSvitok 09. 03. 2020, 09:53:49
Neporadim ti ako (spytaj sa google, mam pocit ze w ako where) ale potrebujes call stack, cize kto volal malloc.
Mozno to nebude ta funkcia co priamo volala malloc, ale niekolko nad tym. Z call stacku by si mohol vidiet, co je to za thread, a cez ake kniznice to islo. Ked sa nebudes vediet pohnut, napis sem cely call stack.
Název: Re:Segmentation fault
Přispěvatel: registrovany_ava 09. 03. 2020, 10:14:29
Užitečná rada: Zkus si to pustit ve Valgrindu, mohl by ti ukázat, kde špatně zacházíš s pamětí nebo máš nějaké race conditions.
Neužitečná rada: Přepiš to do Rustu :-)
Název: Re:Segmentation fault
Přispěvatel: Daniel Novotný 09. 03. 2020, 10:22:23
nedošla paměť? když malloc teda selhal...

další možnosti řešení:

pusť v tom shellu, kde to pouštíš

Kód: [Vybrat]
ulimit -c unlimited
pak by to místo

Kód: [Vybrat]
Segmentation fault
mělo napsat

Kód: [Vybrat]
Segmentation fault (core dumped)
objeví se ti tam soubor "core" a ty můžeš pustit

Kód: [Vybrat]
gdb název_programu core
abys viděl, v jakém stavu to spadlo
Název: Re:Segmentation fault
Přispěvatel: tecka 09. 03. 2020, 10:24:08
Malloc nepadá sám o sobě, ale když pracuje s pamětí, kterou rozvrtal jiný kód. Může to být poblíž, ale i někde úplně jinde.

Můžeš to zkusit zkompilovat s ASAN nebo spustit ve Valgrindu. To by mělo (mohlo) detekovat problém hned, když k němu dojde.

Z toho, jak jsi měl potřebu zmínit svoji opatrnost, úplně čiší, že s pamětí pracovat neumíš. Tak nepiš v Céčku.
Název: Re:Segmentation fault
Přispěvatel: hazardrok 09. 03. 2020, 11:13:28
Z toho, jak jsi měl potřebu zmínit svoji opatrnost, úplně čiší, že s pamětí pracovat neumíš. Tak nepiš v Céčku.

Můžu se autora zeptat z čeho v mém dotazu vyplývá to, že neumím pracovat z pamětí?

Za komentáře díky. Zkusím rady aplikovat. Co se týče toho komentu
Citace
nedošla paměť? když malloc teda selhal...
tím si nejsem úplně jistej. Mám vyzkoušeno, že pokud dojde paměť, tak se zhroutí celej systém a dojde k jeho restartu. To se mi nikdy nestalo.

Jinak ten server mi běží už pár let a nikdy se mi to nestávalo. Nedávno jsem ale změnil princip řízení filedescriptorů ze select na epoll. To byl poměrně velký zásah a od té doby jsem začal mít tyto problémy. Furt mě to tak trochu směřuje tam.

Doufám, že Vám to všem jde líp než mě :-)
Název: Re:Segmentation fault
Přispěvatel: František Ryšánek 09. 03. 2020, 12:18:12
Pokud malloc() selže kvůli nedostatku paměti, tak nezpůsobí segfault, ale zdvořile vrátí chybový návratový kód.

Říkáte, že to běhalo pár let - na jakém to běží hardwaru? Jestli třeba nevadne hardware. S tou změnou ze select() na epoll() to může být jenom nešťastná náhodná shoda v čase.

Google mi našel dvě žertovná (https://stackoverflow.com/questions/54207983/segmentation-fault-with-epoll) povídání (https://idea.popcount.org/2017-02-20-epoll-is-fundamentally-broken-12/), ale myslím, že to Váš problém neřeší.

Ono způsobů jak někde sáhnout mimo alokovaný kus paměti je spousta - a v mém případě bývá problém obvykle v mém vlastním kódu :-(
Název: Re:Segmentation fault
Přispěvatel: radioing 09. 03. 2020, 13:15:06
1. Call Stack, at vidite, jestli segmentation fault zpusobil vas kod, nebo nejaka knihovna, a zda k segfaultu vedla nejaka prima pricina. Samozrejme na segfault mohlo byt zadelano uz davno pred tim, napr. zapisem spatneho pointeru, nezadoucim prepisem obsahu jiz alokovane a pouzite pameti, dealokace a nasledne pouziti pameti, nebo dokonce poskozeni servisnich informaci buketu mallocu atd. atd. Proto je potreba i
2. Mrknout, co je na malloc.c:3779, a co mohlo byt pricinou toho, ze to tam spadlo.
Název: Re:Segmentation fault
Přispěvatel: m1x 10. 03. 2020, 00:56:28
Podívat se na ten malloc.c:3779, jen pro hrubou představu. Moc se v tom nešťourat.

Pak pustit pod Valgrindem.


Nejspíš někdo zapsal něco do paměťového místa které mu nepatřilo. Třeba: použití pointeru nebo objektu po uvolnění paměti, zápis za konec pole nebo za konec alokované paměti, použití neinicializované proměnné, použití čehokoliv ve více vláknech naráz bez uzamčení, interní cache nějakého pointeru v nějaké knihovně, globální proměnná ve vícevláknovém kódu, knihovna která není multithread-safe, ... cokoliv. Fantazii se meze nekladou. Typicky něco nevinného ale nešikovně použitého. Vznikne chyba, která se třeba nikdy neprojeví. Pak někdo program drobně upraví a chyba která byla spoustu let neviditelná najednou začne prudit. Naprosto nahodile a nereprodukovatelně.

Takovéhle chyby se obvykle projevují mnohem později a úplně jinde než kde byla příčina. Calkstack tedy nemusí dát relevantní informaci. Valgrind by měl najít všechny nedostatky  :P
Název: Re:Segmentation fault
Přispěvatel: _Jenda 10. 03. 2020, 01:25:34
Případně jako alternativu k Valgrindu můžeš zkompilovat s -fsanitize=address (možná na starších překladačích ještě -lasan). Výhoda: je to _řádově_ rychlejší. Nevýhoda: Odhalí to jiné chyby než Valgrind a může se stát, že tomu nějaká chyba unikne (ale na to se musíš hodně snažit nebo mít fakt smůlu).

A samozřejmě bych kompiloval s -g -Og aby tam bylo v gdb dobře vidět věci.
Název: Re:Segmentation fault
Přispěvatel: _Jenda 10. 03. 2020, 01:28:16
nedošla paměť? když malloc teda selhal...
Podle mě při dojití paměti malloc vrátí NULL a uvidíš jeho dereferenci při prvním použití (pokud to nekontroluješ). Btw. neumí malloc selhat nějak „hezky“ (zavolá abort, vypíše barevné hlášky…)? Já když jsem tohle řešil, tak jsem si napsal funkci xalloc, což zavolalo malloc a zkontrolovalo na NULL. A totéž realloc. Je to nesystémové a opruz.
Název: Re:Segmentation fault
Přispěvatel: alex6bbc 10. 03. 2020, 07:13:21
nebo pokud je promenna vytvorena v main tak malloc nahrad normalni promennou na stacku
a kdyz to padne tak to neni mallocem.
Název: Re:Segmentation fault
Přispěvatel: iko 10. 03. 2020, 07:58:33
mozno keby si sem dal zdrojovy kod tak pozreme a vidime chybu
Název: Re:Segmentation fault
Přispěvatel: Vít Šesták (v6ak) 21. 03. 2020, 09:40:32
Chyba práce s pamětí může znamenat, že zapisujete do místa, na které zapisovat nemáte. Pokud máte štěští, nikdo jiný to míšto v paměti nepoužívá a bude to fungovat. Pokud máte smůlu, místo v paměti může používat i někdo jiný. To ale může vést ke kolizím, které nastanou poněkud později a v jiné části kódu, než kde je chyba. A na chování mohou mít vliv i víceméně nesouvisející změny, jako změna ze select na epoll – začne se používat jiný kus paměti, a najednou začne docházet ke kolizi třeba i ve funkci, která je na tom nevinně.

Valgrind toho umí najít spoustu, i když úplně neprůstřelný není. Ale takovéto nástroje jsou dobrým začátkem. Umí detekovat chyby často mnohem dříve, než by se reálně projevily. Často přímo na místě chyby.

Opatrnost na malloc – zase se to nesmí přehnat. Viděl jsem i kód, který slokoval data na stacku a předal pointer na ně. Pokud se ten předaný pointer používá i po návratu z funkce, která ho předala, je to problém. Bylo by věštěním z křišťálové koule, jestli je to Váš případ, ale může být.
Název: Re:Segmentation fault
Přispěvatel: Cikáda 21. 03. 2020, 11:34:12
Pokud máte smůlu, místo v paměti může používat i někdo jiný.

To je spíš štěstí, protože se na to přijde. Ale jinak souhlas.
Název: Re:Segmentation fault
Přispěvatel: hazardrok 31. 03. 2020, 13:41:57
Od doby co jsem ten program spustil přes Valgrind, ani jednou to nespadlo. Je to v podstatě od doby co běží toto vlákno. Když ten program ručně kylnu třeba po několika dnech, vypíše mi to přibližně toto:
Kód: [Vybrat]
==30609==   total heap usage: 7,366,709 allocs, 7,366,674 frees, 686,513,208 bytes allocated
==30609==
==30609== LEAK SUMMARY:
==30609==    definitely lost: 0 bytes in 0 blocks
==30609==    indirectly lost: 0 bytes in 0 blocks
==30609==      possibly lost: 304 bytes in 1 blocks
==30609==    still reachable: 246,510 bytes in 34 blocks
==30609==         suppressed: 0 bytes in 0 blocks
==30609== Rerun with --leak-check=full to see details of leaked memory
==30609==
==30609== For counts of detected and suppressed errors, rerun with: -v
==30609== Use --track-origins=yes to see where uninitialised values come from
==30609== ERROR SUMMARY: 3971 errors from 23 contexts (suppressed: 0 from 0)
Takže stále pátrám...
Název: Re:Segmentation fault
Přispěvatel: J ouda 31. 03. 2020, 14:12:07
Jen taková drobnost. Má to víc threadů?
Jestli jo, nepomůže to linknout s "-z now"?
Název: Re:Segmentation fault
Přispěvatel: hazardrok 01. 04. 2020, 07:52:57
Já ta mám vlákna přesně dvě. Jedno hlavní, které dělá většinu věcí. To druhé dělá jen jednu jedinou věc a tou je příjem SSH spojení. Tento příjem se mi totiž nepovedlo udělat jako neblokující.
Název: Re:Segmentation fault
Přispěvatel: linuxak 01. 04. 2020, 08:24:38
V tom případě Helgrind (https://valgrind.org/docs/manual/hg-manual.html). Ale připrav se na to, že hlásí spoustu false positives pro veškerou sychronizaci, která se nedělá přes pthread sychronizační primitiva, budeš se tím muset probrat
Název: Re:Segmentation fault
Přispěvatel: Vít Šesták (v6ak) 02. 04. 2020, 08:55:54
Dvě hypotézy:

a. Problém se týká práce se stackem, což Valgrind AFAIR nedetekuje. (Ono to ani není snadné u zkompilovaného programu. V případě heapu může nahradit dynamicky linkované funkce pro práci s pamětí, v případě stacku to asi nebude tak jednoduché.)
b. Problém se projeví jen pří souběhu více vláken. AFAIR Valgrind dost omezuje souběžnost vláken.

Zmíněný Helgrind může pomoci na kontrolu problémů se souběžností.

Kontrolu problémů na stacku by moho jít udělat pomocí managed implementace LLVM v GraalVM EE: https://medium.com/graalvm/safe-and-sandboxed-execution-of-native-code-f6096b35c360
* Vyžádá si to ale zkompilovat stejným způsobem i použité knihovny. Nedovedu od stolu vyhodnotit, jak jednoduché nebo náročné to bude v tomto případě.
* Samozřejmě se odchylujete od produkčního prostředí. To není ideální, ale asi se tomu úplně nevyhnete.
* Enterprise Edition je zdarma za určitých podmínek, možná by se tam vešel i tento případ. Rozhodně ale nejsem právník a tento komentář píšu sám za sebe, ne za svého zaměstnavatele.