You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Avro C++创建GenericDatum时触发段错误问题

Apache Avro C++ 创建GenericDatum在C17/20下触发段错误,C14正常

在使用Apache Avro C库创建GenericDatum实例时,遇到版本相关的段错误问题:C14编译环境下运行正常,但切换到C17或C20时,创建GenericDatum的代码会直接触发段错误。

复现代码

avro_read.cc

#include <fstream>
#include <avro/GenericDatum.hh>
#include <avro/ValidSchema.hh>
#include <avro/Compiler.hh>

int main(int argc, char* argv[]) {
  // 读取并编译schema
  std::ifstream in("schema.avsc");
  avro::ValidSchema valid_schema;
  avro::compileJsonSchema(in, valid_schema);

  // 创建通用数据(触发段错误)
  avro::GenericDatum datum(valid_schema); 
  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.20)

project(repro CXX)

find_package(unofficial-avro-cpp CONFIG REQUIRED)

add_executable(avro_read avro_read.cc)
target_link_libraries(avro_read PRIVATE unofficial::avro-cpp::avrocpp)

vcpkg.json

{
  "name": "segfault-repro",
  "version-string": "unversioned",
  "description": "A simple repro for the avro GenericDatum segfault",
  "dependencies": [
    "avro-cpp"
  ]
}

schema.avsc

{
    "type": "record",
    "name": "__root__",
    "fields": [
        {
            "name": "name",
            "type": [
                "null",
                "string"
            ]
        },
        {
            "name": "total",
            "type": [
                "null",
                "long"
            ]
        }
    ]
}

编译与运行命令

cmake -S . -B .build -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build .build
.build/avro_read 

调试信息

GDB输出

Program received signal SIGSEGV, Segmentation fault.
0x00005555555ecd70 in ?? ()
(gdb) bt
#0  0x00005555555ecd70 in ?? ()
#1  0x000055555556b46d in main ()

Valgrind输出

==2398834== Memcheck, a memory error detector
==2398834== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==2398834== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==2398834== Command: .build/avro_read
==2398834== 
vex amd64->IR: unhandled instruction bytes: 0xF1 0x60 0x3E 0x0 0x0 0x0 0x0 0x0 0x10 0x7F
vex amd64->IR:   REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR:   VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE
vex amd64->IR:   PFX.66=0 PFX.F2=0 PFX.F3=0
==2398834== Invalid read of size 1
==2398834==    at 0x4DC7EC0: ???
==2398834==    by 0x4DC60DF: ???
==2398834==    by 0x7: ???
==2398834==  Address 0x1b is not stack'd, malloc'd or (recently) free'd
==2398834== 
==2398834== 
==2398834== Process terminating with default action of signal 11 (SIGSEGV)
==2398834==  Access not within mapped region at address 0x1B
==2398834==    at 0x4DC7EC0: ???
==2398834==    by 0x4DC60DF: ???
==2398834==    by 0x7: ???
==2398834==  If you believe this happened as a result of a stack
==2398834==  overflow in your program's main thread (unlikely but
==2398834==  possible), you can try to increase the size of the
==2398834==  main thread stack using the --main-stacksize= flag.
==2398834==  The main thread stack size used in this run was 8388608.
==2398834== 
==2398834== HEAP SUMMARY:
==2398834==     in use at exit: 84,688 bytes in 40 blocks
==2398834==   total heap usage: 123 allocs, 83 frees, 97,888 bytes allocated
==2398834== 
==2398834== LEAK SUMMARY:
==2398834==    definitely lost: 0 bytes in 0 blocks
==2398834==    indirectly lost: 0 bytes in 0 blocks
==2398834==      possibly lost: 0 bytes in 0 blocks
==2398834==    still reachable: 84,688 bytes in 40 blocks
==2398834==         suppressed: 0 bytes in 0 blocks
==2398834== Reachable blocks (those to which a pointer was found) are not shown.
==2398834== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==2398834== 
==2398834== For lists of detected and suppressed errors, rerun with: -s
==2398834== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)
[1]    2398834 segmentation fault  valgrind --leak-check=full .build/avro_read

问题根源分析

Avro C的GenericDatum.hh头文件会根据C版本自动选择使用std::any(C17及以上)或boost::any(C14及以下):

#if __cplusplus >= 201703L
#include <any>
#else
#include "boost/any.hpp"
#endif

测试发现,当强制指定C14编译时(添加set(CMAKE_CXX_STANDARD 14)到CMakeLists.txt),程序运行正常;切换到C17或C++20则触发段错误。推测问题出在Avro对std::any的处理逻辑上:

  • 当处理包含可空类型(联合类型,如["null", "string"])的schema时,GenericDatum初始化过程中可能错误地对空的std::any执行std::any_cast,而std::any在未持有值的状态下执行any_cast会直接触发未定义行为(如段错误)。
  • boost::any对空值的处理更宽松,不会立即触发段错误,因此C++14环境下表现正常。

解决方案

  1. 临时规避方案:强制使用C++14编译,在CMakeLists.txt中添加:
set(CMAKE_CXX_STANDARD 14)
  1. 修复库代码:修改Avro C++的GenericDatum初始化逻辑,确保处理联合类型时:

    • 正确初始化std::any为联合类型的默认值(如null)
    • 在执行any_cast前检查std::any是否持有有效值(通过std::any::has_value()判断)
  2. 升级库版本:检查是否使用了最新版的Avro C++,如果不是,尝试升级到最新版本,确认该问题是否已被官方修复。

内容的提问来源于stack exchange,提问作者alevenberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:07:33