使用哈希字符串搭配switch-case触发段错误的排查求助
CLI段错误问题排查与修复
我正在开发一款CLI命令行工具,目前需求尚未明确。注意:在使用字符串映射搭配switch-case执行命令后,程序开始出现段错误,但编译阶段无任何错误。运行时通过printf打印argc和argv信息后发现,错误可能在任意位置触发。
代码文件 codeycat.cpp
#include <map> #include <iostream> using namespace std; static enum Functions { undef, comm_test, comm_commands } functions; static map<string, Functions> mapStringValues; static void Initialize(); bool samestr(const char *svar, const char *str) { if (strcmp(svar, str) == 0) { return true; } else { return false; } } string construct_version(int major, int minor, int patch) { string strmajor = to_string(major); string strminor = to_string(minor); string strpatch = to_string(patch); string version = strmajor + "." + strminor + "." + strpatch; return version; } int test(string command) { int code = system(command.c_str()); return code; } void commands() { printf("(test, commands)\n"); } int main(int argc, char *argv[]) { string doc = "Usage: codeycat [options...] [function] [args...]\n" "Options:\n" "\t--help -h: Show this message and exit\n" "\t--version -v: Show version and exit\n"; string version = construct_version(1, 0, 0); printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]); if (argc < 2) { printf("%s", doc.c_str()); return 1; } const char command[PATH_MAX] = {*argv[2]}; switch (mapStringValues[command]) { case undef: printf("Command not found: %s", command); case comm_test: test(argv[3]); case comm_commands: cout << "Hello" << endl; // commands(); } return 0; } void Initialize() { mapStringValues["undef"] = undef; mapStringValues["test"] = comm_test; mapStringValues["commands"] = comm_commands; }
运行结果
执行./codeycat返回错误码1,但携带--help、--version、-h、-v等选项或执行功能时均触发段错误:
./codeycat arg count: 1, args: ./codeycat (null) COLORTERM=truecolorUsage: codeycat [options...] [function] [args...] Options: --help -h: Show this message and exit --version -v: Show version and exit
./codeycat --help [1] 12372 segmentation fault ./codeycat --help
./codeycat -h [1] 12416 segmentation fault ./codeycat -h
./codeycat --version [1] 12459 segmentation fault ./codeycat --version
./codeycat -v [1] 12501 segmentation fault ./codeycat -v
./codeycat test 'echo Hello' [1] 12544 segmentation fault ./codeycat test 'echo Hello'
./codeycat commands [1] 12587 segmentation fault ./codeycat commands
错误原因分析
- 未初始化字符串映射:
Initialize()函数从未被调用,mapStringValues是空的,访问mapStringValues[command]时会插入默认值,行为未定义,可能触发段错误。 - argv越界访问:
printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]);中,当argc < 3时,argv[1]或argv[2]为NULL,直接用printf打印NULL指针会触发段错误。 - command变量初始化错误:
const char command[PATH_MAX] = {*argv[2]};仅取了argv[2]的第一个字符,而非完整字符串,且未包含PATH_MAX的定义头文件(需包含<limits.h>或<unistd.h>),导致内存操作异常。 - switch-case无break语句:所有case分支未加
break,会贯穿执行后续分支,导致错误的函数调用。 - 选项处理逻辑缺失:未对
--help、-h等选项做判断,直接进入命令处理逻辑,导致错误访问argv[2]。 - argv[3]访问未做边界检查:调用
test(argv[3])时未检查argc >=4,越界访问会触发段错误。
修复后的代码
#include <map> #include <iostream> #include <cstring> #include <limits.h> #include <unistd.h> using namespace std; enum Functions { undef, comm_test, comm_commands }; static map<string, Functions> mapStringValues; static void Initialize() { mapStringValues["test"] = comm_test; mapStringValues["commands"] = comm_commands; } bool samestr(const char *svar, const char *str) { return strcmp(svar, str) == 0; } string construct_version(int major, int minor, int patch) { return to_string(major) + "." + to_string(minor) + "." + to_string(patch); } int test(const string& command) { return system(command.c_str()); } void commands() { printf("Available commands: (test, commands)\n"); } int main(int argc, char *argv[]) { Initialize(); // 初始化映射表 const string doc = "Usage: codeycat [options...] [function] [args...]\n" "Options:\n" "\t--help, -h: Show this message and exit\n" "\t--version, -v: Show version and exit\n"; const string version = construct_version(1, 0, 0); // 安全打印argv信息 printf("arg count: %d, args: ", argc); for (int i = 0; i < argc; ++i) { printf("%s ", argv[i]); } printf("\n"); // 处理选项 if (argc >= 2) { if (samestr(argv[1], "--help") || samestr(argv[1], "-h")) { printf("%s", doc.c_str()); return 0; } if (samestr(argv[1], "--version") || samestr(argv[1], "-v")) { printf("codeycat version %s\n", version.c_str()); return 0; } } // 检查命令参数 if (argc < 2) { printf("%s", doc.c_str()); return 1; } const string command = argv[1]; auto it = mapStringValues.find(command); if (it == mapStringValues.end()) { printf("Command not found: %s\n", command.c_str()); printf("%s", doc.c_str()); return 1; } switch (it->second) { case comm_test: if (argc >= 3) { test(argv[2]); } else { printf("Error: test command requires an argument\n"); } break; case comm_commands: commands(); break; case undef: printf("Command not found: %s\n", command.c_str()); break; } return 0; }
内容的提问来源于stack exchange,提问作者ArnabProg
相关产品推荐
相关产品推荐

