引出问题
项目中有如下代码片段:
#include <stdio.h>
#include <string.h>
struct st {
char *buf;
int buflen;
};
static void st_test(struct st *st)
{
char *msg = "abc";
/* 若注释下行代码会导致段错误 */
// st->buf = "";
printf("addr_st is: 0x%p\n", st->buf);
printf("begin check st ...\n");
if (!strncmp(st->buf, msg, 3)) {
printf("st is valid!\n");
}
printf("check st done!\n");
}
int main(void)
{
struct st st;
memset(&st, 0, sizeof(st));
st_test(&st);
return 0;
}
编译代码并执行:
> % gcc -g st_test.c
-> % ./a.out
addr_st is: 0x(nil)
begin check st ...
[2] 14728 segmentation fault (core dumped) ./a.out
分析与解决
从运行的打印错误可以明显看出,使用memset把结构体初始化为0后,结构体中指针指向NULL。把NULL直接传递给strncmp导致段错误。
passing NULL as string pointer to strcmp() function; that try to deference at NULL to compare chars codes (e.g. acsii code) this cause undefined behavior at run time.
strcmp的源码如下:
#include <string.h>
#undef strcmp
#ifndef STRCMP
# define STRCMP strcmp
#endif
/* Compare S1 and S2, returning less than, equal to or
greater than zero if S1 is lexicographically less than,
equal to or greater than S2. */
int
STRCMP (const char *p1, const char *p2)
{
const unsigned char *s1 = (const unsigned char *) p1;
const unsigned char *s2 = (const unsigned char *) p2;
unsigned char c1, c2;
do
{
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0')
return c1 - c2;
}
while (c1 == c2);
return c1 - c2;
}
libc_hidden_builtin_def (strcmp)
strcmp/strncmp库函数未对参数合法性进行检查,所以需要调用者对参数合法性负责。在调用该类函数前对参数进行合法性检查。
如:
assert((NULL != str1) && (NULL != str2))
if ((NULL != str1) && (NULL != str2))
{
return 0;
}