字符串复制到malloc'd char数组失败,出现分段错误

时间:2015-08-10 14:22:58

标签: c gdb malloc client-server

我在C中练习客户端 - 服务器应用程序。在应用程序中,客户端首先向服务器注册并获得client_id作为回报。下一次,客户端将消息发送到服务器,然后将client_id添加到消息之前。下面的代码片段来自服务器,在收到消息后,服务器从消息中检索client_id,这是一个3字符长的字符串,起始地址为1,结束地址为4,来自消息数组。例如。在消息"1001CLIENT:001:MESSAGE:01"中,位置0的“1”用于某种目的,“001”是client_id"CLIENT:001:MESSAGE:01"是来自客户端的消息。

char *create_dynamic_string(int str_size)
{
        char *dyn_string = malloc(str_size*sizeof(char));
        if(!dyn_string)
        {
                printf("Dynamic string could not be created");
                return NULL;
        }
        dyn_string[0] = '\0';
        return dyn_string;
}

void free_dynamic_string(char *dyn_string)
{
        free(dyn_string);
}

//char *message is dynamically allocated char array.
char *retrieve_client_id(char *message)
{
        char *client_id;
        int i;
        client_id = create_dynamic_string(CLIENT_ID_SIZE + 1);

        if(!client_id)
        {
                printf("Client_id is NULL");
                return NULL;
        }
        //for(i = 1; i < (CLIENT_ID_SIZE + 1); i++)
        //      client_id[i-1] = message[i];

        //strncpy(client_id, message + 1, CLIENT_ID_SIZE);

        memcpy(client_id, message + 1, CLIENT_ID_SIZE);

        client_id[CLIENT_ID_SIZE] = '\0';
        printf("client_id retrieved=%s", client_id);
        return client_id;
}

服务器接受来自客户端的连接并处理不同线程中的消息。成功测试了对多线程和消息处理的工作。下面的代码编译成功并且大部分时间都可以工作。但有时它会在memcpy() retrieve_client_id()处的分段错误中结束。我无法弄清楚为什么会这样失败。

我使用gdb获取更多信息。如下所示。

Program terminated with signal 11, Segmentation fault.
#0  0x00000000004017ef in retrieve_client_id (message=0x1b904f40 "1000CLIENT:000:MESSAGE:02") at src/server.c:46
46              memcpy(client_id, message + 1, CLIENT_ID_SIZE);
(gdb) print message
$1 = 0x1b904f40 "1000CLIENT:000:MESSAGE:02"
(gdb) print message+1
$2 = 0x1b904f41 "000CLIENT:000:MESSAGE:02"
(gdb) print CLIENT_ID_SIZE
$3 = 3
(gdb) print client_id
$4 = 0xffffffffcc0008c0 <Address 0xffffffffcc0008c0 out of bounds>
(gdb)               

需要帮助了解应用程序失败时可能发生的确切情况。我已验证malloc成功且client_id不是NULL。正如您可以看到注释代码一样,我也尝试使用strcpy()并逐个将chars从source复制到dest数组。但我也看到了失败。

1 个答案:

答案 0 :(得分:2)

我猜测create_dynamic_stringretrieve_client_id处于不同的编译单元中,并且当编译后者时,您没有前者可见的正确原型。

此地址0xffffffffcc0008c0看起来像一个合理的堆地址0xcc0008c0,并附加了额外的位。

添加以下行:

extern char *create_dynamic_string(int);

就在retrieve_client_id的定义之上。

如果这样可以解决问题(应该),则将create_dynamic_string的原型添加到相应的头文件中,并将#include添加到定义retrieve_client_id的源中。

  

我不明白为什么它没有给出编译错误

在C中,未声明的函数假设具有以下原型:

int undeclared(...);

因此,以下任何一项电话都不会被拒绝:

int x = undeclared();
int y = undeclared(1);
char *z = undeclared(1, 2, 3);

你可以要求 GCC警告你特意使用-Wmissing-prototypes丢失原型,但最佳做法是使用-Wall-Werror进行编译。后者不会让你忽略警告而强制你修复它们。

还建议添加-Wextra,但有时会发出误报警告。