Végre egy kis nyomoznivaló php/odbc/oci8 -- segfault

 ( NevemTeve | 2019. április 17., szerda - 15:57 )

Már régen nem volt semmi bajom, hát kipróbáltam egy régebbi unixODBDC-os PHP programocskát.

AIX:
unixODBC-2.3.7
PHP-7.3.4
Oracle-11.2.0.4.0

#0  0x090000000334a51c in lxu4CnvCase () from /opt/lib64/libclntsh.so.11
#1  0x090000000ca8a938 in ?? ()
#2  0x090000000ca8ad8c in ?? ()
#3  0x090000000caaa64c in ?? ()
#4  0x090000000caaa8fc in ?? ()
#5  0x090000000d425088 in SQLPrepare () from /usr/local/lib64/libodbc.so.2
#6  0x000000010082cd84 in zif_odbc_prepare ()
#7  0x00000001000810a8 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER ()
#8  0x000000010019f800 in execute_ex ()
#9  0x000000010019ff3c in zend_execute ()
#10 0x000000010002ef58 in zend_execute_scripts ()
#11 0x000000010000f38c in php_execute_script ()
#12 0x0000000100002ff0 in do_cli ()
#13 0x00000001000045f8 in main ()

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Feliratkozok.

PHP-7.2.17-tel is crash-el?

"Jegyezze fel a vádhoz - utasította Metcalf őrnagy a tizedest, aki tudott gyorsírni. - Tiszteletlenül beszélt a feljebbvalójával, amikor nem pofázott közbe."

Most másképp fogtam a billentyűzetet, ezért a backtrace is informatívabb lett:

#0  0x090000000334a51c in lxu4CnvCase () from /opt/lib64/libclntsh.so.11
#1  0x090000000ca8a938 in bcuFindSQLKeyword () from /opt/lib64/libsqora.so.11
#2  0x090000000ca8ad8c in bcuGetStmtType () from /opt/lib64/libsqora.so.11
#3  0x090000000caaa64c in bccSQLPrepareLckd () from /opt/lib64/libsqora.so.11
#4  0x090000000caaa8fc in SQLPrepareW () from /opt/lib64/libsqora.so.11
#5  0x090000000d425088 in SQLPrepare () from /usr/local/lib64/libodbc.so.2
#6  0x000000010082cd84 in zif_odbc_prepare ()
#7  0x00000001000810a8 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER ()
#8  0x000000010019f800 in execute_ex ()
#9  0x000000010019ff3c in zend_execute ()
#10 0x000000010002ef58 in zend_execute_scripts ()
#11 0x000000010000f38c in php_execute_script ()
#12 0x0000000100002ff0 in do_cli ()
#13 0x00000001000045f8 in main ()

Valahol itt van a baj:

Dump of assembler code from 0x90000000334a4fc to 0x90000000334a53c:
   0x090000000334a4fc <lxu4CnvCase+892>:        ld      r3,0(r3)
   0x090000000334a500 <lxu4CnvCase+896>:        ldx     r0,r3,r4
   0x090000000334a504 <lxu4CnvCase+900>:        add     r3,r0,r6
   0x090000000334a508 <lxu4CnvCase+904>:        lhz     r3,1676(r3)
   0x090000000334a50c <lxu4CnvCase+908>:        b       0x90000000334a398 <lxu4CnvCase+536>
   0x090000000334a510 <lxu4CnvCase+912>:        lhz     r0,82(r30)
   0x090000000334a514 <lxu4CnvCase+916>:        ld      r3,0(r5)
   0x090000000334a518 <lxu4CnvCase+920>:        rlwinm  r4,r0,3,0,28
=> 0x090000000334a51c <lxu4CnvCase+924>:        ld      r3,0(r3)
   0x090000000334a520 <lxu4CnvCase+928>:        ldx     r0,r3,r4
   0x090000000334a524 <lxu4CnvCase+932>:        add     r3,r0,r6
   0x090000000334a528 <lxu4CnvCase+936>:        lhz     r3,1164(r3)
   0x090000000334a52c <lxu4CnvCase+940>:        b       0x90000000334a398 <lxu4CnvCase+536>
   0x090000000334a530 <lxu4CnvCase+944>:        .long 0x0
   0x090000000334a534 <lxu4CnvCase+948>:        .long 0x2043
   0x090000000334a538 <lxu4CnvCase+952>:        lwz     r0,768(r4)

A jó hír az, hogy 12.1-es Oracle InstantClient-tel is dumpol. Az érdekesség meg az, hogy valami 'libodbccr.so' is van a történetben.
Viszont továbbra is a lxu4CnvCase-ben pusztul meg.

Szerk: ha jól látom, a libodbc.so.2 hívja a libodbccr.so-t, de nem olyan sima blikfangtalan módon, hanem a libtdl nevű megkönnyítésen keresztül:

Thread 2 hit Breakpoint 1, 0x09000000000d723c in dlopen () from /usr/lib/libc.a(shr_64.o)
1: (char *)$r3 = 0x1107008d0 "libodbccr.so"
(gdb) bt
#0  0x09000000000d723c in dlopen () from /usr/lib/libc.a(shr_64.o)
#1  0x090000000cd929e8 in vm_open () from /usr/local/lib64/libodbc.so.2
#2  0x090000000cd8a938 in tryall_dlopen () from /usr/local/lib64/libodbc.so.2
#3  0x090000000cd8ce20 in try_dlopen () from /usr/local/lib64/libodbc.so.2
#4  0x090000000cd8d804 in lt_dlopenadvise () from /usr/local/lib64/libodbc.so.2
#5  0x090000000cd8d5fc in lt_dlopen () from /usr/local/lib64/libodbc.so.2
#6  0x090000000cd94c48 in odbc_dlopen () from /usr/local/lib64/libodbc.so.2
#7  0x090000000cd97d98 in __connect_part_two () from /usr/local/lib64/libodbc.so.2

Szerk: Apróság, de legalább egy ".2"-t tegyünk a végére: "libodbccr.so.2".
CPPFLAGS += -DDEFINE_CURSOR_LIB_VER
Mondjuk azt sem értem, miért kell ennek pluginként betöltődnie, miért nincs beleépítv a fő komponensbe, de biztos valami fontos oka van.

Emlékeztető: itten lehetne nyomozni /usr/local/src/unixODBC-2.3.7/DriverManager/SQLPrepare.c

317 s1 = ansi_to_unicode_alloc( statement_text, text_length, statement -> connection, &wlen );

Szerk: relax, csak az zavarta meg a debuggert, hogy egy beágyazott blokkban újrahasznosítottak egy kívül is definiált változónevet (s1). Nyilván nem jutott eszükbe valami új frappáns név, mint pl ws1 (SQLWCHAR *ws1)

Na szóval, az odbc_connect-nek van három opciója a kurzorokat illetően, ebből a SQL_CUR_USE_ODBC (=1) az, amelyiknél segfault jön.

Van egy olyan érzésem, hogy ez a cursor-library egyes funkciókat (drivermanager.h:connection.functions) magára irányít, másokat meg a korábbi állapoton hagy.

    /*
     * if the function is in the cursor lib, pass a additional
     * arg that allows the cursor lib to get the dm handle
     */
#define SQLALLOCHANDLE(con,ht,ih,oh,dmh)\
            (con->cl_handle?\
                    (con->functions[2].func)(ht,ih,oh,dmh):\
                    (con->functions[2].func)(ht,ih,oh))

Rossz esetnél cl_handle töltött, jó esetnél NULL. functions[2] a két esetben:
rossz:

{ordinal = 1001,
 name = 0x90000000121a680 "SQLAllocHandle",
 dm_func = 0x0,
 dm_funcW = 0x0,
 func = 0x9001000a08c7088[u], funcW = 0x0,
 funcA = 0x0,
 can_supply = 1}

jó:

{ordinal = 1001,
 name = 0x90000000c0778d0 <uodbc_get_stats+19756> "SQLAllocHandle",
 dm_func = 0x9001000a11055d8 <_SQLCopyDesc.rw_+952>,
 dm_funcW = 0x0,
 func = [u]0x8001000a0508530,
 funcW = 0x0,
 funcA = 0x0, 
 can_supply = 1}

Ugyanakkor a functions[55] teljesen egyforma.

{ordinal = 0x13, 
 name = 0x90000000c077c90, 
 dm_func = 0x9001000a1105cf8,
 dm_funcW = 0x9001000a1105d10,
 func = 0x0, 
 funcW = 0x8001000a05088f0,
 funcA = 0x0,
 can_supply = 0x1}

Viszont a 'connection->driver_stmt' adatterület különböző. Vagyis az a gyanúm, hogy az Oracle 'SQLPrepareW' rutinját egy olyan paraméterterülettel hívjuk meg, ami nem neki szól (nevezetesen egy cur/cursorlibrary.cl_statement struktúra)

Például azért, mert csak a 'func' mezővel foglalkozik, a 'funcA'-val és a 'funcW'-vel egyáltalán nem.