2013-03-25 56 views
3

我有一个奇怪的错误,由valgrind在一个(愚蠢的)验证模块上发现一些堆分配。分析valgrind输出:“无效的免费()”

==8009== Invalid free()/delete/delete[]/realloc() 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x40263F: authenticate (server_utils.c:109) 
==8009== by 0x401A27: main (server.c:240) 
==8009== Address 0x51f1310 is 0 bytes inside a block of size 18 free'd 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x402633: authenticate (server_utils.c:108) 
==8009== by 0x401A27: main (server.c:240) 
=8009== 
==8009== Invalid free()/delete/delete[]/realloc() 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x40264B: authenticate (server_utils.c:110) 
==8009== by 0x401A27: main (server.c:240) 
==8009== Address 0x51f1319 is 9 bytes inside a block of size 18 free'd 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x402633: authenticate (server_utils.c:108) 
==8009== by 0x401A27: main (server.c:240) 
==8009== 
==8009== Invalid free()/delete/delete[]/realloc() 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x402657: authenticate (server_utils.c:111) 
==8009== by 0x401A27: main (server.c:240) 
==8009== Address 0x51f131e is 14 bytes inside a block of size 18 free'd 
==8009== at 0x4C2A739: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8009== by 0x402633: authenticate (server_utils.c:108) 
==8009== by 0x401A27: main (server.c:240) 
==8009== ... 

从我所了解的他说我做了三个无效的免费()线109-110-111。错误应该是我试图释放比实际分配的空间更多的空间,但我无法决定释放多少空间。另外我不明白为什么它会引用第108行(这也是一个免费的())。

这是从文档(无效免费):

MEMCHECK跟踪你的程序使用malloc /新分配的块,所以它可以准确地知道与否的说法释放/删除是合法与否。在这里,这个测试程序已经释放了同一块两次。与非法读/写错误一样,Memcheck试图理解释放的地址。如果这里的地址是先前已被释放的地址,那么您将被告知 - 使同一块的重复释放容易被发现。

如果您尝试释放一个指向堆块起点的指针,您也会收到此消息。

我真的无法想象如何在这些案件之一。

/* Authentication through <user_id:password:flag> 
* Returns 1 on success, -1 if user_id doesn't exist, -2 on password mismatch 
* On success sets access_permissions 
*/ 
int authenticate(USR_PSW *received, int *access_permissions) { 

/*Users file opening*/ 
FILE *fd; 
fd = fopen(USERS_FILE, "r"); 
if (fd == NULL) { 
    fprintf(stderr, "Users file opening error\n"); 
    exit(EXIT_FAILURE); 
} 

char *usr_psw_line = malloc(USR_SIZE + PSW_SIZE + 3 + 1); 
if (usr_psw_line == NULL) { 
    fprintf(stderr, "Dynamic alloc error\n"); 
    exit(EXIT_FAILURE); 
} 
char *usr_tok = malloc(USR_SIZE); 
if (usr_tok == NULL) { 
    free(usr_psw_line); 
    fprintf(stderr, "Dynamic alloc error\n"); 
    exit(EXIT_FAILURE); 
} 
char *psw_tok = malloc(PSW_SIZE); 
if (psw_tok == NULL) { 
    free(usr_psw_line); 
    free(usr_tok); 
    fprintf(stderr, "Dynamic alloc error\n"); 
    exit(EXIT_FAILURE); 
} 
char *flg_tok = malloc(sizeof (char) *2); 
if (flg_tok == NULL) { 
    free(usr_psw_line); 
    free(usr_tok); 
    free(psw_tok); 
    fprintf(stderr, "Dynamic alloc error\n"); 
    exit(EXIT_FAILURE); 
} 

/*Reading from file <user_id:password:flag> */ 
while (fgets(usr_psw_line, USR_SIZE - 1 + PSW_SIZE - 1 + 3 + 1, fd) != NULL) { 
    usr_tok = strtok(usr_psw_line, ":"); 

    if (strcmp(usr_tok, received->user_id) == 0) { 
     /*user_id found, password check*/ 
     psw_tok = strtok(NULL, ":"); 
     /*password match*/ 
     if (strcmp(psw_tok, received->password) == 0) { 
      flg_tok = strtok(NULL, ":"); 
      *access_permissions = atoi(flg_tok); 
      free(usr_psw_line); //108 
      free(usr_tok);//109 
      free(psw_tok);//110 
      free(flg_tok);//111 
      fclose(fd); 
      return AUTHENTICATED; 
     } else { //password unmatch 
      free(usr_psw_line); 
      free(usr_tok); 
      free(psw_tok); 
      free(flg_tok); 
      fclose(fd); 
      return INVALID_PSW; 
     } 
    } else { 
     fseek(fd, 1, SEEK_CUR); 
     continue; 
    } 

} 
/*EOF Reached without match*/ 
free(usr_psw_line); 
free(usr_tok); 
free(psw_tok); 
free(flg_tok); 
fclose(fd); 
return INVALID_USR; 

} 

头文件:

#ifndef __SERVER_UTILS_H__ 
#define __SERVER_UTILS_H__ 

#define USR_SIZE 9 
#define PSW_SIZE 5 

/*Authentication data structure definition*/ 
typedef struct{ 
    char user_id[USR_SIZE]; // eg: user_123 
    char password[PSW_SIZE]; // eg: a1b2 
} USR_PSW; 

#define NM_MAX_SIZE 17 
#define NR_MAX_SIZE 11 

/*System record structure*/ 
typedef struct{ 
    char first_name[NM_MAX_SIZE]; 
    char last_name[NM_MAX_SIZE]; 
    char number[NR_MAX_SIZE]; 
}TBOOK_RECORD; 


/*Session status flags*/ 
#define NOT_AUTHENTICATED 0 
#define AUTHENTICATED 1 
#define INVALID_USR 2 
#define INVALID_PSW 3 

/*Persmissions flags*/ 
#define NO_PERM 0 
#define READ_WRITE 1 
#define O_WRITE 2 
#define O_READ 3 

/*Contains <user_id:password,flag> triplets stored in server */ 
#define USERS_FILE "users.txt" 

/*Contains all telbook records <first_name:last_name:phone_number>*/ 
#define RECORDS_FILE "records.txt" 

/*Single records file line max length (before \n) */ 
#define RECFILE_LINE_MAX_LEN 2*NM_MAX_SIZE+NR_MAX_SIZE+3+1; 

/*Client operation*/ 
#define NO_OP 0 
#define SEARCH_BY_NAME 1 
#define SEARCH_BY_NUMBER 2 
#define INSERT_RECORD 3 

/* 
* Returns number of bytes copied into buffer (excluding terminating null byte), 
* or 0 on EOF, or -1 on error. 
* size_t : used for sizes of objects. 
* ssize_t: used for a count of bytes or an error indication (-1). 
*/ 
ssize_t readline(int fd, void *buffer, size_t n); 

/* Authentication through <user_id:password:flag> 
* Returns 1 on success, -1 if user_id doesn't exist, -2 on password mismatch 
* On success sets access_permissions 
*/ 
int authenticate(USR_PSW *received, int *access_permissions); 


int close_session(int sock_ds); 

int search_by__(int op_code, TBOOK_RECORD *rc_rcvd, TBOOK_RECORD *rc_rspn 
      , FILE *fd, char *file_line); 

int insert_record(TBOOK_RECORD *rc_rcvd); 

#endif /* __SERVER_UTILS_H__ */ 
+0

行号编 – 2013-03-25 18:43:43

回答

4
usr_tok = strtok(usr_psw_line, ":"); 
... 
    psw_tok = strtok(NULL, ":"); 

您将要覆盖指针您malloc版内存的指针(从而泄漏的话)在其他地方。然后你试图free你从别处收到的指针,这是(如valgrind所说)无效。

+0

干得好;打我吧! – 2013-03-25 18:42:31

1

当您使用strok()时,您正在更改指针地址。当你打电话给free()时,你可能不会指向整个块。您可以使用辅助指针来存储strok()返回值,然后您可以使用原始指针来释放()所有分配的空间correclty。

+0

我应该复制第一个指针吗? – 2013-03-25 19:00:01

+1

第一个指针是什么意思?你应该做的是创建一个新的指针来存储strok()返回地址,而不是覆盖你使用malloc()调用的指针变量。换句话说,您应该始终保留malloc()返回的地址,然后您可以释放()而不会出现任何问题。当你调用strok()并分配和malloc一样的指针时,它会覆盖这个地址并且可能指向那个空间的中间。这就是为什么你释放空间时会出现不同的空间错误。 – 2013-03-25 20:22:51

+0

因此,不要覆盖这个地址,你应该总是创建一个新的指针并保留这个malloced地址,这样你就可以释放()。 – 2013-03-25 20:23:47

2

要添加到上面的回答只是确保你FCLOSE(FP)中的所有,你有一个return语句的情况下

+0

也在出口右侧? – 2013-03-25 18:52:45

+1

是从函数的所有出口路径是的 – Pradheep 2013-03-25 18:56:37

+1

谢谢!我爱你们 :) – 2013-03-25 18:59:27