由uuid_to_string函数想到的C语言函数返回字符串问题

来源:互联网 发布:网络推广工资一般多少 编辑:程序博客网 时间:2024/05/21 19:10

 下午让同事写一个函数,返回字符串形式的uuid给lua脚本,他的实现如下:

初看似乎没什么问题,先用uuid_create创建一个uuid,然后用uuid_to_string格式化成字符串,再把字符串push给脚本就可以了。但是实际上这个new_uuid函数是有内存泄漏的。问题出在uuid_to_string函数里面。

 

uuid_to_string将一个uuid结构格式化成字符串,格式化出来的字符串放在哪里呢?常见的做法是把存放字符串的空间通过指针传进去那么uuid_to_string的声明就是这样:

 

char*   uuid_to_string(uuid_t *uuid, char *str, uint32_t *status);

但实际上libc里面的声明是:

void     uuid_to_string(uuid_t *uuid, char **str, uint32_t *status);

 

第二个参数是char**,也就是说存放字符串的指针通过参数返回给调用者,而不是接受调用者分配的内存。那么它怎么做的呢,它里面是怎么分配内存的呢:

它既没有malloc内存也没有使用static的空间来保存字符串,而是直接调用了asprintf,看asprintf的手册:

 

The asprintf() and vasprintf() functions set *ret to be a pointer to a     buffer sufficiently large to hold the formatted string.  This pointer should be passed to free(3) to release the allocated storage when it is no longer needed.  If sufficient space cannot be allocated, asprintf() and vasprintf() will return -1 and set ret to be a NULL pointer.

 

也就是说asprintf是会调用malloc分配内存的,用完之后使用者必须自己调用free释放内存,uuid_to_string返回的是asprintf分配的内存,必须手动调用free来释放,所以说new_uuid函数有内存泄漏,应该在

lua_pushstring(L, uuidstr);

后面调用

free(uuidstr);

 

uuid_to_string函数是有问题的,首先它的文档没有说明用户需要free 返回的str,太容易使人犯错。更优雅的方式应该是

char*   uuid_to_string(uuid_t *uuid, char *str, uint32_t *status);

由使用者分配内存而不是自己分配内存。

 

另外它的实现也有问题:

if (s == 0)
                return;
这里既然不允许s==0,就不应该在前面把status设置成uuid_s_ok,否则当用户传入的s为0的时候,这个函数啥都没做,没有格式化uuid却把返回值设置成了uuid_s_ok。

 

当遇到返回字符串的C语言函数时都要给自己提个醒,想想他存字符串的空间哪里来的,用户传进去的?函数内部定义的static变量?还是函数内部malloc的,知道它怎么实现的你才能知道该怎么用它。

 

C函数返回字符串时,字符串存放在哪里呢?不外乎3中办法,1、用户分配好空间传进去,如strncpy;2、使用static空间,如strerror;3、自己分配内存空间,如文中的asprintf。对于第一种情况,用户需要检查传进去的空间够不够,不够的情况下函数会怎么处理;对于第二种情况,用户需要知道这个函数不是线程安全的,不能并发调用这种函数;对于第三种情况,则需要手动释放内存。

 

原创粉丝点击