为什么这里有无效写(Valgrind)

时间:2015-05-22 20:00:02

标签: c valgrind

我正在编写一个shell。当我按照此cat /dev/urandom | valgrind ./myshell执行此操作以进行某些测试并查看我是否有任何段错或其他错误时,valgrind有时会告诉我我的函数中有Invalid Write这一行my_wordcpy

tab[++j] = str[*i];

每次都不会发生,但它确实发生了,我只是不明白为什么。这是我的代码:

static int      count_words(char *str, char *sep)
{
  int           quote;
  int           words;
  int           i;

  i = -1;
  if (count_quotes(str) == -1)
    return (0);
  words = 0;
  quote = 0;
  while (str[++i] != '\0')
    {
      if (str[i] == '"')
        {
          if (quote == 0)
            quote = 1;
          else
            quote = 0;
        }
      if (quote == 0
          && (is_cinside(sep, str[i]) == 0 && str[i] != '\t' &&
              (is_cinside(sep, str[i + 1]) == 1 ||
           str[i + 1] == '\t' || str[i + 1] == '\0')))
        ++words;
    }
  return (words);
}

static int      my_wordlen(char *str, int *i, char *sep)
{
  int           quote;
  int           j;

  j = 0;
  quote = 0;
  while (str[++(*i)] != '\0')
    if (str[*i] == '"' && quote == 0)
      quote = 1;
    else if (quote == 1 || (quote == 0 && is_cinside(sep, str[*i]) == 0 &&
                            str[*i] != '\t'))
      {
        ++j;
        if ((quote == 1 && str[*i + 1] == '"') ||
            (quote == 0 && (is_cinside(sep, str[*i + 1]) == 1 ||
                            str[*i + 1] == '\t' ||
                            str[*i + 1] == '\0')))
          {
            if (quote == 1 && str[*i + 1] == '"')
              ++(*i);
            return (j);
          }
      }
  return (-1);
}

static char     *my_wordcpy(char *tab, char *str, int *i, char *sep)
{
  int           quote;
  int           j;

  j = -1;
  quote = 0;
  while (str[++(*i)] != '\0')
    if (str[*i] == '"' && quote == 0)
      quote = 1;
    else if (quote == 1 || (quote == 0 &&
                        is_cinside(sep, str[*i]) == 0 && str[*i] != '\t'))
  {
    tab[++j] = str[*i];            /* here is the invalid write. */
    if ((quote == 1 && str[*i + 1] == '"') ||
        (quote == 0 && (is_cinside(sep, str[*i + 1]) == 1 ||
                        str[*i + 1] == '\t' || str[*i + 1] == '\0')))
      {
        if (quote == 1 && str[*i + 1] == '"')
          ++(*i);
        tab[++j] = '\0';
        return (tab);
      }
  }
  return (NULL);
}

char            **my_quotetowordtab(char *str, char *sep)
{
  char          **tab;
  int           words;
  int           i;
  int           j;
  int           k;

  i = -1;
  j = -1;
  k = -1;
  if (str == NULL)
    return (NULL);
  words = count_words(str, sep);
  if ((tab = malloc(sizeof(char *) * (words + 1))) == NULL)
    return (NULL);
  while (++i < words)
    {
      if ((tab[i] = malloc(sizeof(char) * (my_wordlen(str, &j, sep) + 1)))
          == NULL)
            return (NULL);
      tab[i] = my_wordcpy(tab[i], str, &k, sep);
    }
  tab[i] = NULL;
  return (tab);
}

2 个答案:

答案 0 :(得分:5)

my_wordlen可以返回-1,在将其发送给malloc之前,您不会检查此内容。在这种情况下,0字节被分配,因此my_wordcopy发生堆缓冲区溢出。

答案 1 :(得分:1)

如果您的str只有一个或多个"引号字符,会发生什么?在这种情况下,您的代码似乎不会检查\0,因此可以通过标签的结尾写入。我认为您需要在第二个if子句之外移动NUL字符检查来捕获这两种情况。