条件跳转或移动取决于使用 realloc 的未初始化值

Conditional jump or move depends on uninitialised value(s) using realloc

我用 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] = '[=10=]';
         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)

正在将评论转化为答案。

由于第 136 行包含 if(strstr(*usr_str,"\n") != NULL),优化器似乎注意到您正在寻找单个字符,并将其转换为 if (strchr(*usr_str, '\n') != NULL),然后 100% 逆行并使用旧的准标准函数 index() 而不是 strchr()。这就是 index() 出现在错误消息中的原因。

我认为剩下的问题 — valgrind 抱怨 *use_str 未正确初始化的原因 — 是您没有确保您的字符串以 null 结尾。 memcpy() 不能确保有一个空字节; read() 不能确保有一个空字节;但是 strstr()strchr()index() 都需要一个空终止字符串。

修复可能是:

  *usr_str = temp;
  memcpy(*usr_str + count - bytesread, buf, bytesread);
  (*usr_str)[count] = '[=10=]';
  if (strstr(*usr_str, "\n") != NULL)