shell实现分段故障的历史

时间:2017-01-15 15:04:23

标签: c linux shell singly-linked-list

所以我写了一些代码来实现shell(Linux,GCC,C语言),这一切都有效,但是由于某种原因,当我添加history选项时代码崩溃了: 它真的没有(其他代码)所以我只会把你需要的东西放在这里。

问题是当我在一个需要保存在历史记录中的旧命令之后键入quit时,当我键入退出时,它只会破坏分段错误(核心转储)。

历史记录保存在链表,命令串和下一个节点的节点的结构中,我也将头部保存在主页中。关键是我只想保存最后15个命令,而且我不关心其他命令,因此每次我想要打印列表时,我只是移动了循环中的前15个节点。

当我使用GDB调试时,我发现代码崩溃的行是他将第一个命令添加到历史记录后的行,但当前行与历史记录无关:
主:

int main()
{
    history_ll* top;
    char userInput [CHOICE_LENGTH];
    char buff[PATH_MAX];
    int flag=1;
    cmdLine * head; 
    while (flag)
    {
        getcwd(buff, PATH_MAX); 
        printf("%s:~$ ",buff);
        fgets(userInput,MAX_INPUT, stdin);
        userInput[strlen(userInput)-1]=0;
        historyAdder(userInput,&top);
        if(strcmp(userInput,QUIT_OPTION)==0)    //segmentation fault here!
        {
            flag=0;
        }
        else
        {
            //doesn't matter
        }

    }
    return 0;
}

historyAdder看起来像这样:

void historyAdder(const char *command,history_ll** top)
{
    history_ll* node;
    strcpy(node->command,command);
    node->command[strlen(command)]=0;
    if(historyLength!=0)
    {
        node->next= *top;
    }
    else
    {
        node->next= NULL;
    }
    *top = node;
    historyLength++;
}

注意:historyLength是一个全局变量

这是结构:

typedef struct history_ll{
    char command[CHOICE_LENGTH];
    struct history_ll *next;
}history_ll; 

谢谢助手!

3 个答案:

答案 0 :(得分:1)

此代码中至少存在两个重要问题。 一个是从stdin读取时缓冲区长度可能太短: 定义:

char userInput [CHOICE_LENGTH];

但用法是:

fgets(userInput,MAX_INPUT, stdin);

您应该使用相同的缓冲区大小或断言MAX_INPUT小于或等于CHOICE_LENGTH

其次,通过在此处取消引用未初始化的指针来触发未定义的行为:

void historyAdder(const char *command,history_ll** top)
{
    history_ll* node;
    strcpy(node->command,command);  /* bad... */

答案 1 :(得分:0)

这里(及以下几行)

void historyAdder(const char *command,history_ll** top)
{
  history_ll* node;
  strcpy(node->command,command);
  ...

代码取消引用未初始化的指针:node这样做会调用UB,并且很可能会使程序崩溃。

答案 2 :(得分:0)

这可能是 你的问题:

 grep -R '^DocumentRoot' /etc/httpd/ 2>/dev/null ; grep -R '^DocumentRoot' /etc/apache2/ 2>/dev/null 

除非char userInput [CHOICE_LENGTH]; ... fgets(userInput,MAX_INPUT, stdin); 大于或等于CHOICE_LENGTH,否则MAX_INPUT可以写入fgets数组的末尾,这会破坏内存,从而导致崩溃。但是,由于您没有显示我可以为自己编译并观看崩溃的完整程序,我无法确定。

给你两条建议:

  • 你在Linux上,所以你有getline。使用它代替userInput,您不必担心输入缓冲区大小。

  • 每当您的程序崩溃时出现细分错误,您首先要做的就是valgrind。很多时候,valgrind会发现真正的错误远不是你想象的那样。