【问题标题】:Segmentation fault - splitting command into tokens分段错误 - 将命令拆分为令牌
【发布时间】:2016-11-07 19:24:41
【问题描述】:

我正在实现的代码中,我先用管道然后用空格分割命令。

int main(){
pid_t pid;
while (1) {
printf("$ ");
char *cmd;
ssize_t size=0;
getline(&cmd,&size,stdin);
if (cmd[strlen(cmd)-1]== '\n') {cmd[strlen(cmd)-1]='\0';}
char** commands = splitter(cmd,"|");
int i=0;
int fd[2],in=0;
while (commands[i+1]!=NULL){
 pipe(fd);
 char **args = splitter(commands[i]," \t");
  pid = fork();
  if (pid==-1) {exit(EXIT_FAILURE);}
  else if (pid==0){
   close(fd[0]);
   changeIO(in,0);
   changeIO(fd[1],1);
   execvp(args[0],args);
  }
  else{
   waitpid(pid,NULL,0);
   close(fd[1]);
   close(in);
   in = fd[0];
  }
 i++;
}
char **args = splitter(commands[i+1]," \t");
changeIO(in,0);
execvp(args[0],args);
}
}

下面是上面代码使用的函数的实现

void changeIO(int oldfd,int newfd){  
 if (oldfd!=newfd){  
  dup2(oldfd,newfd);  
  close(oldfd);  
 }  
}  


char** splitter(char* stringToSplit, char* delimiter){  
  char *token;  
  int initial_size = 300;  
  char** args = malloc(initial_size*sizeof(char*));   
  token = strtok(stringToSplit,delimiter);  
  int index = 0;  
  while (token != NULL) {  
    args[index] = token;  
    index++;  
    if (index >= initial_size) {  
      initial_size = initial_size + 100;  
      args = realloc(args,initial_size*sizeof(char*));  
      if (!args) exit(EXIT_FAILURE);  
    }  
    token = strtok(NULL,delimiter);  
   }  
   args[index] = NULL;  
   return args;  
}  

好的,执行代码当我在用户输入中输入命令时出现分段错误。测试各种选项我开始意识到它与char** args 有关,我在其中传递了每个命令的令牌。我不明白为什么会发生这种情况,因为分配了内存,据我所知,我只是将指针 args 指向该分配的内存。任何帮助表示赞赏。

编辑:用 valgrind 检查。结果如下:

==3361== Memcheck, a memory error detector  
==3361== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.  
==3361== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info  
==3361== Command: ./mysh3  
==3361==   
==3361== Conditional jump or move depends on uninitialised value(s)  
==3361==    at 0x40AFE97: getdelim (iogetdelim.c:59)  
==3361==    by 0x40ACDD1: getline (getline.c:32)  
==3361==    by 0x80486C4: main (in /home/dimitris/Desktop/mysh3)  
==3361==   
$ ls  
==3361== Invalid read of size 1   
==3361==    at 0x4101CAA: execvpe (execvpe.c:50)  
==3361==    by 0x4101B33: execvp (execvp.c:26)  
==3361==    by 0x804885F: main (in /home/dimitris/Desktop/mysh3)  
==3361==  Address 0x0 is not stack'd, malloc'd or (recently) free'd  
==3361==   
==3361==   
==3361== Process terminating with default action of signal 11 (SIGSEGV)  
==3361==  Access not within mapped region at address 0x0  
==3361==    at 0x4101CAA: execvpe (execvpe.c:50)  
==3361==    by 0x4101B33: execvp (execvp.c:26)  
==3361==    by 0x804885F: main (in /home/dimitris/Desktop/mysh3)  
==3361==  If you believe this happened as a result of a stack  
==3361==  overflow in your program's main thread (unlikely but  
==3361==  possible), you can try to increase the size of the  
==3361==  main thread stack using the --main-stacksize= flag.  
==3361==  The main thread stack size used in this run was 8388608.  
==3361==   
==3361== HEAP SUMMARY:  
==3361==     in use at exit: 2,520 bytes in 3 blocks  
==3361==   total heap usage: 5 allocs, 2 frees, 4,568 bytes allocated  
==3361==   
==3361== LEAK SUMMARY:  
==3361==    definitely lost: 0 bytes in 0 blocks  
==3361==    indirectly lost: 0 bytes in 0 blocks  
==3361==      possibly lost: 0 bytes in 0 blocks  
==3361==    still reachable: 2,520 bytes in 3 blocks  
==3361==         suppressed: 0 bytes in 0 blocks  
==3361== Rerun with --leak-check=full to see details of leaked memory  
==3361==   
==3361== For counts of detected and suppressed errors, rerun with: -v  
==3361== Use --track-origins=yes to see where uninitialised values come from  
==3361== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)  
Segmentation fault  

【问题讨论】:

  • 你用过调试器吗?如果您希望我们提供帮助,请提供minimal reproducible example。我们无法调试不完整的代码。比如cmd是什么?
  • 可能是未初始化的 fd[2] 数组。这也可能是 cmd 变量本身的问题,我看不到它是如何初始化的。对于这样的错误,我喜欢valgrind.org,以防你在 Linux 上。但是我同意@kaylum 调试器信息对于理解您的问题非常有帮助:)
  • @JacobusConradi 我将使用 valgrind 对其进行测试并更新我的帖子。谢谢。
  • @JacobusConradi 发布更新结果
  • char *cmd;。您需要将cmd 初始化为NULL。因为getline 依赖于此。否则cmd 可能包含一个垃圾非NULL 值,这意味着getline 不会为您分配内存并将写入无效内存,从而导致段错误(或其他未定义行为)

标签: c shell segmentation-fault pipe tokenize


【解决方案1】:

这是一个非一数组索引。

您的 while 循环以 commands[i+1] 为空结束。然后你将它传递给splitter

改为传递commands[i]

【讨论】:

    【解决方案2】:

    当 strtok() 找到一个记号时,它会将记号后面的字符立即更改为 \0,然后返回一个指向该记号的指针。

    【讨论】:

    • 找到this 样本。他使用它几乎完全相同
    • 然后??最好不要对您的答案含糊其辞,并更明确地解释它与 OP 代码的关系。
    • 我在继续使用代码之前通过管道标记化时测试了 splitter(),并且标记已正确完成,没有分段错误,当我按照与第二部分完全相同的方法时,我得到了这个错误。编辑:拆分器代码是 100% 我的,与上面提到的链接无关
    猜你喜欢
    • 1970-01-01
    • 2020-11-19
    • 2014-12-06
    • 2012-10-09
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    相关资源
    最近更新 更多