0

I get a segmentation fault when running spellec.c and I can't figure out why.

/**
 * Implements a dictionary's functionality.
 */

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include "dictionary.h"

//#define HASHMAX 204000 // HASHMAX is calculated so that large dictionary by at around 70% of HASHMAX
#define HASHMAX 1000

/*
 * This hash function is called djb2 is created by Ban Bernstein 
 * I found it on http://www.cse.yorku.ca/~oz/hash.html
 * I made a minor change. The function return hash & HASHMAX instead of just hash.
 */
unsigned long hash_func (char *str)
{
    unsigned long hash = 5381;
    int c;

    while ((c = *str++))
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash % HASHMAX;
}

/**
 * Declaring struct node
 */
typedef struct node 
{
    char word[LENGTH +1];
    struct node *next;
}
node;

// Declaring a global array of node pointers, named hashtable
node *hashtable[HASHMAX];

// Declaring count, to count how many word will be loaded to dictionary
int count = 0;

/**
 * Loads dictionary into memory. Returns true if successful else false.
 */
bool load(const char *dictionary)
{
    // Open dictionary
    FILE *file;
    file = fopen(dictionary, "r");
    if (file == NULL)
    {
        printf("Could open dictionary");
        return false;
    }

    char word[LENGTH +1] = {};

    while (fscanf(file, "%s", word) != EOF)  //  Other version of while while (!feof(file))
    {
        // create new node
        node *node1 = malloc(sizeof(node));
        if (node1 == NULL)
        {
            unload();
            return false;
        }

        // put word inside node
        strcpy(node1->word, word);   //another way is fscanf(file, "%s", node1->word);

        // save the hash in index
        int index = hash_func(word);

        // put node in the beggining of linked list.
        node1->next = hashtable[index];
        hashtable[index] = node1;

        count++; // increment count

    }
    fclose(file);
    return true;
}

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char *word)
{
    // create a new string and copy word to it
    char *str = NULL;
    strcpy(str, word);

    // lowercase str aka word
    for (int i = 0; str[i]; i++)
        str[i] = tolower(str[i]);

    // cursor points to the head of linked list located at hashtable[index]
    node *cursor = hashtable[hash_func(str)];
    while (cursor != NULL) // iterate through the whole list
    {
        if ( strcasecmp(str, cursor->word) == 0) // return true if strings are the same
            return true;

        cursor = cursor->next;
    }

    return false;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{
    if (count != 0)
        return count;
    else
        return 0;
}

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */
bool unload(void)
{
    for (int i = 0; i <= HASHMAX; i++)
    {
        node *cursor = hashtable[i];

        while (cursor != NULL ) 
        {
            node *temp = cursor;
            cursor = cursor->next;
            free(temp);
        }
    }
    return true;
}

And here is the output of valgrind

==21928== Memcheck, a memory error detector
==21928== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21928== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21928== Command: ./speller texts/ralph.txt
==21928== 
==21928== Invalid read of size 1
==21928==    at 0x4C2E1C7: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21928==    by 0x401212: load (dictionary.c:67)
==21928==    by 0x4009CD: main (speller.c:40)
==21928==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==21928== 
==21928== 
==21928== Process terminating with default action of signal 11 (SIGSEGV)
==21928==  Access not within mapped region at address 0x0
==21928==    at 0x4C2E1C7: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21928==    by 0x401212: load (dictionary.c:67)
==21928==    by 0x4009CD: main (speller.c:40)
==21928==  If you believe this happened as a result of a stack
==21928==  overflow in your program's main thread (unlikely but
==21928==  possible), you can try to increase the size of the
==21928==  main thread stack using the --main-stacksize= flag.
==21928==  The main thread stack size used in this run was 8388608.
==21928== 
==21928== HEAP SUMMARY:
==21928==     in use at exit: 624 bytes in 2 blocks
==21928==   total heap usage: 2 allocs, 0 frees, 624 bytes allocated
==21928== 
==21928== LEAK SUMMARY:
==21928==    definitely lost: 0 bytes in 0 blocks
==21928==    indirectly lost: 0 bytes in 0 blocks
==21928==      possibly lost: 0 bytes in 0 blocks
==21928==    still reachable: 624 bytes in 2 blocks
==21928==         suppressed: 0 bytes in 0 blocks
==21928== Reachable blocks (those to which a pointer was found) are not shown.
==21928== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==21928== 
==21928== For counts of detected and suppressed errors, rerun with: -v
==21928== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
7
  • Have you identified which line of code is causing the seg fault? You could insert some printf statements and move them around until you bracket the bad line to find the problem. – Cliff B Sep 9 '17 at 22:12
  • I have tried working with the debugger. I get a "Process received SIGSEGV: Segmentation fault" error after I open the dictionary file in line (file = fopen(dictionary, "r");) But I don't know why – johnlock1 Sep 11 '17 at 16:37
  • I always use like char word[LENGTH+1] = {0};, not {}, not sure if that's relevant. There are obvious sources for segfaults in check and unload, but that in load is tricky. – Blauelf Sep 12 '17 at 15:18
  • In check, use char str[LENGTH+1]; (so there's memory connected to variable str), in unload use i < HASHMAX, not <=. – Blauelf Sep 12 '17 at 15:22
  • 1
    @Blauelf thanks very much for your help. After HOURS of trying to figure out what is wrong, I understood that I also had to recompile speller and not only dictionary as I was doing, since I thought that that was enough, since I only make changes to the latter. After I made the changes you point out in your second comment (and recompiled both files), it worked just fine! – johnlock1 Sep 12 '17 at 21:52
0

I solved the problem, by changing the way I create a new string and copy "word" to it in the begging of check function. The correct way to do it is:

int n = strlen(word);
char str[n + 1];
strcpy(str, word);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .