php-7.0.10 fordítása (AIX újabb kalandjai)

(Felülről lefelé bővül)

20160908.1240
Itten van írásba foglalva (komoly tolongásra azért nem számítok): https://bugs.php.net/bug.php?id=73002#1473330938

20160908.1135
Az a hülye ötletem támadt, hogy alaposabban tesztelem a fejlesztésemet... Nem kellett volna, bugra szaladtam a "csak-be" típusú bind-változóknál.

Ha ez a saját programocskám lenne, akkor a 'php_oci_bind' struktúrából a 'dummy_len' című mezőt kiszedném, és helyette 'maximum_length', 'in_length' és 'out_length' mezőket csinálnék, plusz egy jelzőt, hogy hívódott-e a 'bind_out_callback'.

Ugyanis, ha nem hívódott, akkor az Ora nyilván "csak-be" értelemben használta azt a változót, tehát a 'bind_post_exec'-nek semmit sem kell csinálni vele.

Namost ezt nem merem ("túl nagy módosítás" -- bár nem tudom, miért aggódom, hiszen így sem érdekelt senkit a bug-report), tehát a tákolás-bákolás folyamán a 'dummy_len' a következő pályát fogja befutni:

bind_by_name: belerakjuk a maximum értéket vagy ha az nincs, a string hosszát, vagy valamilyen jó nagy számot (itt nem változtattam semmit)

bind_in_callback: maximum-értékként használjuk (ha az aktuális érték ennél hosszabb, azt levágjuk), azután beállítjuk az aktuális hosszra -- ez utóbbi az új fejlesztés

bind_out_callback: átadjuk 'dummy_len' címét az Orának, hogy ebbe tegye a visszajövő érték hosszát -- ez is új, eddig a zend-string-változó hosszmezőjének címe ment, itt volt típusinkompatibilitás 'size_t' és 'ub4' között (BigEndian 64 patform!)

bind_post_exec: 'dummy_len'-ből vesszük a string hosszát

Említsük meg, hogy a bind_in_callback mindig meghívódik, a bind_out_callback meg csak a kimenő változókra, tehát a csodás tákolásnak mindkét esetben jól kell működnie. (Megjegyzés: látszólag háromféle bind-változó-használat van: IN, OUT és IN OUT, de a valóságban az 'OUT' is 'IN OUT', ezért tanácsos a kimenő változókat NULL-ra állítani hívás előtt.)

20160902.1315
Na ennyit mára a tudomány és a technika újdonságaiból.
https://bugs.php.net/bug.php?id=73002

20160902.1200
Itt is vélek látni valami zavart:


(gdb) p *alenpp
$12 = (ub4 *) 0x70000000009e010
(gdb) p *bufpp 
$13 = (void *) 0x70000000009e018

(gdb) ptype val->value.str[0]
type = struct _zend_string {
70000000009e000    zend_refcounted_h gc;
70000000009e008    zend_ulong h;
70000000009e010    size_t len; /* ez itten 64-bites, big endian */
70000000009e018    char val[1];
}

20160902.1115
Ilyen a zend_string:


struct _zend_string {
    zend_refcounted_h gc;
    zend_ulong        h;                /* hash value */
    size_t            len;
    char              val[1];
};

Ilyen a zend_string_init:


static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
{
    zend_string *ret = zend_string_alloc(len, persistent);

    memcpy(ZSTR_VAL(ret), str, len);
    ZSTR_VAL(ret)[len] = '\0';
    return ret;
}

és a zend_string_alloc:


static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
{
    zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);

    GC_REFCOUNT(ret) = 1;
#if 1
    /* optimized single assignment */
    GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
#else
    GC_TYPE(ret) = IS_STRING;
    GC_FLAGS(ret) = (persistent ? IS_STR_PERSISTENT : 0);
    GC_INFO(ret) = 0;
#endif
    zend_string_forget_hash_val(ret);
    ZSTR_LEN(ret) = len;
    return ret;
}

20160902.1040
Szóval van egy ilyen, hogy


ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE);

ennek a végén *(val->value.str) kellene legyen az újonnan foglalt buffer. Ehhez képest val->value.str->val==NULL
Ez lenne a makrókifejtés eredménye:


ZVAL_NEW_STR(val, zend_string_init(p, PHP_OCI_PIECE_SIZE, 0));

ennek a kifejtése:


{
    zval *__z = (val);
    zend_string *__s = (zend_string_init(p, PHP_OCI_PIECE_SIZE, 0));
    Z_STR_P(__z) = __s;
    Z_TYPE_INFO_P(__z) = IS_STRING_EX;
}

Talán a zend_string_init ad vissza NULL-pointert?

20160902.0940
Következik a OCIBindDynamic, különös tekintettel a 'php_oci_bind_out_callback' nevű függvényre.

20160902.0935
Most úgy tűnik, hogy az OCIBindByName hatodik paramétere (valuep) egységesen nulla. Nyomozást folytatni.

20160902.0850
Tehát most itt tartunk:


#if PHP_MAJOR_VERSION > 6
    #define my_RETURN_STRINGL_DUPLICATE(s,l) RETURN_STRINGL((s),(l))
    typedef size_t TStrParamLen;
#else
    #define my_RETURN_STRINGL_DUPLICATE(s,l) RETURN_STRINGL((s),(l),1)
    typedef int TStrParamLen;
    typedef long zend_long;
#endif

20160902.0840
Közben arra vélek gondolni, hogy a 'zend_long' típus az olyan jópofa LLP64-es rendszerek miatt van, amilyen a Windows64... van is ott egy vizsgálat:


#if defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || \
    defined(_WIN64)
# define ZEND_ENABLE_ZVAL_LONG64 1
#endif

(Mondjuk az 'intptr_t'-t is használnánk ilyesmire, de a 'zend_long' szebben cseng)

20160902.0755
linuxon megy ugyanez php7-ben. Nem azonos Oracle-verzió ugyan (11 vs 12).

20160902.0725
Itt egy kódrészlet, ami eltérően működik php5-ben és php7-ben:


    $sql= 'BEGIN SELECT ename INTO :ename FROM emp WHERE empno=:empno; END;';
    $stmt= oci_parse ($conn, $sql);
    if ($conn===FALSE) {
        $e= oci_error ($conn);
        $errstr= $e['message'];
        goto RETURN_;
    }

    $rc= @oci_bind_by_name ($stmt, ":empno",  $empno);
    if (!$rc) {
        $e = oci_error ($stmt);
        $errstr= $e['message'];
        goto RETURN_;
    }
    $rc= @oci_bind_by_name ($stmt, ":ename",  $ename, 64, SQLT_CHR);
    if (!$rc) {
        $e = oci_error ($stmt);
        $errstr= $e['message'];
        goto RETURN_;
    }

    $rc= oci_execute ($stmt);
    if (!$rc) {
        $e = oci_error ($stmt);
        $errstr= $e['message'];
        goto RETURN_;
    }

Ez a hibaüzenet php7-ben:


oci_execute(): ORA-03131: an invalid buffer was provided for the next piece

A $ename üres stringként volt inicializálva az oci_bind előtt. Akkor most mi legyen?

20160902.0705
Rendkívül frappánsan menet közben váltunk irányt, ezentúl az elején lesz a bővülés.
Szóval az oci8 nem annyira megy, mint amennyire nem. Persze egy sima SELECT megy, de most egy tárolt eljárást hívnék, és -3113 jön az oci_execute-nál. Természetesen másik gépen ugyanez megy (php5-tel)


Session ID: 336 Serial number: 49540 in /home/projects/szir/include/io_jog.inc on line 72
loc_jog_login (PROBA) returned Oracle execute error:
ORA-03113: end-of-file on communication channel

Úgy látszik, a php-5.6.x sorozat már nem hoz új kihívásokat, adjunk egy egy esélyt a 7.0.10-nek. Van pl. egy ilyen rész a configure során:


sed: Function s/'CPPFLAGS=-D__UNIX__ <nyissz> -DHAVE_OCI_PING'// cannot be parsed.

Ugyanis a CPPFLAGS-ban /perjelek is vannak, pl: -I/usr/local/include -- erre mondaná Váncsa István, hogy 'némely emberi agy egészen másképp működik, mint ahogy azt józan ésszel elvárnánk'

A configure-ban pedig van egy ilyen:


clean_configure_args=$(echo $clean_configure_args | sed -e "s/'$var=$val'//")

Szóval meg akarja tisztítani a paramétereit. Vajon az előző verzióban is előadták ezt? Szerk: Nem, ez új eredmény.

https://bugs.php.net/bug.php?id=72987

Viszont van olyan is, ami nem változik:
https://bugs.php.net/bug.php?id=51558

Aztán van egy pont, ahol kellene neki a ext/pdo_sqlite/libsqlite/sqlite3.c
Ilyen persze nincs. Olyan van, hogy ext/sqlite3/libsqlite/sqlite3.c
"Ezt most így hogy?" Senkinek se hiányzott? Vagy linuxon másképp gányolódik?

Megpróbálkoztatunk egy ilyet:


s;ext/pdo_sqlite/libsqlite/sqlite3;ext/sqlite3/libsqlite/sqlite3;g

20160901.1345: Jó hír, nemcsak az imagick, hanem a házi bővítmény sem fordul az új verzióval:


GlobusPni.c: In function 'zif_glb_set':
GlobusPni.c:168:32: error: 'IS_BOOL' undeclared (first use in this function)
  } else if (Z_TYPE_P (optval)==IS_BOOL ||
                                ^
GlobusPni.c:168:32: note: each undeclared identifier is reported only once for each function it appears in
GlobusPni.c: In function 'zif_glb_get':
GlobusPni.c:199:35: error: macro "RETURN_STRINGL" passed 3 arguments, but takes just 2
  RETURN_STRINGL (retstr, retlen, 1);

https://wiki.php.net/phpng-upgrading

Kezdem úgy érezni magam, mint a gonosz Lord Helmet az Űrgolyhókban. "Sejtettem, Balfaszokkal vagyok körülvéve"

Persze megpróbálhatok elágazni a ZEND_VERSION alapján:


5.6.x: #define ZEND_VERSION "2.6.0"
7.0.x: #define ZEND_VERSION "3.0.0"

Mielőtt még fellelkesülnénk: #if-ben nem lehet stringösszehasonlítás

Akkor újabb információig válasszuk ezt:


5.6.x: #define PHP_MAJOR_VERSION 5
7.0.x: #define PHP_MAJOR_VERSION 7

Vagyis:


/* 20160901.NT
   Nem is lenne az igazi, ha nem tennének bele inkompatibilis változtatást
 */
#if PHP_MAJOR_VERSION > 6
#define my_RETURN_STRINGL_DUPLICATE(s,l) RETURN_STRINGL((s),(l))
#else
#define my_RETURN_STRINGL_DUPLICATE(s,l) RETURN_STRINGL((s),(l),1)
#endif

És akkor jött a Tenkes Kapitánya... Akarom mondani, az újabb hibaüzenet:


ld: 0711-317 ERROR: Undefined symbol: .__zend_malloc

Szerk: hiszti off, csak az import-fájlt kellett bővíteni

20160901.1620: Most tudtam meg, hogy van nekem egy zend_long típusom.
Kicsit meg is ijesztettem magam, mert nem gondoltam rá, hogy a cpp-nek is át kell passzolni a '-maix32 / -maix64' opciók valamelyikét, hogy ugyanazt lássam, mint a valós fordításnál.

20160901.1630:
zend_API.c: zend_parse_parameters -> zend_parse_va_args -> zend_parse_arg -> zend_parse_arg_impl -> zend_parse_arg_string


                case 's':
                        {
                                char **p = va_arg(*va, char **);
                                size_t *pl = va_arg(*va, size_t *);
                                if (!zend_parse_arg_string(arg, p, pl, check_null)) {
                                        return "string";
                                }
                        }
                        break;

Ugyanez 5.6.25-ben:


                case 's':
                        {
                                char **p = va_arg(*va, char **);
                                int *pl = va_arg(*va, int *);

Ugye nem kell magyaráznom, hogy ilyen körülmények között mi jött vissza az 'int' típusú 'length_of_strparam' mezőmben? (big endian PowerPC)

Hozzászólások

sed: Function s/'CPPFLAGS=-D__UNIX__ -DHAVE_OCI_PING'// cannot be parsed.
Jajj, ezzel én is jártam így egy saját szkriptben, kellett némi idő, míg rájöttem a hiba okára (mentségemre szóljon, hogy a kifejezés környezeti változóban volt, és nem mindig volt benne per-jel).