0

C で独自のシェルを作成しようとしています。以下のコードは、パイプのないコマンドでは機能しますが、それ以外の場合は機能しません。

--trace-children=yes および --track-origins=yes を指定して valgrind を実行すると、「Syscall param execve(argv) points to uninitialized byte(s)」が表示されます (以下の完全なエラーを参照)。

関連するメソッド(以下の makeargs を参照) では、valgrind は、この行で「ヒープ割り当てによって初期化されていない値が作成されました」と伝えています。

「ls | sort」valgrind のテスト入力を使用すると、「サイズ 12 のブロックが割り当てられた」と表示されます。ls と sort はそれぞれ makeargs を呼び出し、char* には 4 バイト、最後に execvp が必要とする (char*)NULL には 4 バイトが必要なため、両方とも 8 バイトを割り当てる必要があるため、これがどのように可能かわかりません。引数配列の。

このコマンドを実行すると、プログラムがハングします。

makeargs への呼び出しが 1 つしかない (パイプがない) 場合に機能するため、なぜこれが起こっているのかわかりません。任意の入力をいただければ幸いです。

void execCommand(char** commandParts, int pipeCount)
{
  const int PIPE_READ = 0;
  const int PIPE_WRITE = 1;
  int numCommands = pipeCount + 1;
  int newfds[2];
  int oldfds[2];

  int k = 0;
  for(k; k < numCommands; k++)
  {

    //more commands exist
    if(k < pipeCount)
    {
      if (pipe(newfds) == -1) 
      {
        perror("new pipe error");
        exit(EXIT_FAILURE);
      }
    }

    if(fork() == 0) //child
    {
      //is prev command
      if(k > 0)
      {
        dup2(oldfds[PIPE_READ], STDIN_FILENO);
        close(oldfds[PIPE_READ]);
        close(oldfds[PIPE_WRITE]);
      }

      //more commands exist
      if(k < pipeCount)
      {
        close(newfds[PIPE_READ]);
        dup2(newfds[PIPE_WRITE], STDOUT_FILENO);
        close(newfds[PIPE_WRITE]);
      }
      char** args = NULL;
      int argcount = makeargs(commandParts[k], &args);

      if(execvp(args[0], args) == -1)
      {
        printf("%s: command not found \n", args[0]);
      }
    }
    else //parent
    {
      int status;
      waitpid(-1, &status, NULL);

      //is prev command
      if(k > 0)
      {
        close(oldfds[PIPE_READ]);
        close(oldfds[PIPE_WRITE]);
      }
      //more commands exist
      if(k < pipeCount)
      {
        oldfds[PIPE_READ] = newfds[PIPE_READ];
        oldfds[PIPE_WRITE] = newfds[PIPE_WRITE];
      }
    }
    //there are pipes
    if(pipeCount > 0 && k > 0)
    {
      close(newfds[PIPE_READ]);
      close(newfds[PIPE_WRITE]);
    } 
    //   if(argcount > 0)
    //    cleanArgs(argcount, args);   
  }
}

呼び出される make args メソッド

int makeargs(char *s, char *** argv)
{
  stripLeadingAndTrailingSpaces(s);
  int k =0, count = 0;
  for(k; k < strlen(s); k++)
  {
    if(s[k] == ' ')
    count++;
  }
  count++;

  char* parts = strtok (s," ");
  strip(parts);

  *argv = (char **)malloc((count+1) * sizeof(char*));

  (*argv)[0] = (char *)malloc(strlen(parts)+1);
  strcpy((*argv)[0], parts);

  int i = 1;
  for(i; i < count; i++)
  {
    parts = strtok (NULL, " ");
    if(parts != NULL)
    {
      strip(parts);
      (*argv)[i] = (char *)malloc(strlen(parts)+1);
      strcpy((*argv)[i], parts);
    }
  }
  (*argv)[count] = NULL;

  return count;
}

valgrind 出力

==3603== Syscall param execve(argv) points to uninitialised byte(s)
==3603==    at 0x40E2CDF: execve (execve.c:60)
==3603==    by 0x40E314E: execvp (execvp.c:30)
==3603==    by 0x8049069: main (cscd340_s12_hw2.c:250)
==3603==  Address 0x41c617c is 4 bytes inside a block of size 12 alloc'd
==3603==    at 0x4028876: malloc (vg_replace_malloc.c:236)
==3603==    by 0x8049416: makeargs (ush.c:100)
==3603==    by 0x8048E61: execCommand (cscd340_s12_hw2.c:191)
==3603==    by 0x8049069: main (cscd340_s12_hw2.c:250)
==3603==  Uninitialised value was created by a heap allocation
==3603==    at 0x4028876: malloc (vg_replace_malloc.c:236)
==3603==    by 0x8049416: makeargs (ush.c:100)
==3603==    by 0x8048E61: execCommand (cscd340_s12_hw2.c:191)
==3603==    by 0x8049069: main (cscd340_s12_hw2.c:250)
4

2 に答える 2

0

countコマンドラインの単語数ではなく、スペースの数です。これは、コピーするコードに影響します:

for(i; i < count; i++)
{
  parts = strtok (NULL, " ");
  if(parts != NULL)
  {
    ...
  }
}

入力コマンドラインの単語が少なすぎる場合、いくつかの末尾のエントリが初期化されargvません。あなたはおそらく次のようなことをしたいと思うでしょう:

for(i; i <= count; i++)
{
  parts = strtok (NULL, " ");
  if(parts != NULL)
  {
    ... // consider using strdup
  }
  else
  {
    (*argv)[i] = NULL;
    break;
  }
}
于 2012-04-22T16:49:05.373 に答える
0

最後に、stripLeadingAndTrailingSpaces; まで問題を追跡しました。

私が持っていた

void stripLeadingAndTrailingSpaces(char temp[]) 
{
   int len = strlen(temp), start = 0;  
   while(isspace(temp[len]))
   {
      len--;
   }
   while(isspace(temp[start]))
   {
      start++;
   }  
   memmove(temp, temp + start, len);
}

しかし必要

void stripLeadingAndTrailingSpaces(char temp[]) 
{
   int len = strlen(temp)+1, start = 0;  
   while(isspace(temp[len-2]))
   {
      temp[len-2] = '\0';
      len--;
   }
   while(isspace(temp[start]))
   {
      start++;
      len--;
   }  
   memmove(temp, temp + start, len);
}

古いストリップ方式にはいくつかの問題がありました。

  1. 最後にスペースがあるかどうかを確認するために「/0」をチェックしていました。
  2. 新しい終端に新しいヌル ターミネータを適用していませんでした。
  3. 前のスペースをカットするとき、長さを短くしていませんでした。
于 2012-04-22T17:53:30.897 に答える