C 为什么这里有一个无效的写入(Valgrind)

C 为什么这里有一个无效的写入(Valgrind),c,valgrind,C,Valgrind,我正在编写一个shell。当我像这样执行它时,cat/dev/uradom | valgrind./myshell运行一些测试,看看我是否没有任何segfault或其他错误,valgrind有时会告诉我,在这行tab[++j]=str[*I]的函数my_wordcpy中有一个无效的Write 这不是每次都会发生,但确实发生了,我就是不明白为什么。这是我的密码: static int count_words(char *str, char *sep) { int

我正在编写一个shell。当我像这样执行它时,
cat/dev/uradom | valgrind./myshell
运行一些测试,看看我是否没有任何segfault或其他错误,
valgrind
有时会告诉我,在这行
tab[++j]=str[*I]的函数
my_wordcpy
中有一个
无效的Write

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

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);
}
static int count\u字(char*str,char*sep)
{
国际报价;
智力词;
int i;
i=-1;
if(count_quotes(str)=-1)
返回(0);
字=0;
报价=0;
而(str[++i]!='\0')
{
如果(str[i]=''''''')
{
如果(引号==0)
报价=1;
其他的
报价=0;
}
如果(引号==0
&&(是(sep,str[i))==0&&str[i]!='\t'&&
(是中国(九月,str[i+1])==1||
str[i+1]='\t'| | str[i+1]=='\0'))
++文字;
}
返回(文字);
}
静态int my_wordlen(char*str,int*i,char*sep)
{
国际报价;
int j;
j=0;
报价=0;
而(str[++(*i)]!='\0')
如果(str[*i]==''“&"e==0)
报价=1;
如果(quote==1 | |)(quote==0&&is|cinside(sep,str[*i])==0&&
str[*i]!='\t'))
{
++j;
如果((引号==1&&str[*i+1]==”)||
(quote==0&&(是中国的九月,月[*i+1])==1||
str[*i+1]='\t'||
str[*i+1]=='\0'))
{
如果(quote==1&&str[*i+1]=='”)
++(*一);
返回(j);
}
}
返回(-1);
}
静态字符*my_wordcpy(字符*tab,字符*str,int*i,字符*sep)
{
国际报价;
int j;
j=-1;
报价=0;
而(str[++(*i)]!='\0')
如果(str[*i]==''“&"e==0)
报价=1;
如果(quote==1 | |)(quote==0&&
是(sep,str[*i])==0&&str[*i]!='\t'))
{
tab[++j]=str[*i];/*这是无效写入*/
如果((引号==1&&str[*i+1]==”)||
(quote==0&&(是中国的九月,月[*i+1])==1||
str[*i+1]='\t'| | str[*i+1]=='\0'))
{
如果(quote==1&&str[*i+1]=='”)
++(*一);
制表符[++j]='\0';
返回(选项卡);
}
}
返回(空);
}
字符**我的单词标签(字符*str,字符*sep)
{
字符**选项卡;
智力词;
int i;
int j;
int k;
i=-1;
j=-1;
k=-1;
如果(str==NULL)
返回(空);
单词=计数单词(str,sep);
if((tab=malloc(sizeof(char*)*(words+1)))==NULL)
返回(空);
while(++i<字)
{
if((tab[i]=malloc(sizeof(char)*(my_wordlen(str,&j,sep)+1)))
==空)
返回(空);
tab[i]=我的单词cpy(tab[i],str,&k,sep);
}
tab[i]=NULL;
返回(选项卡);
}

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

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

您可以在代码中设置一个if大小写(断言),以确保增量后
j
中的值以及
*i
也是有效的,并且仍然在
选项卡
str
数组中吗?写入无效的唯一方法是如果
j
越界,如果
tab
是垃圾,如果
*i
越界,或者
str
是garabge。好吧,我不认为它越界,因为我通过返回my_wordlen函数来计算正确的数量(这是相同的函数,只是它不复制,只计算字符)我还尝试了malloc更多(+1000)扩展边界,但它不起作用。我仍然有内存损坏崩溃。你说的tab是垃圾是什么意思?tab as垃圾将是传递到函数中的一个错误指针,尽管如果上述代码确实是进入函数的唯一途径,那么这种可能性非常低。在
j
上进行if检查将100%回答这个问题一个坏的索引,虽然我仍然认为你有一个问题,如我在下面所说的引号。是的,它会,但问题是,我受一个编码风格的限制,我不能发送超过4个参数到一个函数,我已经有4个在这一个。所以我真的不知道我如何放置一个好的检查,而不发送标签的长度:-/我不知道引号是这里的问题,我没有把它粘贴在这里,但我有一个函数,我在开始时调用它(用count_单词),它检查我是否有正确的引号数。(移动检查将是第二个安全措施,所以我无论如何都要这样做,谢谢)这个答案似乎并没有提供问题的答案。若要评论或要求作者澄清,请在他们的帖子下方留下评论。是的,事实证明这不是主要答案,但这是当时最好的答案,并最终显示出潜在的问题。这既不是批评,也不是要求澄清。哇谢谢你,我以前怎么看不到?!这似乎解决了问题!