Prhub

#23136 Fix segfault in cudaMemcpyBatchAsync on CUDA 13.0

原始 PR 作者 yhyang201 合并时间 2026-04-21 03:20 文件变更 1 提交数 8 评论 9 代码增减 +48 / -17

执行摘要

修复 CUDA 13.0 下 cudaMemcpyBatchAsync 参数错位导致的段错误。

根据 PR body,CUDA 13.0 移除了 cudaMemcpyBatchAsync 的 failIdx 参数,导致使用 CUDA 12.8 签名调用时,stream 参数错位,引发段错误。修复目标是识别根本原因并提供工作修复,确保跨 CUDA 版本的兼容性。

建议精读此 PR,特别是运行时版本检测和 CUDA API 兼容性处理的实现方式,这对于涉及低级别 CUDA 编程的项目有借鉴意义。

讨论亮点
  • 编译时宏问题:gemini-code-assist[bot] 指出使用 #if CUDA_VERSION 宏会导致二进制不兼容,应改为运行时检测。
  • 内存安全漏洞:同一 bot 指出 attrs_idxs 向量大小不匹配,需调整为 num_copies
  • 运行时符号识别:Kangyan-Zhou 强调 cudaMemcpyBatchAsync 是运行时符号,应使用 cudaRuntimeGetVersion 而非驱动版本检测。
  • 开发者响应:yhyang201 及时修复了这些问题。

实现拆解

  1. 入口点修改:在 sgl-kernel/csrc/kvcacheio/transfer.cutransfer_kv_page_first_direct_impl 函数中,添加运行时版本检测逻辑。
  2. 版本检测:使用 cudaRuntimeGetVersion 获取 CUDA 运行时版本,并缓存结果以避免每次调用重复查询。
  3. 条件分支:根据版本号选择调用 cudaMemcpyBatchAsync 的正确签名(CUDA 13.0 使用 8 参数,CUDA 12.8 使用 9 参数)。
  4. 内存安全修复:调整 attrs_idxs 向量大小以匹配 num_copies,防止数组越界访问。
  5. 回退机制:在 API 不支持或出错时,回退到 fallback_to_page_copy 方法。
文件 模块 状态 重要度
sgl-kernel/csrc/kvcacheio/transfer.cu 内核传输 modified 5.44

关键符号

transfer_kv_page_first_direct_impl

关键源码片段

sgl-kernel/csrc/kvcacheio/transfer.cu core-logic

这是唯一修改的文件,包含了修复 cudaMemcpyBatchAsync 调用段错误的核心逻辑。

inline void transfer_kv_page_first_direct_impl(...) {
    // ... 省略其他代码 ...    // Symbol gate: runtime may not expose cudaMemcpyBatchAsync in some environments.
    static void* cuda_memcpy_batch_async_sym = dlsym(RTLD_DEFAULT, "cudaMemcpyBatchAsync");
    if (cuda_memcpy_batch_async_sym == nullptr) {
        fallback_to_page_copy();
        return;
    }    // 使用 cudaRuntimeGetVersion 检测运行时版本,并缓存结果以避免热路径性能开销
    static int runtime_version = 0;
    static cudaError_t runtime_version_err = cudaRuntimeGetVersion(&runtime_version);
    if (runtime_version_err != cudaSuccess) {
        fallback_to_page_copy();
        return;
    }
    static const bool use_v13_signature = runtime_version >= 13000; // CUDA 13.0 及以上使用新签名    // 构建批量复制参数
    size_t num_copies = 0;
    std::vector<void*> batch_srcs;
    std::vector<void*> batch_dsts;
    std::vector<size_t> batch_sizes;
    // ... 填充参数 ...    if (num_copies > 0) {
        // 调整 attrs_idxs 向量大小以匹配 num_copies,防止数组越界
        std::vector<size_t> attrs_idxs(num_copies, 0);
        cudaError_t err;
        if (use_v13_signature) {
            // CUDA 13.0 签名:8 个参数,无 failIdx
            using FnV13 = cudaError_t (*)(void* const*, const void* const*, const size_t*, size_t, cudaMemcpyAttributes*, size_t*, size_t, cudaStream_t);
            auto fn = reinterpret_cast<FnV13>(cuda_memcpy_batch_async_sym);
            err = fn(batch_dsts.data(), batch_srcs.data(), batch_sizes.data(), num_copies, &attrs, attrs_idxs.data(), 1, stream);
        } else {
            // CUDA 12.8 及以下签名:9 个参数,包含 failIdx
            using FnV12 = cudaError_t (*)(void**, void**, size_t*, size_t, cudaMemcpyAttributes*, size_t*, size_t, size_t*, cudaStream_t);
            auto fn = reinterpret_cast<FnV12>(cuda_memcpy_batch_async_sym);
            size_t fail_idx = std::numeric_limits<size_t>::max();
            err = fn(batch_dsts.data(), batch_srcs.data(), batch_sizes.data(), num_copies, &attrs, attrs_idxs.data(), 1, &fail_idx, stream);
        }
        if (err == cudaErrorNotSupported || err == cudaErrorCallRequiresNewerDriver) {
            fallback_to_page_copy(); // 回退到 page_copy 方法
            return;
        }
        TORCH_CHECK(err == cudaSuccess, "cudaMemcpyBatchAsync failed: ", cudaGetErrorString(err));
    }
}

评论区精华

编译时宏导致二进制不兼容 正确性

gemini-code-assist[bot] 指出使用 #if CUDA_VERSION 宏在编译时决定函数签名,会导致二进制在不同 CUDA 版本环境下不兼容,引发段错误。

结论:改为运行时版本检测,使用 cudaRuntimeGetVersion 动态选择签名。 · 已解决

attrs_idxs 向量大小不匹配 正确性

gemini-code-assist[bot] 指出 attrs_idxs 向量初始大小为 1,但 cudaMemcpyBatchAsync 期望数组大小为 num_copies,导致潜在数组越界。

结论:修复为调整向量大小以匹配 num_copies。 · 已解决

运行时版本检测的正确方法 设计

Kangyan-Zhou 强调 cudaMemcpyBatchAsync 是运行时符号,应使用 cudaRuntimeGetVersion 而非 cudaDriverGetVersion 检测版本,以避免容器环境中驱动与运行时版本不一致的问题。

结论:采纳运行时版本检测,并缓存结果优化性能。 · 已解决

风险与影响

  • 版本检测失败:如果 cudaRuntimeGetVersion 调用失败,可能导致错误签名选择,引发段错误。
  • 线程安全:虽然静态初始化在 C++11 下线程安全,但高并发环境下需确保缓存版本的一致性。
  • 兼容性风险:修复依赖于 CUDA 运行时 API,可能在旧版本或非标准环境中不工作。
  • 用户影响:修复了在 CUDA 13.0 环境下运行时的段错误,提升了系统稳定性和用户体验。
  • 系统影响:确保 KV 缓存传输功能在跨 CUDA 版本环境中正常工作,避免崩溃和数据损坏。
  • 团队影响:提供了处理 CUDA API 变化的模板,减少了未来类似兼容性问题的维护成本。
运行时依赖风险 内存安全漏洞 跨版本兼容性挑战

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论