Apache Arrow C++读取CSV示例触发Segmentation Fault求助
排查Apache Arrow C++读取CSV时的段错误问题
我来帮你分析这个段错误的问题,看代码和Core Dump信息,很快就能找到根源:
问题相关信息
环境信息
- g++版本:7.3.1
- 编译命令:
c++ -g -std=c++11 -Wall -O2 test.cpp -o test -I../../arrow/src -L../../arrow/lib -larrow -lparquet -Wl,-rpath,./
问题代码片段
arrow::Status status; arrow::MemoryPool *pool = arrow::default_memory_pool(); std::shared_ptr<arrow::io::InputStream> input; std::string csv_file = "test.csv"; auto input_readable = std::dynamic_pointer_cast<arrow::io::ReadableFile>(input); PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(csv_file, pool, &input_readable)); auto read_options = arrow::csv::ReadOptions::Defaults(); read_options.use_threads = false; read_options.column_names.emplace_back("name"); read_options.column_names.emplace_back("age"); auto parse_options = arrow::csv::ParseOptions::Defaults(); auto convert_options = arrow::csv::ConvertOptions::Defaults(); convert_options.include_missing_columns = true; std::shared_ptr<arrow::csv::TableReader> reader; status = arrow::csv::TableReader::Make(pool, input, read_options, parse_options, convert_options, &reader); if (!status.ok()) { std::cout << "make csv table error" << std::endl; return -1; } std::shared_ptr<arrow::Table> table; status = reader->Read(&table); if (!status.ok()) { std::cout << "read csv table error" << std::endl; return -1; }
Core Dump信息
Program terminated with signal 11, Segmentation fault.
#0 0x00007fe4fcda83e7 in arrow::io::internal::ReadaheadSpooler::Impl::WorkerLoop() () from ./libarrow.so.15
(gdb) bt
#0 0x00007fe4fcda83e7 in arrow::io::internal::ReadaheadSpooler::Impl::WorkerLoop() () from ./libarrow.so.15
#1 0x00007fe4fd405a2f in execute_native_thread_routine () from ./libarrow.so.15
#2 0x00007fe4fa8ecdf3 in start_thread () from /lib64/libpthread.so.0
#3 0x00007fe4fb86e1bd in clone () from /lib64/libc.so.6
CSV文件内容
name,age aaa,12 bbb,13 ccc,14 ddd,15
问题根源
你代码里的核心错误是:创建TableReader时传入的是未初始化的空指针input,而不是你实际打开的文件流input_readable。
具体来说:
- 你先初始化了一个空的
std::shared_ptr<arrow::io::InputStream> input; - 然后把这个空指针转成
input_readable,接着调用ReadableFile::Open成功打开了文件,此时input_readable指向了有效的文件句柄,但input本身还是空的 - 最后创建
TableReader时,你传入了空的input,导致Arrow内部尝试读取数据时访问了空指针,触发了段错误——哪怕你设置了use_threads = false,Arrow的预读机制还是会尝试操作这个无效的流,所以崩溃在了ReadaheadSpooler的线程逻辑里。
修复方案
调整代码逻辑,确保传入TableReader的是已经打开的有效文件流:
arrow::Status status; arrow::MemoryPool *pool = arrow::default_memory_pool(); std::string csv_file = "test.csv"; // 直接初始化ReadableFile,跳过空的InputStream初始化 std::shared_ptr<arrow::io::ReadableFile> input_readable; PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(csv_file, pool, &input_readable)); // 将ReadableFile转换为InputStream类型(TableReader需要这个接口) std::shared_ptr<arrow::io::InputStream> input = input_readable; auto read_options = arrow::csv::ReadOptions::Defaults(); read_options.use_threads = false; // 因为你的CSV已经有表头了,其实可以去掉下面两行,让Arrow自动解析列名 // read_options.column_names.emplace_back("name"); // read_options.column_names.emplace_back("age"); auto parse_options = arrow::csv::ParseOptions::Defaults(); auto convert_options = arrow::csv::ConvertOptions::Defaults(); convert_options.include_missing_columns = true; std::shared_ptr<arrow::csv::TableReader> reader; // 这里传入有效的input流 status = arrow::csv::TableReader::Make(pool, input, read_options, parse_options, convert_options, &reader); if (!status.ok()) { std::cout << "make csv table error: " << status.ToString() << std::endl; return -1; } std::shared_ptr<arrow::Table> table; status = reader->Read(&table); if (!status.ok()) { std::cout << "read csv table error: " << status.ToString() << std::endl; return -1; } // 可以加个验证,确认读取成功 std::cout << "Successfully read " << table->num_rows() << " rows" << std::endl;
额外提示
- 你的CSV文件第一行已经是列名,完全不需要手动设置
read_options.column_names,让Arrow自动解析表头会更灵活,避免硬编码列名带来的维护问题 - 建议在打印错误时加上
status.ToString(),这样能看到更具体的错误信息,方便后续排查
内容的提问来源于stack exchange,提问作者annsshadow
相关产品推荐
相关产品推荐

