【问题标题】:Why is there an Invalid Write here (Valgrind)为什么这里有一个无效的写入(Valgrind)
【发布时间】:2015-05-23 04:48:46
【问题描述】:

我正在编写一个 shell。当我像这样cat /dev/urandom | valgrind ./myshell 执行它来运行一些测试并查看我是否没有任何段错误或其他错误时,valgrind 有时会告诉我在函数my_wordcpy 中有一个Invalid Write 在这一行@987654325 @

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

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

【问题讨论】:

  • 您能否在您的代码(断言)中放置一个 if 案例,以确保在递增后 j 中的值以及 *i 也是有效的并且仍在 tab 内和str 数组?写入无效的唯一方法是如果j 超出范围,tab 是垃圾,*i 超出范围,或者str 是垃圾。
  • 好吧,我不认为它超出了界限,因为我用 my_wordlen 函数的返回分配了正确的数量(这是相同的函数,只是它不复制,只是计数字符),我还尝试了更多的 malloc(+ 1000)以扩大范围,但它不起作用。我仍然有内存损坏崩溃。标签是垃圾是什么意思?
  • tab asgarbage 将是一个错误的指针传递给函数,但如果上面的代码确实是进入函数的唯一方法,这种可能性非常低。
  • j 进行 if 检查将 100% 解决索引错误的问题,但我仍然认为您对引用有问题,如下所述。
  • 是的,但问题是我受到编码风格的限制,我不能向函数发送超过 4 个参数,而我已经有 4 个。所以我真的不明白如何在不发送标签长度的情况下进行良好的检查:-/

标签: c valgrind


【解决方案1】:

my_wordlen 可以返回-1,并且在将其提供给malloc 之前不要检查它。在这种情况下,0 字节被分配,因此在my_wordcopy 中会发生堆缓冲区溢出。

【讨论】:

  • 哇,谢谢,我以前怎么看不到?!这似乎解决了问题!
【解决方案2】:

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

【讨论】:

  • 我不知道引号是否是这里的问题,我没有在这里粘贴它,但我有一个函数,我在开始时调用(在 count_words 中)检查我是否有正确的报价数量。 (不过,移动支票将是第二道安全措施,所以无论如何我都会这样做,谢谢)
  • 这个答案似乎没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • 是的,事实证明这不是主要答案,但它是当时最好的答案,并且最终显示出潜在的问题。这不是批评,也不是要求澄清。
猜你喜欢
  • 2019-09-14
  • 2014-08-04
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多