I'm not seeing the error in the following linked list.


C

Chad

In the following code, 'free(temp->name); ' in the function cleanup()
causes the program to crash and I don't see why either.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 30

struct new {
char *name;
char *pword;
struct new *next;
};

void add_person(struct new** );
void printme(struct new* );
void cleanup(struct new* );

char *strddup(char *s, size_t n)
{
char *p;

p = malloc(strlen(s) + 1);
if (p != NULL)
(void)strncpy(p, s, n);
return p;
}

void add_person(struct new** head_ref)
{
char name[MAX];
char pword[MAX];
struct new *person;

if ((person = malloc(sizeof(struct new))) == NULL ) {
(void)fprintf(stderr, "Invalid name\n");
exit(1);
}

(void)printf("Enter a name: ");
fflush(stdout);

if ((scanf("%s", name)) == 1) {
if ((person->name = strddup(name, MAX)) == NULL) {
(void)fprintf(stderr, "Invalid name\n");
exit(1);
}
} else {
(void)fprintf(stderr, "Invalid input\n");
exit(1);
}

/*Need OS specific functions to disable echoing*/
(void)printf("Enter a pasword: ");
fflush(stdout);
if ((scanf("%s", pword)) == 1) {
if ((person->pword = strddup(pword, MAX)) == NULL ) {
(void)fprintf(stderr, "Invalid password\n");
exit(1);
}
} else {
(void)fprintf(stderr, "Invalid input\n");
exit(1);
}

person->next = *head_ref;
*head_ref = person;
}

void printme(struct new* head)
{
struct new* current = head;

printf("\n");

while (current != NULL) {
printf("The name is: %s\n", current->name);
printf("The password is: %s\n", current->pword);
current = current->next;
}
}

void cleanup(struct new* head)
{
struct new* temp;

while (head != NULL) {
temp = head;
head = head->next;
free(temp->name); /*<---the problem line of code*/
free(temp);
}
}

int main(void)
{
struct new* head= NULL;
int add = 1;
int c;

(void)printf("Do you want to add a name? ");
(void)printf("Enter either y|Y to enter one or n|N to exit: ");
fflush(stdout);

while(((c = getchar()) != EOF) && add != 0) {
switch(c)
{
case 'Y': case 'y':
add_person(&head);
break;
case 'N': case 'n':
add = 0;
break;
default:
(void)printf("Do you want to add another person? ");
fflush(stdout);
break;
}
}

printme(head);
cleanup(head);

exit(0);
}

And the partial output...

[[email protected] oakland]$ gcc -Wall -Wextra -Wshadow bored.c -o
bored
[[email protected] oakland]$ ./bored
Do you want to add a name? Enter either y|Y to enter one or n|N to
exit: y
Enter a name: chad
Enter a pasword: no
Do you want to add another person? n

The name is: chad
The password is: no
*** glibc detected *** ./bored: free(): invalid next size (fast):
0x0896e018 ***
======= Backtrace: =========
 
Ad

Advertisements

B

Ben Pfaff

Chad said:
In the following code, 'free(temp->name); ' in the function cleanup()
causes the program to crash and I don't see why either.

Use valgrind:

[email protected]:~/tmp(130)$ valgrind ./a.out
Do you want to add a name? Enter either y|Y to enter one or n|N to exit: y
Enter a name: chad
==5768== Invalid write of size 1
==5768== at 0x4025DB0: strncpy (mc_replace_strmem.c:329)
==5768== by 0x8048661: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80486FA: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768== Address 0x418906d is 0 bytes after a block of size 5 alloc'd
==5768== at 0x4024C4C: malloc (vg_replace_malloc.c:195)
==5768== by 0x804863F: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80486FA: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768==
==5768== Invalid write of size 1
==5768== at 0x4025DBD: strncpy (mc_replace_strmem.c:329)
==5768== by 0x8048661: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80486FA: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768== Address 0x418906e is 1 bytes after a block of size 5 alloc'd
==5768== at 0x4024C4C: malloc (vg_replace_malloc.c:195)
==5768== by 0x804863F: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80486FA: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768==
Enter a pasword: no
==5768== Invalid write of size 1
==5768== at 0x4025DB0: strncpy (mc_replace_strmem.c:329)
==5768== by 0x8048661: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80487B5: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768== Address 0x41890a3 is 0 bytes after a block of size 3 alloc'd
==5768== at 0x4024C4C: malloc (vg_replace_malloc.c:195)
==5768== by 0x804863F: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80487B5: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768==
==5768== Invalid write of size 1
==5768== at 0x4025DBD: strncpy (mc_replace_strmem.c:329)
==5768== by 0x8048661: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80487B5: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768== Address 0x41890a4 is 1 bytes after a block of size 3 alloc'd
==5768== at 0x4024C4C: malloc (vg_replace_malloc.c:195)
==5768== by 0x804863F: strddup (in /home/blp/tmp/a.out)
==5768== by 0x80487B5: add_person (in /home/blp/tmp/a.out)
==5768== by 0x8048942: main (in /home/blp/tmp/a.out)
==5768==
Do you want to add another person? n

The name is: chad
The password is: no
[email protected]:~/tmp(0)$
 
Ad

Advertisements

P

Paul N

In the following code, 'free(temp->name); ' in the function cleanup()
causes the program to crash and I don't see why either.

I think the problem is not with the linked list itself but in the way
you handle strings. If it's any consolation, handling input in C is a
bit of a pain and so many otherwise simple programs have to include
messy stuff to handle the input.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 30

struct new {
  char *name;
  char *pword;
  struct new *next;

};

void add_person(struct new** );
void printme(struct new* );
void cleanup(struct new* );

char *strddup(char *s, size_t n)
{
  char *p;

  p = malloc(strlen(s) + 1);

So, assuming malloc worked, p points to enough memory to hold the
string s, plus the 0 at the end of it. If, for instance, s is "Chad",
this reserves five bytes.
  if (p != NULL)
    (void)strncpy(p, s, n);

And here's your problem. I don't use strncpy much, if at all, but
looking it up shows that it pads the destination if the string copied
in is shorter than the length specified. So now, if s is "Chad", this
will copy in the four letters of it, followed by 26 nuls, into the
area pointed at by p. But you don't have enough space for these - you
write into memory that isn't yours, which presumably causes the crash.
  return p;

}

void add_person(struct new** head_ref)
{
  char name[MAX];
  char pword[MAX];
  struct new *person;

  if ((person = malloc(sizeof(struct new))) == NULL ) {
    (void)fprintf(stderr, "Invalid name\n");
    exit(1);
  }

  (void)printf("Enter a name: ");
  fflush(stdout);

  if ((scanf("%s", name)) == 1) {

It's perhaps worth pointing out that this could also overrun name, as
you have not put any limit on how much can be read in. This could be
fixed by replacing "%s" with "%29s", if I remember correctly.

Hope this all helps.
Paul.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top