-3

I have a file with format: [name][number][amount] number is taken as a string. and im using it in a strcmp. Problem is that i get a segmentation fault. I know that on most cases when strcmp signs segmentation fault it means that one of the parameters is null or cant find its "end" ('\0'). I checked with gdb and i cant say if this is the problem.Take a look:

> (gdb) bt full
> #0  0x08048729 in lookup (hashtable=0x804b008, hashval=27, 
>     number=0x804b740 "6900101001") 
>         list = 0xffffffff
> #1  0x080487ac in add (hashtable=0x804b008, 
>     number=0x804b740 "9900101001", name=0x804b730 "Smithpolow",
> time=6943) 
>         new_elem = 0xffffffff
>         hashval = 27
> #2  0x08048b25 in main (argc=1, argv=0xbffff4b4) 
>         number = 0x804b740 "9900101001"
>         name = 0x804b730 "Smithpolow"
>         time = 6943
>         i = 2

Code:

        typedef struct  HashTable
        {
            int length;
            struct  List *head; 

        } HashTable;

        //(resolving collisions using chaining)
        typedef struct  List
        {
            char *number;
            char *name;
            int time;
            struct List *next;
        } List;

    int primes[]={17,29,51,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899};
    *int PrimesIndex=1;* **int PrimesIndex=0;**  **//changed.**


     HashTable *createHashTable(size)
    {
         HashTable *new_table = malloc(sizeof(*new_table)*size);

        if (new_table == NULL)
        {   return NULL;
        }

        int i=0;
        for(i; i<size; i++)
        {   new_table[i].length=0;
            new_table[i].head=NULL;
        }
        return new_table;
    }

    int hash ( HashTable *hashtable,char* number)
    {
        int hashval = 0;
        int i = 0;
        for ( i = 0; i < 10; i++)
        {   hashval = (hashval << 5)|(hashval >> 27);
            hashval += ( int)number[i];
        }

        return hashval % primes[PrimesIndex];
    }

         List *lookup ( HashTable *hashtable,int hashval,char number[10])
        {
         printf("NUMBER:%s\n",number);
          List *list=hashtable[hashval].head;
         for(list; list!=NULL; list=list->next){
           if (strcmp(number,list->number)==0)    
            return list;

         }
         return NULL;
        }


        int add ( HashTable* hashtable,char number[10],char* name,int time)
        {
             List *new_elem;
            int hashval=hash (hashtable,number);

            new_elem=hashtable[hashval].head;
            if(hashtable[hashval].length>0)
            {                   
                  if ((lookup (hashtable,hashval,number))!=NULL) {return 0;}    
            }

            if (!(new_elem=malloc(sizeof(struct  List)))){ return -1;}

            //insert values for the new elem
            new_elem->number=strdup(number);    
            new_elem->name=strdup(name);
            new_elem->time=time;

            hashtable[hashval].head=new_elem;
            new_elem->next=NULL;
            hashtable[hashval].length++;

            /* rehash existing entries if necessary */
            if(hashTableSize(hashtable)>= 2*primes[PrimesIndex])    
            {    
                 hashtable = expand(hashtable);
                 if (hashtable ==NULL){
                   return 0;
                 }

            }

            return 1;
        }

 HashTable* expand( HashTable* h )
{   printf("EXPAND \n");
     HashTable* new;
     List *temp;
    int n;
     List *node,*next;
    PrimesIndex++;
    int new_size= primes[PrimesIndex];      /* double the size,odd length */

    if (!(new=malloc((sizeof(  List*))*new_size))) return NULL;

    for(n=0; n< h->length; ++n) {
        for(node=h[n].head; node; node=next) {
            add (new, node->number, node->name,node->time);
            next=node->next;
            //free(node);
        }
    }
    free(h);
    return new;
}

and the main:

  int main(int argc, char *argv[])  
    {
        char **token;
        FILE *delimitedFile;
        /*Here's an example of tokenizing lines from an actual file*/
        /*Open file for reading ("r"), and take a FILE pointer, 
          which you can use to fetch lines using fgets()*/

        my_hash_table = createHashTable(17);
        if(my_hash_table==NULL)
        {   return 1;
        }

        FILE * File2;
            if ( ( File2=fopen(" File.txt","r")) !=NULL ) 
            { // File.txt format:  [name number time]
                int li = 0;
                char *lin = (char *) malloc(MAX_LINE * sizeof(char));

                while(fgets(lin, MAX_LINE, File2) != NULL)
                {
                    token = my_linetok(lin, " ");
                    if(token != NULL)
                    {
          char* number ;
          char* name;
          int time;
          int i;
                        for(i = 0; token[i] != NULL; i++)
                        {
           name=strdup(token[0]);
           number=strdup(token[1]);
           time=atoi(token[2]);

           if (i==2)
           { int insertDone=0;
                 insertDone =add(my_hash_table,number,name,time);   

           } 
          }
          free(name); 
          free(number);
          free(token);

                    }
                    else 
             {
                        printf("Error reading line %s\n", lin);
                        exit(1);   
                    }
                }

            } 
            else 
            {
                printf("Error opening file \nEXIT!");
         exit(0);
            }

        return 1;
    }
FILIaS
  • 495
  • 4
  • 13
  • 26
  • 1
    I imagine this isn't the cause of your segfault, but don't you want to be comparing against `list->number`, not `list->name`? – Oliver Charlesworth Jan 16 '11 at 12:31
  • 1
    Also, the backtrace implies you're in a function called `lookup()`, called from a function called `add()`. Where are these? – Oliver Charlesworth Jan 16 '11 at 12:33
  • You free `name`, but don't free `number`. Does your function `add()` allocate memory to hold both `number` and `name`, or just for `number`? – DReJ Jan 16 '11 at 12:37
  • @Oli Charlesworth. OK that was from copy paste. Updated post. U can check add() function. – FILIaS Jan 16 '11 at 12:40
  • @DReJ Thanks for noticing that. I forgot it cause before number was taken as a long int. :/ – FILIaS Jan 16 '11 at 12:41
  • 1
    @FILIaS: That still doesn't explain the `lookup()`/`lookup_on_Clients()` discrepancy! Are you sure this is the code that corresponds to your backtrace? – Oliver Charlesworth Jan 16 '11 at 12:46
  • 2
    Also, have you noticed that `list = 0xffffffff`? – Oliver Charlesworth Jan 16 '11 at 12:46
  • @FILIaS: You still haven't posted the definition of `struct HashTable` or of `my_hash_table`. -1. – j_random_hacker Jan 16 '11 at 12:55
  • @Oli Charlesworth. Sorry for that.Just copy paste mistake. Yes i noticed that. :/ But i dont know why its like that :/ If u have any idea i would be grateful – FILIaS Jan 16 '11 at 12:55
  • @j_random_hacher.I just posted it. – FILIaS Jan 16 '11 at 12:58
  • Where is `PrimesIndex` defined? I get the feeling it's a global variable -- when it should be a per-hashtable quantity, or a local variable, recomputed from the size of the hashtable. Also we need to see `createClientsHashTable()` and `my_linetok()`. – j_random_hacker Jan 16 '11 at 13:03
  • @j_random_hacker. my_linetok is a different file.and i could be feel safe about it us it was given to me as a company file. Im gonna post now createHashTable. yes PrimesIndex is global as primes too. EDIT: Posted. – FILIaS Jan 16 '11 at 13:04
  • What is `clientFile2`? Is it `File2`? Please post the exact code! – j_random_hacker Jan 16 '11 at 13:14
  • Why does `main()` contain a loop `for(i = 0; token[i] != NULL; i++)` that then processes specific items (rather than the ith token)? You are currently calling `strdup()` multiple times inside this loop, and only `free()`ing the last version. That won't cause a crash (unless you run out of memory) but it is a memory leak. – j_random_hacker Jan 16 '11 at 13:19
  • It processes specific items as in each line of the file there are: name number time, how can they be added to the structure without the loop? You are right for the free() but if i free them inside the loop, how can i then call add function with these? – FILIaS Jan 16 '11 at 13:21
  • @FILIaS: No, the `while` loop iterates once for each line in the file. It's not necessary (and in fact is wasteful) to have the `for` loop I mentioned in my previous comment inside that `while` loop. – j_random_hacker Jan 16 '11 at 13:23
  • @j_random_hacker Ok thanks for that. Any ideas why list is marked as list = 0xffffffff ?? :/ – FILIaS Jan 16 '11 at 13:29
  • 1
    @FILIaS: No, but it shouldn't be too hard to track down why it becomes that, either by stepping in the debugger, or by adding printf statements. – Oliver Charlesworth Jan 16 '11 at 13:43
  • @ Oli Charlesworth. Maybe you are right.But a "mature sight" would be better on these cases. – FILIaS Jan 16 '11 at 13:53
  • This is hilarious. `expand()`, which you only posted in the most recent update, contains 2 separate bugs that will cause crashes, plus a 3rd bug that will cause a large memory leak. And I've just noticed a bug in `add()` that ensures that no hash bucket ever contains more than 1 element. (As well as another memory leak -- *for a change*.) – j_random_hacker Jan 16 '11 at 14:50
  • @ j_random_hacker. Im happy that my mistakes make you lauph a bit as you say. At least im working on it. – FILIaS Jan 16 '11 at 15:51

3 Answers3

3

The underlying problem here is that you create a hashtable with 17 buckets:

my_hash_table = createHashTable(17);

But C arrays are 0-based, and PrimesIndex starts out at 1, not 0, so inside add(), the call to hash():

int hashval=hash (hashtable,number);

will return a number between 0 and 28, not a number between 0 and 16. So at some point, an out-of-range value will be assigned to hashval, and one of the subsequent accesses indexed by hashval, e.g.

new_elem=hashtable[hashval].head;

will be reading uninitialised memory, leading ultimately to crazy pointer values like 0xffffffff surfacing later on.

Solution: Change int PrimesIndex = 1; to int PrimesIndex = 0;.

But honestly, I think there could well be other issues that I'm missing. There are:

  • Issues with the for loop inside the while loop in main() that I've pointed out in comments;
  • The dubious declaration for the number parameter to lookup_on_Clients();
  • The fact that sometimes the function is called lookup() and sometimes lookup_on_Clients() (as noticed by Oli);
  • And I don't trust that my_linetok() (which you don't show source for) works properly -- at the very least, unless it uses a static buffer, it must be allocating an array of char * in order to hold the pointers to the individual tokens, which is never freed -- a memory leak.
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
  • That's right. Well the only reason that PrimesIndex was 1 is that from the beginning i create a hash table with 17 buckets (the first number on primes) so i thought it was useless to start it from 0. Anyway,i believe the same,it;s not this the serious problem.(EDIT: I meant PrimesIndex,for any case i changed it!) – FILIaS Jan 16 '11 at 13:38
  • @FILIaS: **YES** this is **the** problem. What don't you understand about my explanation? – j_random_hacker Jan 16 '11 at 13:39
  • @j_random_hacker. For the first one: I already changed that thanks. Second note: dubious yes. But what can i do for better? Third note: Thats from copy paste dont pay attention to these. Fourth one: For what i see yes this code has leaks. But im not meant to change it, so... – FILIaS Jan 16 '11 at 13:41
  • @FILIaS: So you changed it to `int PrimesIndex = 0;` and you still get the same problem? – j_random_hacker Jan 16 '11 at 13:45
  • @j_random_hacker. Now i got what u mean with PrimesIndex i didnt notice that i use it on hash(). Thanks. – FILIaS Jan 16 '11 at 13:45
  • @j_random_hacker. Well,i changed it,now it doesnt crash from the beginning but yes i get segmentation again – FILIaS Jan 16 '11 at 13:46
  • @j_random_hacker Should i provide you the new messages on gdb? – FILIaS Jan 16 '11 at 13:50
  • @FILIaS: So there are other problems besides the one I identified -- I'm not surprised. I'm sorry but you are infuriating. I have just spent most of the last hour trying to help you, and for what? You couldn't even be bothered *trying* the solution I have carefully worked out and explained to you. Nor are you prepared to show your thanks with an upvote. Don't bother showing me the latest gdb message -- I'm not interested in helping you any longer. – j_random_hacker Jan 16 '11 at 13:55
  • @j_random_hacker I;m sorry for you thinking like this. I was going to upvote. But this is all? The upvoting? Im just trying to solve my problem.Ok. I didnt check it IMMEDIATELY. But all this is for that? Thanks anyway – FILIaS Jan 16 '11 at 13:57
  • Thanks for downvoting btw. Thanx for "infuriating" too. Its clearly from your first comment here...who;s infuriating. – FILIaS Jan 16 '11 at 13:59
2

You don't have a room for null terminator in number. You set size of number to be equal to 10 chars, but you have 10 digits in your number and no space for \0.

EDIT:

I looked your updated code. You created hashtable of initial size = 17, but your hasval = 27. But you don't have code to extend the size of hashtable properly.

new_elem=hashtable[hashval].head;
if(hashtable[hashval].length>0) // <-- when hashval is out of array 
                                // hashtable[hashval] can have any value of length and head (not NULL)
DReJ
  • 1,966
  • 15
  • 14
  • While you are sure that \0 in the original string was not replaced with other data it's ok. But in common it's unpredictable behaviour. – DReJ Jan 16 '11 at 12:51
  • So,what should i do for better? – FILIaS Jan 16 '11 at 12:55
  • Try `strncmp(number,list->number,10)` just to make sure – DReJ Jan 16 '11 at 13:07
  • @DReJ. Checked it. It's the same. None change to results. You can re-check my post if you mind as I posted some new functions.Thanks – FILIaS Jan 16 '11 at 13:11
  • @DReJ. That's right. So should i change my hash()??? :/ Or the initial size of the table? – FILIaS Jan 16 '11 at 13:55
  • @DReJ. For what i tracked down the problem is my expand(). Without calling this,everything is fine now. So the problem remains on that. – FILIaS Jan 16 '11 at 14:08
0

You don't actually show the source for add() which presumably calls lookup_on_Clients(), and the backtrace mentions lookup() instead of lookup_on_Clients(), so I can't be sure, but here's my diagnosis:

  • The backtrace says list = 0xffffffff -- that's definitely not a valid address, so it's probably the list->name access that is causing the SIGSEGV.
  • I'm also bothered by the fact that the number parameter to lookup_on_Clients() is declared as char number[10] and yet gdb shows it contains a 10-digit number -- that suggests that the variable holding the argument for this is declared the same way, meaning that there's no room for a terminating 0 byte. And the fact that you're calling strcmp() on it means that you are treating number as nul-terminated string, so the variable holding the argument that gets passed to lookup_on_Clients() as number (possibly a local variable declared in add()?) should be declared as an array with size at least 11 to avoid crashes. You're safe if add() just passes its own number argument straight through, since that is dynamically allocated to be large enough via strdup() in main(), but I would nevertheless change the declaration on lookup_on_Clients().
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169