【发布时间】: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