strcmp/strncmp导致的段错误浅析

引出问题

项目中有如下代码片段:

#include 
#include 

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 

#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;
}

你可能感兴趣的:(strcmp/strncmp导致的段错误浅析)