如何修复自制命令解释器中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找不到对应可执行文件自然返回失败。
修复方案
需修改的核心代码片段
- 修复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'逻辑
- 修复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
相关产品推荐
相关产品推荐

