C Помогите интерпретировать calloc segfault

У меня есть следующие строки в моем коде:

DocumentNode *docNode = NULL;
initDocNode(docNode, docID, wordFreq);

Вот функция initDocNode

void initDocNode(DocumentNode *docNode, int docID, int wordFreq) {
    docNode = calloc(1, sizeof(DocumentNode));
    if (!docNode)
        fprintf(stderr, ....);
    docNode->docID = docID;
    docNode->wordFrequency = wordFreq;
}

У меня есть цикл while, который создает docNodes, но в какой-то момент я получаю segfault со следующей обратной трассировкой. Похоже, что-то происходит внутри calloc. Любая помощь в понимании этого будет высоко оценена.

_int_malloc (av=av@entry=0x396fbb8760 <main_arena>, bytes=bytes@entry=16)
at malloc.c:3718
3718          set_head(remainder, remainder_size | PREV_INUSE);
(gdb) backtrace

_int_malloc (av=av@entry=0x396fbb8760 <main_arena>, bytes=bytes@entry=16)
at malloc.c:3718
0x000000396f88098a in __libc_calloc (n=<optimized out>, elem_size=<optimized out>)
at malloc.c:3187
0x0000000000402270 in initDocNode (docnode=0x0, docID=680, wordFreq=1)
at ../util/indexerUtils.c:59
0x000000000040147b in ReconstructIndex (hashtable=0x7fffc8c561f8,
wordToAdd=0x1c3eab0 "mode", docID=680, wordFreq=1) at src/query_engine.c:337
0x0000000000401209 in ReadFile (file=0x7fffc8c5932a "cs_lvl3.dat")
at src/query_engine.c:267
0x0000000000400eff in main (argc=2, argv=0x7fffc8c58998) at src/query_engine.c:147

У меня есть набор слов, и для каждого слова я создаю docNodes для документов, содержащих это слово. Я получаю эту ошибку сегмента только тогда, когда обрабатываю слово с длинным списком соответствующих документов. Есть ли предел тому, сколько я могу calloc?

Вот функция, которая считывает файл, содержащий слова и соответствующие им документы, и создает хеш-таблицу для данных. Содержимое файла имеет следующий вид: число_слов_соответствующих_документов doc wordFreq doc wordFreq ...

HashTable *ReadFile(char *file){
FILE *fp = fopen(file, "r");
if (!fp) {
    fprintf(stderr, "Error: Couldn't open file %s for reloading.\n", file);
    return NULL;
}

HashTable *hashtable = calloc(1, sizeof(HashTable));
if (!hashtable) {
    fprintf(stderr, "Error: Couldn't allocate memory for hashtable.\n");
    return NULL;
}  
char c;
bool done = false;
while (1){
    int wordLength = 0;
    //keep reading until you find a space
    //this is to determine the length of the word
    while ((c = fgetc(fp)) != ' '){

        if (c == EOF){
            // but if c is EOF, then we're done reading the file                
            done = true;
            // break out of the loop counting word lenght
            break;
        }

        wordLength++;
    }

    if (done){
        // break out of loop reading file
        break;
    }            
    // now allocate memory for the word and null character
    char *currWord = calloc(wordLength + 1, sizeof(char));
    if (!currWord){
        fprintf(stderr, "Failed to allocate memory to store %s\n", currWord);
        continue;
    }
    //now reverse the pointer to the beginning of the word
    fseek(fp, -(wordLength + 1), SEEK_CUR);

    int numFiles;
     // now read the word. If it's unsuccessful, then there's no more lines. exit
    fscanf(fp, "%s %d", currWord, &numFiles);
    printf("Processing %s\n", currWord);
    int i = 0;
    while (numFiles--) {
        int docID;
        int wordCount;
        if (!fscanf(fp, " %d %d", &docID, &wordCount)) {
            fprintf(stderr, "Error: Couldn't process document for word, %s.\n", currWord);
            free(currWord);
            continue;
        }
        if (!ReconstructIndex(&hashtable, currWord, docID, wordCount)) {
            fprintf(stderr, "Error: Couldn't reconstruct index for word, %s\n", currWord);
            free(currWord);
            continue;
        }
        printf("%s: just processed %d document\n", currWord, i);
        i++;

    }

}
fclose(fp);
return hashtable;

}

Вот ReconstructIndex()

int ReconstructIndex(HashTable **hashtable, char* wordToAdd, int docID, int wordFreq) {
//get the hash index
int hashIndex = JenkinsHash(wordToAdd, MAX_HASH_SLOT);
// if hash index is not taken
if ((*hashtable)->table[hashIndex] == NULL) {
    // make document node
    DocumentNode *newDocNode = NULL;
    // newDocNode = initDocNode(newDocNode, docID, wordFreq);
    initDocNode(&newDocNode, docID, wordFreq);
    if (!newDocNode) {
        fprintf(stderr, "Failed to make DocumentNode for %s.\n", wordToAdd);
        return 0;
    }
    // make word node with this document node
    WordNode *newWordNode = NULL;
    newWordNode = initWordNode(newWordNode, wordToAdd, newDocNode);
    if (!newWordNode) {
        fprintf(stderr, "Failed to make WordNode for %s.\n", wordToAdd);
        free(newDocNode);
        return 0;
    }
    // make hash table node with this word node
    HashTableNode *newHTNode = NULL;
    newHTNode = initHashTNode(newHTNode, (void*)newWordNode, NULL);
    if (!newHTNode) {
        fprintf(stderr, "Failed to make HashTableNode for %s.\n", wordToAdd);
        free(newDocNode);
        free(newWordNode->word);
        free(newWordNode);
        return 0;
    }
    // put hashtablenode into table at the hash index
    (*hashtable)->table[hashIndex] = newHTNode;

    return 1;
}
// if hash index is taken
else {
    // find word
    HashTableNode *currHTNode = (*hashtable)->table[hashIndex];
    int inHashTable = 0;
    while (currHTNode) {
        WordNode * currWordNode = (WordNode *)(currHTNode->hashKey);
        if (strcmp(wordToAdd, currWordNode->word) == 0){
            inHashTable = 1;
            break;
        }
        currHTNode = currHTNode->next;
    }
    // if word was found
    if (inHashTable) {
        WordNode *currWordNode = (WordNode *)(currHTNode->hashKey);
        // add document to this word's listing in hash index
        // make new document node
        DocumentNode *newDocNode = NULL;
        // newDocNode = initDocNode(newDocNode, docID, wordFreq);
        initDocNode(&newDocNode, docID, wordFreq);
        if (!newDocNode) {
            fprintf(stderr, "Failed to make DocumentNode for %s.\n", wordToAdd);
            return 0;
        }
        // append this new doc node to back of other document nodes
        DocumentNode *lastDocNode = currWordNode->doc;

        while (lastDocNode->next) {
            lastDocNode = lastDocNode->next;               
        }

        lastDocNode->next = newDocNode;
        // free(wordToAdd);      // causes seg fault
        return 1;
    }
    // if word was not found
    else {
        // add word node to hashtable at this index
        // make new document node
        DocumentNode *newDocNode = NULL;
        // newDocNode = initDocNode(newDocNode, docID, wordFreq);
        initDocNode(&newDocNode, docID, wordFreq);
        if (!newDocNode) {
            fprintf(stderr, "Failed to make DocumentNode for %s.\n", wordToAdd);
            return 0;
        }
        // make word node with this document node
        WordNode *newWordNode = NULL;
        newWordNode = initWordNode(newWordNode, wordToAdd, newDocNode);
        if (!newWordNode) {
            fprintf(stderr, "Failed to make WordNode for %s.\n", wordToAdd);
            free(newDocNode);
            return 0;
        }
        // make hash table node with this word node
        HashTableNode *newHTNode = NULL;
        newHTNode = initHashTNode(newHTNode, (void*)newWordNode, NULL);
        if (!newHTNode) {
            fprintf(stderr, "Failed to make HashTableNode for %s.\n", wordToAdd);
            free(newDocNode);
            free(newWordNode->word);
            free(newWordNode);
            return 0;
        }
        // append this new hashtable node to end of other hashtable nodes at hash index
        HashTableNode *lastHTNode = (*hashtable)->table[hashIndex];
        while (lastHTNode->next) {
            lastHTNode = lastHTNode->next;
        }
        lastHTNode->next = newHTNode;
        return 1;
    }
}

}


person Stralo    schedule 14.05.2014    source источник
comment
Можете ли вы опубликовать код для цикла while. Возможно, вы попадаете в бесконечный цикл и вам не хватает памяти.   -  person R Sahu    schedule 14.05.2014
comment
Я добавлю цикл while через секунду. Однако я не думаю, что у меня есть бесконечный цикл. я добавил оператор печати, чтобы увидеть свой прогресс, и я заметил, что получаю segfault после вызова initDocNode для 678-го документа определенного слова   -  person Stralo    schedule 14.05.2014
comment
Кстати, ваша функция initDocNode не повлияет на вызывающую сторону. Указатель передается по значению, поэтому присваивание docNode = влияет только на аргумент — оно не влияет на переменную в вызывающем объекте.   -  person nobody    schedule 14.05.2014
comment
@Andrew: что ты имеешь в виду под сообщением об ошибке? Это: 0 _int_malloc (av=av@entry=0x396fbb8760 ‹main_arena›, байты=bytes@entry=16) at malloc.c:3718 3718 set_head(remainder, rester_size | PREV_INUSE);   -  person Stralo    schedule 14.05.2014
comment
Почему вы делаете free(currWord); перед выполнением continue в цикле while (numFiles--)? На следующей итерации внутреннего цикла fscanf попытается записать в освобожденную память.   -  person nobody    schedule 14.05.2014
comment
Не обращайте внимания на сообщение об ошибке. Я думал, что у gdb больше информации, но я ошибся, и это не так.   -  person nobody    schedule 14.05.2014
comment
Я попробовал DocumentNode *docNode = NULL и изменил initDocNode, чтобы я мог вызывать его с помощью initDocNode(&docNode, ...), и у меня все еще была та же проблема. Я собираюсь попытаться освободить currWord в другом месте.   -  person Stralo    schedule 14.05.2014
comment
@Stralo, трассировка стека ясно показывает, что проблема возникает, когда «ReadFile ()» вызывает «ReconstructIndex ()»; затем 'ReconstructIndex()' вызывает 'initDocNode()'. Следовательно, очень важно, чтобы весь код в этом кодовом пути был раскрыт в вопросе. Пожалуйста, отредактируйте вопрос и добавьте содержимое «ReconstructIndex()».   -  person Mahonri Moriancumer    schedule 14.05.2014
comment
Я только что добавил ReconstructIndex.   -  person Stralo    schedule 14.05.2014
comment
После выполнения if (!docNode) fprintf(stderr, ....); следует выйти из программы, а не продолжать разыменование docNode.   -  person M.M    schedule 14.05.2014
comment
char c; должно быть int c; . Использование fseek может быть ненадежным, попробуйте переделать свою логику, чтобы избежать fseek. Попробуйте запустить под valgrind, чтобы найти переполнения.   -  person M.M    schedule 14.05.2014


Ответы (1)


Попробуйте использовать **docNode вместо *docNode в теле функции, потому что изменения не отражаются за пределами тела функции. Он создает узел локально. Чтобы вызвать аргумент передачи функции как &docNode.

person वरुण    schedule 14.05.2014
comment
Вы имеете в виду объявить функцию как void initDocNode(DocumentNode **docNode, int docID, int wordFreq); и вызвать ее, используя initDocNode(&docNode, docID, wordFreq); правильно? - person ; 14.05.2014
comment
Да, при этом изменения также будут отражены в точке вызова. - person वरुण; 14.05.2014