Дамп ядра структуры, указателя и отливки - PullRequest
1 голос
/ 08 мая 2020

У меня есть программа C, написанная 30 лет go (для файлов ISAM), в которой есть раздел, в котором я мог бы использовать некоторую помощь в понимании / исправлении. Человек, который написал это, видел, что его / ее комментарии могут быть в будущем. Компилируется нормально, но дамп ядра.

Вот проблемная строка:

altkptr = (struct keydat *)(++header);

Код в функции:

 struct  indxheader {
    int     pnumrecs ;
    long    pnxtposn ;
    int     pnextnode ;
    long    pfreedat ;
    int     pfreenodes;
#ifdef  FIXED_RECLEN
    int preclength;     /* Added 23-Jun-89 .. kavi */
#endif
    int paltkeys ;
};

struct  keydat {
    int     pkeylength,
        proot,
        pmaxkeys,
        pnodesize,
        pnumkeys,
        pkeyparts ,
        *partsarray ;
};


static  int buildtables(alloc_flg) 
int alloc_flg ;     /* if occupy slot etc are to be called */
{
struct  indxheader  *header ;
struct  keydat      *altkptr;

int savekey, i ;
int *sptr, *dptr ;

    savekey = currkeyno ;

    if(seek(0) == ERROR) 
        reterr(NODSKERR);
    if(read(currslot.fd2,ptr2,INXHSZ)<INXHSZ)
        reterr(IFLRDERR); /* SIZE OF HEADER BLOCK IN FILE < SIZE DECLARED IN ISNAMES.H */

    header = (struct indxheader *)ptr2 ;
    currslot.numrecords = header->pnumrecs ; /*added .. if i have luck*/
#ifdef  FIXED_RECLEN
    currslot.reclength =  header->preclength ;
#endif

    currslot.nxtposn = header->pnxtposn;
    currslot.nextnode = header->pnextnode;
    currslot.freedat = header->pfreedat;
    currslot.freenodes = header->pfreenodes;
    currslot.altkeys = header->paltkeys;

/** If occupyslot to be called then check **/

    if ( alloc_flg )
        if (alloctable() == ERROR) return (ERROR) ;
    altkptr = (struct keydat *)(++header); /* deserves attention..*/

    for(currkeyno = 0;currkeyno<currslot.altkeys;currkeyno++) {
        currindex.proot = altkptr->proot;
        if (currindex.proot == -1) reterr (CRPIXFLERR) ;
        currindex.pmaxkeys = altkptr->pmaxkeys;
        currindex.pnodesize = altkptr->pnodesize;
        currindex.pnumkeys = altkptr->pnumkeys;
        currindex.pkeyparts = altkptr->pkeyparts ;
        currindex.pkeylength = altkptr->pkeylength ;
        altkptr++ ;
        sptr = (int *)altkptr ;
        if (alloc_flg) {
            if ((currindex.partsarray = dptr = (int *)malloc((unsigned)(currindex.pkeyparts*4)*sizeof(int))) == NULL) reterr(MEMORYERR) ;
            for (i = 0 ; i<(currindex.pkeyparts*4) ; i++)
                *dptr++ = *sptr++ ;
        }
        else sptr += (currindex.pkeyparts*4) ;
        altkptr = (struct keydat *)sptr ;
    }
    currkeyno = savekey ;   /*restore currkeyno to its initial value*/
    return (NOERROR);
}

1 Ответ

2 голосов
/ 08 мая 2020

header - это указатель на struct indxheader

Он приводится к altkptr, который является struct keydat

Это:

altkptr = (struct keydat *)(++header);

Это эквивалентно:

++header;
altkptr = (struct keydat *) header;

Вопрос о том, было ли приведение в действие в 1989 году, может быть предметом споров. Но ...

Приращение header является проблемой.

В 1989 году long имело такое же sizeof [и, следовательно, выравнивание struct], что и ан int. Это произошло потому, что большинство / все процессоры были 32-битными (или 16-битными).

Теперь вы, вероятно, работаете на 64-битной машине. Итак, long - это 64 бита.

Итак, в 1989 году размер каждого struct [вероятно] совпадал. Теперь размеры [вероятно] разные.

Итак, приращение header недействительно.

Вам может повезло с компиляцией с -m32 для принудительная компиляция в 32-битном режиме. Но в остальном этот код настолько шаткий, что я бы сказал, используйте его как [свободное] руководство и перепишите все, что сможете.


ОБНОВЛЕНИЕ:

Я пишу код C с 1981 года, поэтому я немного знаком с системами, которые были доступны тогда.

Одна из проблем заключается в том, что структура keydat имеет встроенный указатель, который сохраняются в файл ISAM и считываются из него.

Если это так, разыменование такого обратного указателя почти наверняка приведет к сбою или выдаче неверных результатов.

Это потому, что нет гарантии, что программа загружен в память в том же месте.

Ключевой вопрос заключается в том, пытаетесь ли вы перенести этот код, чтобы вы могли читать существующие старые файлы ISAM, которые были созданы длинной go. В противном случае было бы лучше использовать существующий код в качестве руководства и переписать с нуля.

Если вам нужно нужно читать старые файлы, это поможет точно узнать тип системы, на которой выполнялось программное обеспечение.

Если оно запускалось на P C той эпохи под MS / DOS, int, вероятно, было 16 бит, а long было 32 бит. 1062 но int может быть 16- или 32-битным. В большинстве систем для int использовалось 32 бита, но это был выбор компилятора.

Кроме того, ПК были / были с прямым порядком байтов, но системы mc68000 Unix были с прямым порядком байтов.

Итак, сначала вам нужно определить sizeof для int, long и указатель для системы той эпохи.

Кроме того, вам нужно определить, какое выравнивание были использованы элементы структуры.

Затем вам, возможно, придется переписать функцию, которая читает эти данные, почти побайтово, и выполнить преобразование для каждого поля, чтобы получить правильное количество байтов в прочитать поле и его порядок следования байтов.

Это похоже на то, что должен делать XDR.

...