You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复自制命令解释器中execvp()调用失败与栈粉碎问题

命令解释器代码问题修复方案

问题根因

两个问题相互独立,根因分别如下:

1. 栈粉碎(stack smashing)触发原因

main函数中输入处理逻辑存在栈越界写:

  • 定义的input_cmd数组长度为50,合法下标范围是0~49,但原代码直接取len = sizeof(input_cmd)得到值50后执行input_cmd[len] = '\0',等价于向数组外的栈空间写入数据,直接触发栈保护机制的崩溃检测。
  • 额外问题:没有使用read系统调用的返回值,无法正确处理实际读取的输入长度,也无法正确替换末尾的换行符。

2. execvp执行失败原因

parsecmd函数的空白字符跳过逻辑完全写反:

  • 原代码第一个循环条件while(*line != ' ' || *line == '\t' || *line == '\n')的执行逻辑是:只要当前字符不是空格、或者是制表符/换行符,就将当前字符替换为\0并后移指针。这会直接把输入的命令字符串第一个字符就替换成\0,最终解析出的argv[0]是空字符串,execvp找不到对应可执行文件自然返回失败。

修复方案

需修改的核心代码片段

  1. 修复main函数的输入处理逻辑:
// 替换原main函数中read相关的代码段
ssize_t read_len;
write(1, "OS420>", 6);
read_len = read(0, input_cmd, sizeof(input_cmd) - 1); // 预留1字节存结束符
if (read_len <= 0) break;
// 替换末尾换行符为结束符
if (input_cmd[read_len - 1] == '\n') {
    input_cmd[read_len - 1] = '\0';
}
// 移除原错误的len赋值和input_cmd[len] = '\0'逻辑
  1. 修复parsecmd函数的循环条件:
// 替换parsecmd中第一个while循环的逻辑
while(*line == ' ' || *line == '\t' || *line == '\n')
    line++; // 不需要写\0,直接跳过空白字符即可

完整修复后代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <errno.h>

#define MAX_ARGS 20

void parsecmd(char *line, char **argv) {
    while(*line != '\0') {
        // 修复:跳过所有空白字符
        while(*line == ' ' || *line == '\t' || *line == '\n')
            line++;
        if (*line == '\0') break; // 到末尾直接退出
        *argv++ = line;
        // 跳过当前参数的所有非空白字符
        while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') 
            line++;
        if (*line != '\0') {
            *line = '\0';
            line++;
        }
    }
    *argv = NULL; // 标准argv要求末尾为NULL指针
}

int runcmd(char *cmd) {
    char* argv[MAX_ARGS];
    pid_t child_pid;
    int child_status;

    parsecmd(cmd, argv);
    child_pid = fork();
    if (child_pid == 0) {
        execvp(argv[0], argv);
        write(1, "UnknownCommand\n", 15);
        _exit(0);
    }
    else {
        wait(&child_status);
        return child_status;
    }
}

int main() {
    char input_cmd[50];
    ssize_t read_len;
    
    while(1) {
        write(1, "OS420>", 6);
        read_len = read(0, input_cmd, sizeof(input_cmd) - 1);
        if (read_len <= 0) break;
        if (input_cmd[read_len - 1] == '\n') {
            input_cmd[read_len - 1] = '\0';
        }
        if (strcmp(input_cmd, "exit") == 0) {
            exit(0);
        }
        printf("Input Function -> %s\n", input_cmd);
        runcmd(input_cmd);
    }
    return 0;
}

内容的提问来源于stack exchange,提问作者LTM1815

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 04:27:01