Rcpp读取二进制文件异常:数据读取错误致崩溃求助
核心问题分析
你的代码存在几处关键错误,导致内存越界和非法内存访问,最终引发RStudio崩溃:
内存分配错误
代码中malloc(sizeof(char*)*sizeOfFile)是致命错误:sizeof(char*)是指针的大小(通常4/8字节),而非单个char的大小。你需要分配sizeOfFile个1字节的char空间,应改为malloc(sizeOfFile)(因sizeof(char)固定为1)。错误的分配会导致内存区域超出预期,引发后续操作崩溃。文件大小类型溢出风险
ftell()返回long类型,用int存储会在文件超过2GB时溢出,应改为long sizeOfFile = ftell(file);,后续相关变量类型同步调整。fread参数与错误检查缺失
fread(fileData, sizeOfFile, 1, file)虽能读取数据,但无法准确判断是否完整读取文件。建议改为fread(fileData, 1, sizeOfFile, file),同时检查返回值是否等于文件大小,确保读取完整:size_t bytesRead = fread(fileData, 1, sizeOfFile, file); if (bytesRead != static_cast<size_t>(sizeOfFile)) { free(fileData); fclose(file); Rcpp::stop("Failed to read entire file"); }memcpy目标地址错误
构造函数中memcpy(¶ms, arrayPointer, 28)错误:params是数组名,本身已指向数组首元素,¶ms是指向整个数组的指针,会将数据写入错误内存区域。应改为memcpy(params, arrayPointer, 28)。冗余的类型转换
*(uint8_t*)&arrayPointer[0]完全冗余,arrayPointer[0]本身是char类型,直接转为uint8_t即可:static_cast<uint8_t>(arrayPointer[0])。
修正后的代码片段
修正后的readFile函数
inline void readFile(string filePath){ FILE* file = fopen(filePath.c_str(), "rb"); if (file == NULL){Rcpp::stop("Cannot open file");} // 用long存储文件大小,避免溢出 fseek(file, 0, SEEK_END); long sizeOfFile = ftell(file); if (sizeOfFile < 1){Rcpp::stop("Bad File size");} Rcpp::Rcout << "File size: " << sizeOfFile << endl; // 正确分配内存并检查分配结果 fileData = static_cast<char*>(malloc(sizeOfFile)); if (fileData == NULL) { fclose(file); Rcpp::stop("Failed to allocate memory"); } rewind(file); // 修正fread参数并验证读取完整性 size_t bytesRead = fread(fileData, 1, sizeOfFile, file); if (bytesRead != static_cast<size_t>(sizeOfFile)) { free(fileData); fclose(file); Rcpp::stop("Failed to read entire file"); } fclose(file); arrayPointer = fileData; end = fileData + sizeOfFile; if(arrayPointer == NULL){Rcpp::stop("arrayPointer is null");} // 简化第一个字节的打印 Rcpp::Rcout << "First byte: " << static_cast<uint8_t>(arrayPointer[0]) << endl; }
修正后的构造函数
const_array_iterator(string filePath) { readFile(filePath); uint32_t params[7]; // 修正memcpy目标地址 memcpy(params, arrayPointer, 28); arrayPointer += 32; Rcpp::Rcout << "Copied params" << endl; magicByteSize = params[0]; rowType = params[1]; nRows = params[2]; colType = params[3]; nCols = params[4]; valueWidth = params[5]; oldIndexType = params[6]; memcpy(&value, arrayPointer, valueWidth); arrayPointer += valueWidth; memcpy(&newIndexWidth, arrayPointer, 1); arrayPointer++; }
内容的提问来源于stack exchange,提问作者Seth Wolfgang

