我在c中编写了一个简单的echo-server,它写回了除写入之外的所有客户端(使用realloc),我在valgrind中得到错误,而且我不确定我做错了什么。我想得到一些帮助。 这是我的代码:
int read_from_socket(int connfd,char **usr_str);
int main (int argc,char* argv[])
{
int sockFD;
int port, new;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in serveraddr;
struct sockaddr_in clientname;
int size;
char buf[4096];
int j;
bzero(&buf, sizeof(buf));
char* data;
//Check command line args
if (argc != 2)
{
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(EXIT_FAILURE);
}
port = atoi(argv[1]);
// socket: create a socket
sockFD = socket(AF_INET, SOCK_STREAM, 0);
if (sockFD < 0)
printf("ERROR opening socket\n");
// build the server's internet address
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET; // we are using the Internet
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // accept reqs to any IP addr
serveraddr.sin_port = htons((unsigned short)port); // port to listen on
// bind: associate the listening socket with a port
if (bind(sockFD, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
printf("ERROR on binding\n");
// Create the socket and set it up to accept connections.
if (listen (sockFD, 20) < 0)
{
printf("ERROR on listening\n");
exit (EXIT_FAILURE);
}
// Initialize the set of active sockets.
FD_ZERO (&active_fd_set);
FD_SET (sockFD, &active_fd_set);
while (1)
{
// Block until input arrives on one or more active sockets.
read_fd_set = active_fd_set;
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
{
printf("ERROR in selecting");
exit (EXIT_FAILURE);
}
// Service all the sockets with input pending.
if (FD_ISSET (sockFD, &read_fd_set))
{
// Connection request on original socket.
size = sizeof (clientname);
new = accept (sockFD,(struct sockaddr *) &clientname, &size);
if (new < 0)
{
printf("ERROR in accepting");
exit (EXIT_FAILURE);
}
fprintf (stderr, "Server: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
continue;
}
data = NULL;
for (i = 0 ; i<FD_SETSIZE; ++i)
if (i != sockFD && FD_ISSET(i, &read_fd_set))
{
if(read_from_socket(i, &data) == -1)//(line: 99)
{
printf("Closing read\n");
close(i);
FD_CLR(i, &active_fd_set);
}
for (j = 0; j < FD_SETSIZE; ++j)
if (j != i && j != sockFD && FD_ISSET(j, &active_fd_set))
write(j,data,strlen(data));//(line: 108)
}
free(data);
}
}
int read_from_socket(int connfd,char **usr_str)
{
int count = 0, bytesread = 0;
char *temp;
char buf[16] = {0};
while((bytesread = read(connfd,buf,16)) > 0)
{
if(bytesread == 0)
return -1;
temp = NULL;
count = count + bytesread;
temp = realloc(*usr_str, count+1);//(line: 128)
if(NULL == temp)
{
printf("\nMemory Error\n");
return -1;
}
*usr_str = temp;
memcpy(((*usr_str) + count - bytesread),buf, bytesread);
if(strstr(*usr_str,"\n") != NULL)//(line: 136)
{
(*usr_str)[count] = '\0';
break;
}
}
return 0;
}
这是我的valgrind错误(我在代码中写了行号):
==4213== Conditional jump or move depends on uninitialised value(s)
==4213== at 0x4C2D6DD: index (vg_replace_strmem.c:232)
==4213== by 0x401303: read_from_socket (echoServerNew.c:136)
==4213== by 0x4010D0: main (echoServerNew.c:99)
==4213== Uninitialised value was created by a heap allocation
==4213== at 0x4C2D094: malloc (vg_replace_malloc.c:296)
==4213== by 0x4C2D208: realloc (vg_replace_malloc.c:692)
==4213== by 0x401291: read_from_socket (echoServerNew.c:128)
==4213== by 0x4010D0: main (echoServerNew.c:99)
==4213==
==4213== Conditional jump or move depends on uninitialised value(s)
==4213== at 0x4C2D6D2: index (vg_replace_strmem.c:232)
==4213== by 0x401303: read_from_socket (echoServerNew.c:136)
==4213== by 0x4010D0: main (echoServerNew.c:99)
==4213== Uninitialised value was created by a heap allocation
==4213== at 0x4C2D094: malloc (vg_replace_malloc.c:296)
==4213== by 0x4C2D208: realloc (vg_replace_malloc.c:692)
==4213== by 0x401291: read_from_socket (echoServerNew.c:128)
==4213== by 0x4010D0: main (echoServerNew.c:99)
答案 0 :(得分:5)
将评论转换为答案。
由于第136行包含if(strstr(*usr_str,"\n") != NULL)
,优化器似乎注意到你正在寻找一个单个字符,并将其转换为if (strchr(*usr_str, '\n') != NULL)
,然后100%逆行并使用旧的,预标准函数index()
而不是strchr()
。这就是index()
出现在错误消息中的原因。
我认为问题的其余部分 - valgrind
抱怨*use_str
未正确初始化的原因 - 是您不确保您的字符串以空值终止。 memcpy()
不能确保存在空字节; read()
不能确保有空字节;但是strstr()
或strchr()
或index()
都期望一个空终止的字符串。
修复可能是:
*usr_str = temp;
memcpy(*usr_str + count - bytesread, buf, bytesread);
(*usr_str)[count] = '\0';
if (strstr(*usr_str, "\n") != NULL)