繁体   English   中英

Valgrind 使用 C 中的链表读取大小为 4 的无效

[英]Valgrind Invalid read of size 4 with linked list in C

我在 C 语言中的链表遇到了一些问题。我实际上正在做一个项目,使用套接字与服务器和客户端连接。 我决定为我的客户使用链接列表。 这是我的结构:

typedef struct ClientsList_s {
    int sockfd;
    struct ClientsList_s *next;
} ClientsList_t;

因此,当我使用 valgrind 执行工作时,我从 6 个上下文中得到了 6 个错误。 这是一个错误的示例:

Invalid read of size 4
==33211==    at 0x109531: get_max_socket (server.c:26)
==33211==    by 0x1097C2: do_server_loop (server.c:80)
==33211==    by 0x109A40: launch_teams (main.c:53)
==33211==    by 0x109AE6: main (main.c:63)
==33211==  Address 0x4a58040 is 0 bytes inside a block of size 16 free'd
==33211==    at 0x483CA3F: free (in /usr/lib/x86_64-linux- 
gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==33211==    by 0x109675: receive_socket_message (server.c:47)
==33211==    by 0x109832: do_server_loop (server.c:86)
==33211==    by 0x109A40: launch_teams (main.c:53)
==33211==    by 0x109AE6: main (main.c:63)
==33211==  Block was alloc'd at
==33211==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux- 
gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==33211==    by 0x10937B: add_client (client.c:18)
==33211==    by 0x109777: check_new_socket (server.c:68)
==33211==    by 0x109816: do_server_loop (server.c:84)
==33211==    by 0x109A40: launch_teams (main.c:53)
==33211==    by 0x109AE6: main (main.c:63)

这是错误来自的函数:

static int get_max_socket(MasterSocket_t *server, ClientsList_t **clients)
{
    int maxSd = server->sockfd;
    ClientsList_t *temp = *clients;

    FD_ZERO(&server->readfds);
    FD_SET(server->sockfd, &server->readfds);
    while (temp != NULL) {
        if (temp->sockfd > 0)
            FD_SET(temp->sockfd, &server->readfds);
        if (temp->sockfd > maxSd)
            maxSd = temp->sockfd;
        temp = temp->next;
    }
    return (maxSd);
}

因此,当我关闭客户端并且服务器仍在运行时,会出现所有错误。 我在 while 中使用 temp 的每一行都会给我一个错误。 所以首先我认为这是一个初始化问题,但似乎并非如此。 这是我的功能:

void add_client(ClientsList_t **clients, int newSocket, int port)
{
    ClientsList_t *temp = NULL;
    ClientsList_t *last = *clients;

    temp = malloc(sizeof(ClientsList_t));
    temp->sockfd = newSocket;
    temp->next = NULL;
    if (*clients == NULL)
        *clients = temp;
    else {
        while (last->next != NULL)
            last = last->next;
        last->next = temp;
    }
}

还有一个功能,当我关闭他的客户时,我会破坏一个元素:

static void receive_socket_message(ClientsList_t **clients,
                                   MasterSocket_t *server)
{
    ClientsList_t *temp = *clients;
    ClientsList_t *tempDel = NULL;
    int valread = 0;
    int addrlen = 0;
    char buffer[1025];

    while (temp != NULL) {
        if (FD_ISSET(temp->sockfd, &server->readfds)) {
            if ((valread = read(temp->sockfd, buffer, sizeof(buffer))) == 0) {
                tempDel = temp;
                temp = temp->next;
                close(tempDel->sockfd);
                free(tempDel);
                continue;
            } else {
                buffer[valread] = '\0';
                printf("%s\n", buffer);
            }
        }
        temp = temp->next;
    }
}

如果你想测试一些东西,有我的循环功能:

static int check_new_socket(ClientsList_t **clients,
                            MasterSocket_t *server, int port)
{
    int newSocket = 0;

    if (FD_ISSET(server->sockfd, &server->readfds)) {
        if ((newSocket = accept(server->sockfd,
                                (struct sockaddr *)&server->address,
                                (socklen_t *)&server->addrlen)) < 0)
            return (-1);
        add_client(clients, newSocket, port);
    }
    return (0);
}

int do_server_loop(MasterSocket_t server, int port)
{
    int maxSd = 0;
    int activity = 0;
    ClientsList_t *clients = NULL;

    while (true) {
        maxSd = get_max_socket(&server, &clients);
        if ((activity = select(maxSd + 1, &server.readfds,
                               NULL, NULL, NULL)) < 0 
        &&  (errno != EINTR))
            return (-1);
        if (check_new_socket(&clients, &server, port) == -1)
            return (-1);
        receive_socket_message(&clients, &server);
    }
    destroy_clients(clients);
    return (0);
}

谢谢你的帮助。

问题出在receive_socket_message中:释放列表元素时,不会将前一个节点链接到下一个节点。

这是修改后的版本:

static void receive_socket_message(ClientsList_t **clients,
                                   MasterSocket_t *server)
{
    ClientsList_t *temp = *clients;
    ClientsList_t *tempDel = NULL;
    ClientsList_t **link = clients;
    int valread = 0;
    int addrlen = 0;
    char buffer[1025];

    while (temp != NULL) {
        if (FD_ISSET(temp->sockfd, &server->readfds)) {
            if ((valread = read(temp->sockfd, buffer, sizeof(buffer))) == 0) {
                tempDel = temp;
                *link = temp = temp->next;
                close(tempDel->sockfd);
                free(tempDel);
                continue;
            } else {
                buffer[valread] = '\0';
                printf("%s\n", buffer);
            }
        }
        link = &temp->next;
        temp = temp->next;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM