Korábbi topikokban már írtam, hogy az mc sajnos nagyon elszállós, és ez a hajlama az idő múltával nem csökken hanem inkább verzióról verzióra nő. Leggyakoribb esetek: Kijelölöm inserttel a törölni kívánt fájlokat, F8-at nyomok, mire az mc el-SIGSEGV-zik, és hagy egy core fájlt. Vagy csak ki akarok lépni, F10-et nyomok, mire keletkezik egy core fájl. A jelenség nem determinisztikus, néha előjön, néha nem.
Hogy hardverhibás a gépem. Persze, mind a húsz, és mindegyiknél éppen az mc-ben jön elő a hardverhiba. Más fórumokon is panaszkodnak az F8-as elszállásra. Egy helyen a Fejlesztő Úr azt válaszolta, hogy ő többezer fájlon tesztelte sikeresen az F8-as törlést, és szerinte a program jó. Persze hibás a logikája, millió fájlon végzett sikeres tesztből is csak annyi következik, hogy a program nem biztosan rossz.
Gondoltam, megnézem hol szálldos el az mc. A /etc/rc.local-ba bettettem ezt a sort:
echo '/var/crash/%e-%t.core' >/proc/sys/kernel/core_pattern
Ha ezután bármi elszáll, akkor /var/crash-ben keletkezik egy egyedi core fájl (lásd man core). Az mc esetében ilyesmi:
mc-1452426735.core
Hogy kényelmes legyen nézelődni, az mc-t úgy konfiguráltam, hogy az ilyen fájlon entert ütve rögtön induljon el az adott fájlra a gdb (debugger), amiben a bt parancs mutatja a callstacket. Ilyeneket látok:
...
Core was generated by `mc'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00007f8404de0cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
(gdb) bt
#0 0x00007f8404de0cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1 0x00007f8404de40d8 in __GI_abort () at abort.c:89
#2 0x00007f8404e1d394 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f8404f2bb28 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3 0x00007f8404e2966e in malloc_printerr (ptr=<optimized out>, str=0x7f8404f2bcc8 "free(): invalid next size (fast)", action=1) at malloc.c:4996
#4 _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
#5 0x0000000000471043 in release_hotkey (hotkey=...) at widget-common.c:103
#6 0x000000000048680e in menu_entry_free (entry=0x25464a0) at menu.c:791
#7 0x00007f84053d2648 in g_list_foreach () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#8 0x00007f84053d266b in g_list_free_full () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#9 0x0000000000486991 in destroy_menu (menu=0x25c9060) at menu.c:831
#10 0x00007f84053d2648 in g_list_foreach () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x00007f84053d266b in g_list_free_full () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x0000000000486a82 in menubar_set_menu (menubar=0x25cedb0, menu=0x0) at menu.c:862
#13 0x0000000000486312 in menubar_callback (w=0x25cedb0, sender=0x0, msg=MSG_DESTROY, parm=0, data=0x0) at menu.c:618
#14 0x000000000041c2ea in send_message (w=0x25cedb0, sender=0x0, msg=MSG_DESTROY, parm=0, data=0x0) at ../../lib/widget/widget-common.h:162
#15 0x000000000041c48e in dlg_broadcast_msg_to (h=0x25ce030, msg=MSG_DESTROY, reverse=0, flags=0) at dialog.c:148
#16 0x000000000041dd49 in dlg_broadcast_msg (h=0x25ce030, msg=MSG_DESTROY) at dialog.c:986
#17 0x000000000041e4c4 in dlg_destroy (h=0x25ce030) at dialog.c:1268
#18 0x000000000044b3da in do_nc () at midnight.c:1793
#19 0x00000000004099e2 in main (argc=1, argv=0x7ffeefc18588) at main.c:400
(gdb) q
Ebből annyi látszik, hogy a widget-common.c modul 103. sorában meghívott release_hotkey függvényben következett be a baj. Lássuk, mi van ott:
void
release_hotkey (const hotkey_t hotkey)
{
g_free (hotkey.start);
g_free (hotkey.hotkey);
g_free (hotkey.end); // <-- 103-dik sor
}
Mi a tanulság. A gobject rendszer referenciaszámlálós szemétgyűjtést használ. Ha "valaki" használ egy objektumot, azaz referenciát tart fenn az objektumra, az megnöveli 1-gyel az objektumban tárolt referenciaszámlálót. Ha már nem kell az objektum, akkor meg 1-gyel csökkenti. Az objektum figyeli a saját referenciaszámlálóját, és ha a számláló 0-ra csökken, az azt jelenti, hogy már senkinek sincs rá szüksége, és megszünteti magát. Egyszerű, de sajnos több sebből vérző módszer. Ott vannak a körök. Ha az objektumok kölcsönösen referenciát tartanak fenn egymásra, akkor a referenciszámlálójuk sosem csökken 0-ra, zárványként beragadnak. Még nagyobb baj, hogy a referenciaszámláló módosítgatása sok esetben az alkalmazási program részévé válik, és nem világos, hogy kinek, és milyen időzítéssel kell elvégezni a módosítást. Az mc esetében is ez lehet a baj. A program g_free-vel meg akar szüntetni egy olyan objektumot, amelynek (vagy egy beágyazott objektumának) a refszámlálója korábban (tévesen) már le volt csökkentve. Na és persze a program elszállása, nem a hiba elkövetésekor következik be, hanem jóval később. Vagyis a hiba helyéről nem tudtunk meg semmit. Az ilyet baromi nehéz kinyomozni.
A referenciaszámlálós szemétgyűjtést nem is tekintik igazi szemétgyűjtésnek. Őszintén szólva az IT tudományban dilettáns modszernek számít. Éppen ezért kár, hogy ilyen rendszerek, mint a gtk (gnome, xfce4), python, referenciaszámlálós szemétgyűjtésre épülnek. Agyaglábakon állnak.