Ilyet sem tud az AIX (fpc hiba kombinálva glibc hibával)

A mai debuggolástól kellemesen elfáradva (vö TV-torna), az jutott eszembe, hogy ezt a hibát a korszerűtlen kényelmetlen AIX-on sehogy vagy legalább is sokkal nehezebben lehetne előadni.

Hozzászólások

Szerkesztve: 2020. 01. 30., cs – 22:52

Az egyszerű, mindennapos történet a következő láncolatban írható le:

User php-scriptet futtat, benne ffi-hívás egy pluginra

PHP betölti a libffi-t

libffi betölti a plugin-t

A plugin betölti (illetve hozza magával) a libglib-2.0.so-t

libglib-nek calloc kellene

A linker-loader valamilyen hibás linkelési opciók illetve a holdállás miatt nem a libc.so-ból, hanem a ld-linux-x86_64.so-ból húz elő egy calloc-ot.

Ez a spéci calloc vissza van vezetve a szintén spéci malloc-ra, amely tiszta memóriát ad vissza, tehát nem kell memset/bzero.

De a dinamikus linkelés egyik csodálatos eredményeképpen nem a spéci malloc hívódik, hanem a közönséges (a libc.so-beli).

Szóval a glib-2.0 (és talán más komponensek) működése innentől kezdve egy olyan calloc-on alapul, ami nem tiszta memóriát ad vissza. Találgathatunk, hogy mi lesz ennek az eredménye. [Szerk: Elárulom: már a libglib-2.0.so konstruktora megpusztul.]

 

Részletek itt: 

https://www.linuxquestions.org/questions/programming-9/debugging-dlopen…

 

Na és hogy az AIX-on mi a pálya? Ott linkeleskor [tipikusan] nem az kerül az outputfájlba, hogy `depends on calloc` hanem az, hogy `depends on libc.a(shr64.so):calloc` illetve haladó esetben: `depends on /usr/lib/libc.a(shr64.so):calloc`.

Ez a spéci calloc vissza van vezetve a szintén spéci malloc-ra, amely tiszta memóriát ad vissza, tehát nem kell memset/bzero.

Also 'calloc' in 'ld.linux' calls 'malloc', but doesn't call 'memset' -- guess it assumes 'malloc' returns cleared memory.

Ezt miért kellett így implementálni? A malloc() per definition inicializálatlan memóriát ad vissza; értem én, hogy itt "spéci" malloc-ról beszélünk, de IMHO ez akkor is bad practice, amint a végeredmény is mutatja.

Lehet, hogy hülye vagyok, de ha megszakadok sem értem az összefüggést: ha adott platformon nincs malloc, akkor úgy próbálják meg a dolgot feloldani, hogy a calloc a platformtól függetlenül szembemegy a definícióval és úgy veszi, hogy a malloc inicializált területet ad vissza? Vagy nem jól értem?

Hát azt én nem tudom, hogy mire gondoltak tákolás közben, de rendes lett volna tőlük, hogy ha tényleg saját memóriakezelésre volt szükség (mondjuk a legelején a betöltésnek), azt valamilyen más néven fejlesztik ki, és nem is exportálják (még Weak symbolként sem).

Viszont valaki reagált a bugreportra: https://sourceware.org/bugzilla/show_bug.cgi?id=25486

Hát igen. Ez van, ha valaki direkt szembemegy a lefektetett konvenciókkal.

Ez a válasz, hogy "adjust the link order"? Ez még workaroundnak sem jó, hiszen ahhoz, hogy ezt valaki megtegye egy ilyen helyzetben, ahhoz az kell, hogy tudja mi történik. Te rájöttél, mert értesz hozzá, de mit kezd ezzel a helyzettel valaki, aki csak PHP-ben ügyködik és belefut ebbe a PHP->ffi->plugin->glib->bad calloc felállásba?

Ennyire nem egyszerű a történet, ez egy shared lib, ami maga is számos más shared libre dependál... Az SO-ra belinkelte a kolléga a forrást, sajnos én nem tudok portugálul, és nem értek a FP-höz; ami test-et csináltam fp-2.4.6-tal, abba nem került bele ez a problémás dependencia... Bőven függhet pl. az FP-verziójától, vagy csak valaki valamit rosszul csinált...

https://stackoverflow.com/questions/59956996/problem-loading-a-library-…

http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/

Ha a lib FP-ben van írva, akkor baromi érdekes lenne, ha ilyen linkelési problémája lenne (mármint a calloc/malloc mizéria), mert az FP saját memóriakezelést és minden egyéb a futásához szükséges cuccot statikusan fordít bele a binárisba: zéró libc függése van, nem hív se malloc-ot, se calloc-ot. Az más kérdés, ha valami külső lib cuccait hívogatja, de az nem része a runtime-nak; viszont memóriakezelési függvényeket minek hívogatna a libc-ből?

Lecsekkoltam az lpi-t, így hirtelen nem látok benne semmi külső függőséget, de lehet elsiklottam felette. Majd holnap leforgatom magamnál.

A fél világ bele van húzva; ilyen a readelf kimenete [a kérdező kolléga megadta a google-drive-ján a SO-n a kérdésben]:

$ readelf -d libacbrnfe64.so

Dynamic section at offset 0xaf0c40 contains 42 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgdk-x11-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libX11.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgdk_pixbuf-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgtk-x11-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgobject-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libglib-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgthread-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgmodule-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libcairo.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libatk-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libxml2.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpangocairo-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libacbrnfe64.so]

Ahogy debuggoltam, a gondra a glib-2.0.so constructora szaladt rá; közben lett egy kicsit kevésbé mesterkélt példa Pascal nélkül, az is jópofa:

$ php demodule.php
demodule.init: calloc is at 0x7f29ce261b40 returned 0x1f10db0 first 8 bytes: 7f29cb90e698
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFe-change-log.txt
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFe.lpi
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFe.lpr
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeClass.pas
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeConfig.pas
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeConsts.pas
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeDataModule.lfm
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeDataModule.pas
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeRespostas.pas
# wget http://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Fontes/NFe/ACBrLibNFeStaticImport.pas
# lazbuild ACBrLibNFe.lpi
### TCodeToolManager.HandleException: [20170422130152] "include file not found "ACBr.inc"" at Line=34 Col=5 in "/root/ize/ACBrLibNFe.lpr"
Error: (lazbuild) Broken dependency: ACBr_Integrador

Hiányos a forrás, az "ACBr.inc" fájl nincs feltöltve a többi közé, anélkül pedig nem lehet lefordítani.

Egyébként ahogy nézem a linkelt depeket, ez nem a fél világ, csak egy GTK2-es program futásához szükséges dynlibek (GTK, GDK, ATK, X11, threadek, Cairo, stb.). Amit nem értek, hogy az ld miért függőség. (A libc-t gondolom azért, mert a többi library igényli.)

program test;
begin
end.
# fpc -O3 -CX -Xs -XX test.pas
# readelf -d test
There is no dynamic section in this file.

Egy FP program alapesetben nem függ a kernelen kívül semmitől.

Related: https://hup.hu/comment/1738037#comment-1738037

Ott az volt a gond, hogy linuxon a bash.exe meg a libreadline.so boldog vegyülésben élnek: ha mindkettőnek van 'setenv' nevű függvénye, akkor az nyer, akit először töltöttek be (ez rendszerint a bash.exe), annak a setenv-jét használják mind a ketten.

Aix-on meg ez messze nem szokás, mondatni sosem láttam ilyen beállítással linkelt termékez.

Szerkesztve: 2020. 02. 03., h – 12:16

Valamit látni vélek a fpc-3.0.4 forrásában, ami összefügghet a problémával; elsősorban most láncot építek a verziókból, hogy hátha a 2.6.4-ről eljutok oda valamiféleképpen. Egyelőre 2.6.4 nem viszi a 3.0.2-t, folyt köv.


   480        { Write sharedlibraries like -l, also add the needed dynamic linker
   481          here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
   482        if (isdll) then
   483         begin
   484           Add('INPUT(');
   485           Add(info.DynamicLinker);
   486           Add(')');
   487         end;

Szerk:
20200203.1143: most fordul a 3.0.0
20200203.1156: lement, de valami jószándékú segítő komponens még van itt valahol:


$ ls -l /usr/local/bin/fpc
-rwxr-xr-x 1 root root 430560 Feb  3 11:44 /usr/local/bin/fpc
$ /usr/local/bin/fpc -v
Free Pascal Compiler version 2.6.4+dfsg-4 [2014/10/14] for x86_64

20200203.1205: Sikeresen telepítette a komponenseket (pl. ppcx64) a /usr/local/lib/fpc/3.0.0 könyvtárba. Csak nem ott keresi őket a fpc.exe ... Persze aki harminc éve van az iparban, az már nem lepődik meg egy kis bénázáson;)

20200203.1211: No, már a 3.0.0 is mutatja a hibát. Source


LIBRARY paslib;

USES initc;

FUNCTION g_malloc (len: longint): PChar; external 'libglib-2.0.so';
FUNCTION dlopen (filename: PChar; flags: integer): PChar; external 'libdl.so';
FUNCTION xmlAddChildList (fake: PChar): PChar; external 'libxml2.so';

PROCEDURE _init;
BEGIN
    WriteLn ('Hello from Pascal');
END;

FUNCTION fun1 (a, b: integer): integer;
BEGIN
    fun1 := a + b;
END;

EXPORTS
    fun1;
END.

fordítás:


$ fpc -g paslib.pas
Free Pascal Compiler version 3.0.0 [2020/02/03] for x86_64
Copyright (c) 1993-2015 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling paslib.pas
Linking libpaslib.so

hiba bemutatása:


$ readelf -d libpaslib.so
Dynamic section at offset 0x2b018 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libglib-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libxml2.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libpaslib.so]

Szóval két kishibás program (fpc és ld-linux) így találkozott össze szerencsésen.

Az fpc 2.6.4 tényleg nem csinálja. Összehasonlítottam a két fpc.cfg-t, de semmi érdemlegeset nem találtam. Talán valamelyik újabb forrás/unit is csinálhatja, vagy tényleg a compiler. (A compiler flagek közt nincs, ami ezt szabályozná.) Jelented az FPC fejlesztőknek?

Egyébként, ha a függvénydeklarációkat és az initc unit behívását ki is szeded, az ld akkor is függőség marad. Minden más repül, de az marad.

A verziókövetőjük itt van: https://www.freepascal.org/docs-html/current/user/userse73.html

Szerintem itt ez az érintett revízió: svn log ./compiler/systems/t_linux.pas

r19036 | tom_at_work | 2011-09-08 23:17:35 +0200 (cs, 08 szept 2011) | 27 lines

Fix shared library loading and unloading for Linux platforms. Shared library initialization and finalization are now called correctly at program startup for compile-time linked dynamic libraries on powerpc-/powerpc64-/arm-/i386- and x86_64-linux.

...

svn cat -r 19036 ./compiler/systems/t_linux.pas > t_linux.pas.r19036
svn cat -r 17889 ./compiler/systems/t_linux.pas > t_linux.pas.r17889
diff -U 3 -dHrN -- t_linux.pas.r17889 t_linux.pas.r19036
--- t_linux.pas.r17889  2020-02-03 15:48:19.279515276 +0100
+++ t_linux.pas.r19036  2020-02-03 15:47:58.047515352 +0100
@@ -330,6 +330,7 @@
   s,s1,s2      : TCmdStr;
   found1,
   found2       : boolean;
+  linksToSharedLibFiles : boolean;
 begin
   result:=False;
 { set special options for some targets }
@@ -432,6 +433,13 @@

       { Write sharedlibraries like -l, also add the needed dynamic linker
         here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
+      if (isdll) then
+       begin
+         Add('INPUT(');
+         Add(info.DynamicLinker);
+         Add(')');
+       end;
+      linksToSharedLibFiles := not SharedLibFiles.Empty;

       if not SharedLibFiles.Empty then
        begin
@@ -497,8 +505,13 @@
           end;
        end;

-      {Entry point.}
-      add('ENTRY(_start)');
+      {Entry point. Only needed for executables, set on the linker command line for
+       shared libraries. }
+      if (not isdll) then
+       if (linksToSharedLibFiles and not linklibc) then
+        add('ENTRY(_dynamic_start)')
+       else
+        add('ENTRY(_start)');

 {$ifdef x86_64}
 {$define LINKERSCRIPT_INCLUDED}
@@ -641,7 +654,6 @@
           add('OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",');
           add('              "elf32-littlearm")');
           add('OUTPUT_ARCH(arm)');
-          add('ENTRY(_start)');
           add('SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");');
           add('SECTIONS');
           add('{');

Csak az az érdekes, hogy ez egy 2011-es commit, a 2.6.0 pedig 2012-es...de lehet, hogy addigra már feature freeze volt a 2.5-dev ágban, ez pedig a 2.7-dev ágban keletkezett.