M1平台C++调用remotezip下载文件触发段错误问题求助
M1平台C++调用remotezip下载文件段错误修复
问题背景
- 代码适配目标:从.plist文件提取待下载文件路径,调用Python工具remotezip完成下载,剥离路径前缀后保存到指定目标文件夹
- 故障表现:下载zip包非根目录的bss文件时触发段错误,zip根目录下的Manifest.plist下载正常,正常运行的代码片段如下:
system((std::string("remotezip ") + zip.link + " " + "Manifest.plist ").c_str()); - 已知工具特性:remotezip仅支持传入完整路径(调用示例:
remotezip google.com /files/random/bss),调用时会自动创建路径对应的层级目录
故障代码
std::string BSS(std::string board){ //Working Path for Download chdir((std::string("WorkD_") + identifier + "_" + version).c_str()); std::ifstream Manifest("Manifest.plist"); while(getline(Manifest, bss.path)) { //Select the one matching with Board input. if(bss.path.find(board) != std::string::npos) { for(int i = 0; i < 4000 && getline(Manifest, bss.path); i++) { if(bss.path.find("BSS.")!= std::string::npos) { Manifest.close(); bss.path.erase(0, 14); for(int y = 0; y < bss.path.size(); y++) { if(bss.path[y] == '<') { bss.path.erase(y); //Remote zip work only if the path is complete like remotezip google.com /files/random/bss and it will also mkdir files and random..I believe this is the problem. system((std::string("remotezip") + zip.link + " " + bss.path).c_str()); bss.path.erase(0, 13); bss.name = bss.path; } } } } } } return bss.name; }
根因定位
- 命令拼接错误直接触发崩溃:下载Manifest时
"remotezip "尾部带空格,拼接bss路径时写为std::string("remotezip") + zip.link,remotezip和服务器链接之间无空格,最终生成的是非法shell命令。M1(ARM64)平台对非法指令的内存访问校验远严于x86平台,system执行非法命令时的内存越界会直接触发段错误,x86平台下可能因内存布局侥幸不崩溃。 - 文件流操作触发未定义行为:在getline遍历循环内部直接调用
Manifest.close(),但外层while、内层for的循环条件仍会对已关闭的文件流执行getline操作,属于C++标准明确的未定义行为,在ARM架构上极易触发崩溃。 - 硬编码路径偏移存在越界风险:代码固定执行
erase(0,14)、erase(0,13)截取路径,若读取到的字符串长度小于硬编码偏移值,会直接触发std::out_of_range异常,无异常捕获时进程直接终止。 - 系统调用无校验放大故障范围:chdir、文件打开、system调用均未做返回值校验,若目录不存在、权限不足、命令执行失败,后续逻辑会在非法状态下继续运行,触发随机崩溃。另外使用相对路径调用chdir,remotezip自动创建子目录后,后续函数调用的相对路径会失效,直接找不到Manifest.plist文件。
修复方案
- 修正命令拼接逻辑,所有参数间保留空格,建议先将完整命令存入临时变量,方便排查
- 调整文件流操作逻辑:找到目标路径后先跳出所有读循环,再关闭文件流,禁止在循环遍历过程中关闭正在读取的流
- 移除所有硬编码的字符串偏移,通过字符串查找定位截取位置,截取前先校验查找结果合法性,避免字符串越界
- 所有系统调用增加返回值校验,出错直接返回,避免在非法状态下执行后续逻辑;工作目录建议使用绝对路径,避免chdir相对路径导致的路径错乱
- M1平台适配补充:调用remotezip时建议写工具的绝对路径,避免M1默认shell的PATH环境变量与x86 Rosetta环境差异导致找不到命令
修复后参考代码
std::string BSS(std::string board){ // 建议替换为绝对路径拼接工作目录,避免相对路径chdir异常 std::string work_dir = "WorkD_" + identifier + "_" + version; if (chdir(work_dir.c_str()) != 0) { return ""; } std::ifstream Manifest("Manifest.plist"); if (!Manifest.is_open()) { return ""; } std::string line; std::string target_full_path; bool board_matched = false; const std::string path_prefix = "<string>"; // 对应plist标签前缀,替换原硬编码的14位偏移 const size_t prefix_len = path_prefix.size(); while (getline(Manifest, line)) { if (!board_matched) { if (line.find(board) != std::string::npos) { board_matched = true; } continue; } size_t bss_pos = line.find("BSS."); if (bss_pos != std::string::npos) { // 定位路径起始位置 size_t path_start = line.find(path_prefix); if (path_start == std::string::npos) break; path_start += prefix_len; // 定位XML标签结束位置 size_t path_end = line.find('<', path_start); if (path_end == std::string::npos) break; target_full_path = line.substr(path_start, path_end - path_start); break; } } Manifest.close(); if (target_full_path.empty()) { return ""; } // 补全命令参数间的空格,修正原拼接错误 std::string download_cmd = "remotezip " + zip.link + " " + target_full_path; int cmd_ret = system(download_cmd.c_str()); if (cmd_ret != 0) { return ""; } // 按最后一个路径分隔符截取文件名,替换原硬编码的13位偏移 size_t last_slash_pos = target_full_path.rfind('/'); std::string bss_name = (last_slash_pos == std::string::npos) ? target_full_path : target_full_path.substr(last_slash_pos + 1); return bss_name; }
内容的提问来源于stack exchange,提问作者Gen
相关产品推荐
相关产品推荐

