Ethan
Ethan

Reputation: 1266

Invalid Write -- Valgrind

Hi I'm running into an munmap_chunk(): invalid pointer: error in my c program.

The main problem is...I'm not even sure what all of the ways a pointer can become invalid are. I've checked all over my code for strings not being calloced with enough space, but found nothing that looks like it'll run over bounds!

The relevant code is below (what I THINK is the relevant code anyway)

//Takes in a username and suggests friends of friends who are the opposite sex as friends of username
395 void suggest_friends(char* username, FILE* out) {
396     //printf("ENTER suggest_friends\n");
397     to_lowercase(username);
398 
399     if (check_username(username) == 0) {
400 
401         struct user_node *user = search_username(username);
402         if (user != NULL) {
403 
404             struct friend_node *a_friend = user->a_friend;
405             struct friend_node *friends_friend = NULL;
406             struct friend_node *temp_friends_friend = NULL;
407 
408             struct friend_suggest_node *list = NULL;
409             struct friend_suggest_node *list_it = NULL;
410             struct friend_suggest_node *new_suggest = NULL;
411             int friend_suggest_switch = -1;
412 
413             int print_string_size = 50;
414             int print_string_len = 0;
415             char* print_string = calloc(print_string_size + 1, sizeof(char));
416             char* user_string = NULL;
417             int num_suggestions = 0;
418             int num_mutual_friends = 0;
419             int max_friends = 0;
420 
421             //Iterate over all friends
422             while (a_friend != NULL) {
423 
424                 friends_friend = a_friend->user->a_friend;
425                 //Does friend have friends of opposite sex that I'm not friends with?
426                 //Iterate over friend's friends
427                 while (friends_friend != NULL) {
428 
429                     num_mutual_friends = 0;
430                     //mutual friend found
431                         //Different gender, and not friends
432                     if (friends_friend->user->gender != user->gender && are_friends(friends_friend->u    ........ser, user) != 0) {
433 
434                         //are there are elements in the suggested friends list yet??
435                         if (list == NULL) {
436 
437                             new_suggest = malloc(sizeof(struct friend_suggest_node));
438                             new_suggest->user = friends_friend->user;
439                             new_suggest->next = NULL;
440                             list = new_suggest;
441                             friend_suggest_switch = 0;
442                         }
443                         //there are already elements
444                         else {
445 
446                             friend_suggest_switch = 0;
447                             //Loop over suggested friends, to check if friends friend already found
448                             list_it = list;
449                             while (list_it != NULL) {
450 
451                                 //if the user is already in the suggested list
452                                 if (list_it->user == friends_friend->user) {
453                                     friend_suggest_switch = -1;
454                                     break;
455                                 }
456                                 list_it = list_it->next;
457                             }
458 
459                             //if the friend to suggest is a new suggestion
460                             if (friend_suggest_switch == 0) {
461 
462                                 //add friend to suggest to the front of the list
462                                 //add friend to suggest to the front of the list
463                                 new_suggest = malloc(sizeof(struct friend_suggest_node));
464                                 new_suggest->user = friends_friend->user;
465                                 new_suggest->next = list;
466                                 list = new_suggest;
467                             }
468                         }
469 
470                         //if the friend found was new
471                         if (friend_suggest_switch == 0) {
472 
473                             //INTENTION? LOOP OF THE FRIEND OF A FRIEND'S FRIEND LIST!?
474                             //Loop over the remainder of the user's friends's, friend list
475                                 //whom is about to be suggested as a mutual friend
476                             temp_friends_friend = friends_friend->user->a_friend;
477                             while (temp_friends_friend != NULL) {
478 
479                                 //if user is found who is a mutual friend with user
480                                 if (are_friends(temp_friends_friend->user, user) == 0) {
481 
482                                     num_mutual_friends++;
483                                 }
484 
485                                 temp_friends_friend = temp_friends_friend->next_friend;
486                             }
487 
488                             //if more mutual friends then previous choice,
489                                 //set user_string equal to this user now
490                             if (num_mutual_friends > max_friends) {
491                                 max_friends = num_mutual_friends;
492                             }
493 
494                             //get string for user
495                             user_string = get_user_string(friends_friend->user);
496                             num_suggestions++;
497                             //+3 for \0 and ', '
498                             print_string_len = strlen(user_string) + 3;
498                             print_string_len = strlen(user_string) + 3;
499 
500                             //if length exceeds size of string
501                             if (print_string_len > print_string_size) {
502 
503                                 while (print_string_len >= print_string_size) {
504                                     print_string_size *= 2;
505                                 }
506 
507                                 char* temp_string = calloc(print_string_size + 1, sizeof(char));
508                                 strcpy(temp_string, print_string);
509                                 free(print_string);
510                                 print_string = temp_string;
511                                 temp_string = NULL;
512                             }
513 
514                             //add ", " fot string for formatting
515                             if (strlen(print_string) > 0) {
516                                 strcat(print_string, ", \0");
517                                 //TBR
518                                 //printf("AFTER TACKING ON COMMA!\n");
519                             }
520                             strcat(print_string, user_string);
521                             //TBR
522                             //fprintf(out, "before fail 111\n");
523                             //fprintf(out, "user_string is  %s\n", user_string);
524                             //fprintf(out, "user_string ptr is %p\n", user_string);
525                             free(user_string);
526                             //TBR
527                             //fprintf(out, "after fail 111???\n");
528                             user_string = NULL;
529                         }
530                     }
531 
532                     friends_friend = friends_friend->next_friend;
533                 }
534 
535                 a_friend = a_friend->next_friend;
536             }
537 
538             if (num_suggestions != 0) {
539                 fprintf(out, "%s may know following people because they have %d mutual friend(s):\n%s    ........\n", username, max_friends, print_string);
540             }
541             else {
542                 fprintf(out, "Sorry, there are no friend suggestions for %s.\n", username);
543             }
544 
545             free(print_string);
546             print_string = NULL;
547         }
548         else {
549             fprintf(out, "User %s does not exist. Please try again.\n", username);
550         }
551     }
552     else {
553         fprintf(out, "%s username is not a valid username\n", username);
554     }
555     //printf("EXIT suggest_friends\n");
556 }



//Takes a user_node and returns a char* to a string holding the user's info
771     //in the format name/age/gender/location
772 char* get_user_string(struct user_node *user) {
773     char age[5];
774     sprintf(age, "%d", (user->age));
775     char* gender = NULL;
776 
777     //Female
778     if (user->gender == 0) {
779         gender = "female\0";
780     }
781     //male
782     else {
783         gender = "male\0";
784     }
785 
786     //allocate memory for length of location, name, age, and gender + 3 '/'s + \0
787         //+20 for good measure!!!
788     char* user_string = NULL;
789     user_string = calloc((strlen(user->name) + strlen(user->location) + strlen(age) + strlen(gender)     ........+ 4 + 20), sizeof(char));
790     strcat(user_string, user->name);
791     strcat(user_string, "/");
792     strcat(user_string, age);
793     strcat(user_string, "/");
794     strcat(user_string, gender);
795     strcat(user_string, "/");
796     strcat(user_string, user->location);
797     return user_string;
798 }

When I run it through valgrind I get this output:

==10158== Memcheck, a memory error detector
==10158== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==10158== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==10158== Command: ./social_network -f crash_tester.txt crash_test_output.txt
==10158== 
==10158== Invalid write of size 1
==10158==    at 0x402C36B: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10158==    by 0x804A434: suggest_friends (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==  Address 0x41f12bb is 0 bytes after a block of size 51 alloc'd
==10158==    at 0x402A5E6: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10158==    by 0x804A1F3: suggest_friends (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158== 
==10158== Invalid write of size 1
==10158==    at 0x402C390: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10158==    by 0x804A434: suggest_friends (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==  Address 0x41f12cf is not stack'd, malloc'd or (recently) free'd
==10158== 
==10158== Invalid read of size 1
==10158==    at 0x4089E29: vfprintf (vfprintf.c:1630)
==10158==    by 0x4091EBE: fprintf (fprintf.c:33)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==  Address 0x41f12bb is 0 bytes after a block of size 51 alloc'd
==10158==    at 0x402A5E6: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10158==    by 0x804A1F3: suggest_friends (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158== 
==10158== Invalid read of size 4
==10158==    at 0x40C40BC: __GI_mempcpy (mempcpy.S:60)
==10158==    by 0x40B6769: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1350)
==10158==    by 0x4089E01: vfprintf (vfprintf.c:1630)
==10158==    by 0x4091EBE: fprintf (fprintf.c:33)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==  Address 0x41f12bb is 0 bytes after a block of size 51 alloc'd
==10158==    at 0x402A5E6: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10158==    by 0x804A1F3: suggest_friends (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804B25A: command_read (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049460: read_args_file (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x8049294: switch_parsing (in /home/ethan/cs2506/comp-org-3/social_network)
==10158==    by 0x804ACF7: main (in /home/ethan/cs2506/comp-org-3/social_network)
==10158== 

Upvotes: 2

Views: 2036

Answers (1)

Ben Kelly
Ben Kelly

Reputation: 1344

I believe the problem is here:

print_string_len = strlen(user_string) + 3;

//if length exceeds size of string
if (print_string_len > print_string_size) {

    while (print_string_len >= print_string_size) {
        print_string_size *= 2;
    }

    char* temp_string = calloc(print_string_size + 1, sizeof(char));
    strcpy(temp_string, print_string);
    free(print_string);
    print_string = temp_string;
    temp_string = NULL;
}

//add ", " fot string for formatting
if (strlen(print_string) > 0) {
    strcat(print_string, ", \0");
}
strcat(print_string, user_string);

While you attempt to pre-check the end result length against your buffer limit, the end result length is not calculated correctly. You are forgetting to include the pre-existing contents of the buffer; e.g. strlen(print_string).

So I think you need to change:

print_string_len = strlen(user_string) + 3;

to:

print_string_len = strlen(print_string) + strlen(user_string) + 3;

Upvotes: 1

Related Questions