Closed
[Bug|算子缺陷]: aclnnAdaLayerNormBackward gradInputOut=nullptr 时 GetWorkspaceSize 段错误(SIGSEGV) #179
Alice_zhouAdd on  23 days agoClosed at  22 days ago
Alice_zhou
23 days ago Create

一、问题描述(必填)

  • 接口名:aclnnAdaLayerNormBackward;异常场景:gradInputOut=nullptr(NULLPTR_OUTPUT)
  • 现象:aclnnAdaLayerNormBackwardGetWorkspaceSize 在 gradInputOut(必需输出 tensor)传入 nullptr 时发生段错误(SIGSEGV,进程崩溃退出码 139),崩溃点为 aclTensor::GetDataType() 空指针解引用(libopapi_nn.so)
  • md 预期:错误码表规定入参指针为空应返回 161001(ACLNN_ERR_PARAM_NULLPTR),不应崩溃
  • 判定:是bug(CANN 版本问题:必需输出参数 nullptr 未判空导致段错误)——反向 CPP 检查通过(base 构造完全满足 md 约束,仅注入单参数 nullptr),合法输入执行崩溃

二、问题复现步骤(必填)

  1. 下载测试框架:https://gitcode.com/Alice_zhou/Vector_fuzz_cpp_testing/tree/main/turing_sec/aclnnAPI_fuzz/
  2. 环境准备(清除原有内容,将下方附件 cpp 保存为 aclnnAdaLayerNormBackward_error.cpp 放入对应目录下):
    rm -rf aclnnAPI_fuzz/src/op/*
    # 将附件 cpp(单场景 gradInputOut=nullptr 最小复现)保存为 aclnnAPI_fuzz/src/op/aclnnAdaLayerNormBackward_error.cpp
    
  3. 编译:
    cd aclnnAPI_fuzz/ ; make
    
  4. 执行(预期:进程段错误退出,exit=139;正确行为应打印 GWS ret=161001):
    cd out ; ./aclnnAPI_fuzz aclnnAdaLayerNormBackward_error_fuzz
    

复现基线构造(满足 md 全部约束):input/gradOut/gradInputOut=[2,4,16],mean/rstd=[2,4,1],scale/shift/gradScaleOut/gradShiftOut=[2,16],weight/bias/gradWeight/gradBias=[16],normalizedShape=[16],全部 FLOAT,仅 gradInputOut 置 nullptr。

三、附件与证据(必填)

单场景最小复现 CPP(gradInputOut=nullptr,可直接编译执行):

#include <iostream>
#include <vector>
#include <cstring>
#include <unistd.h>
#include "acl/acl.h"
#include "aclnn/aclnn_base.h"
#include "acl/acl_base.h"
#include "acl/acl_rt.h"
#include "sec_common.h"
#include "utils.h"
#include "aclnnop/aclnn_ada_layer_norm_backward.h"
using namespace std;

// 单场景最小复现:gradInputOut = nullptr 时 aclnnAdaLayerNormBackwardGetWorkspaceSize 段错误
// base 构造完全满足 md 约束:input/gradOut/gradInputOut=[2,4,16],mean/rstd=[2,4,1],
// scale/shift/gradScaleOut/gradShiftOut=[2,16],weight/bias/gradWeight/gradBias=[16],normalizedShape=[16],全 FLOAT
int RunRepro()
{
    auto ret = Init(deviceId, &context, &stream);
    if (ret != ACL_SUCCESS) { printf("Init failed %d\n", (int)ret); return 1; }
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("[REPRO] aclnnAdaLayerNormBackward gradInputOut=nullptr 单场景复现开始\n");
    std::vector<int64_t> inputShape = {2, 4, 16};
    std::vector<int64_t> meanShape = {2, 4, 1};
    std::vector<int64_t> scaleShape = {2, 16};
    std::vector<int64_t> weightShape = {16};
    std::vector<int64_t> normArr = {16};
    void* goA=nullptr; aclTensor* go=nullptr;
    void* inA=nullptr; aclTensor* in=nullptr;
    void* meA=nullptr; aclTensor* me=nullptr;
    void* rsA=nullptr; aclTensor* rs=nullptr;
    void* scA=nullptr; aclTensor* sc=nullptr;
    void* shA=nullptr; aclTensor* sh=nullptr;
    void* wtA=nullptr; aclTensor* wt=nullptr;
    void* biA=nullptr; aclTensor* bi=nullptr;
    void* giA=nullptr; aclTensor* gi=nullptr;
    void* gsA=nullptr; aclTensor* gs=nullptr;
    void* ghA=nullptr; aclTensor* gh=nullptr;
    void* gwA=nullptr; aclTensor* gw=nullptr;
    void* gbA=nullptr; aclTensor* gb=nullptr;
    uint64_t ws=0; aclOpExecutor* ex=nullptr; void* wsAddr=nullptr;
    aclIntArray* ns=nullptr;
    int rc = 0;
    {
        std::vector<float> xh(128, 1.5f), mh(8, 0.5f), ph(32, 1.0f), oh(128, 0.0f), wh(16, 1.0f);
        CreateAclTensor_New(xh, inputShape, &goA, ACL_FLOAT, ACL_FORMAT_ND, &go);
        CreateAclTensor_New(xh, inputShape, &inA, ACL_FLOAT, ACL_FORMAT_ND, &in);
        CreateAclTensor_New(mh, meanShape, &meA, ACL_FLOAT, ACL_FORMAT_ND, &me);
        CreateAclTensor_New(mh, meanShape, &rsA, ACL_FLOAT, ACL_FORMAT_ND, &rs);
        CreateAclTensor_New(ph, scaleShape, &scA, ACL_FLOAT, ACL_FORMAT_ND, &sc);
        CreateAclTensor_New(ph, scaleShape, &shA, ACL_FLOAT, ACL_FORMAT_ND, &sh);
        CreateAclTensor_New(wh, weightShape, &wtA, ACL_FLOAT, ACL_FORMAT_ND, &wt);
        CreateAclTensor_New(wh, weightShape, &biA, ACL_FLOAT, ACL_FORMAT_ND, &bi);
        CreateAclTensor_New(oh, inputShape, &giA, ACL_FLOAT, ACL_FORMAT_ND, &gi);
        CreateAclTensor_New(ph, scaleShape, &gsA, ACL_FLOAT, ACL_FORMAT_ND, &gs);
        CreateAclTensor_New(ph, scaleShape, &ghA, ACL_FLOAT, ACL_FORMAT_ND, &gh);
        CreateAclTensor_New(wh, weightShape, &gwA, ACL_FLOAT, ACL_FORMAT_ND, &gw);
        CreateAclTensor_New(wh, weightShape, &gbA, ACL_FLOAT, ACL_FORMAT_ND, &gb);
        ns = aclCreateIntArray(normArr.data(), normArr.size());
        // ===== 注入唯一异常点:gradInputOut = nullptr =====
        aclDestroyTensor(gi); gi = nullptr;
        printf("[FUZZ_ERROR_POINT] case_0: errorType=NULLPTR_OUTPUT, errorTarget=gradInputOut, description=gradInputOut tensor is nullptr (md错误码表规定应返回161001)\n");
        printf("[FUZZ_PARAM] gradOut: dtype=FLOAT, shape=[2,4,16]; input: dtype=FLOAT, shape=[2,4,16]; normalizedShape=[16]; mean/rstd: shape=[2,4,1]; scale/shift: shape=[2,16]; weight/bias: shape=[16]; gradInputOut=nullptr\n");
        printf("[FUZZ_LOG] plog_file: aclnnAdaLayerNormBackward_error_plog_case_0.log\n");
        ret = aclnnAdaLayerNormBackwardGetWorkspaceSize(go, in, ns, rs, me, sc, sh, wt, bi,
            gi, gs, gh, gw, gb, &ws, &ex);
        printf("[REPRO] GetWorkspaceSize ret=%d (期望 161001, 实际发生 SIGSEGV 则为 bug)\n", (int)ret);
        printf("aclnnAdaLayerNormBackward execute failed :%d\n", (int)ret);
        rc = (int)ret;
        if (ret == ACL_SUCCESS) {
            if (ws > 0) { aclrtMalloc(&wsAddr, ws, ACL_MEM_MALLOC_HUGE_FIRST); }
            ret = aclnnAdaLayerNormBackward(wsAddr, ws, ex, stream);
            printf("aclnnAdaLayerNormBackward execute success :%d\n", (int)ret);
            rc = 0;
            aclrtSynchronizeStream(stream);
        }
        printf("[FUZZ_RESULT] case_0: %s, ret=%d\n", (rc == 0) ? "success" : "faild", rc);
    }
    if (go) aclDestroyTensor(go); if (in) aclDestroyTensor(in);
    if (me) aclDestroyTensor(me); if (rs) aclDestroyTensor(rs);
    if (sc) aclDestroyTensor(sc); if (sh) aclDestroyTensor(sh);
    if (wt) aclDestroyTensor(wt); if (bi) aclDestroyTensor(bi);
    if (gi) aclDestroyTensor(gi); if (gs) aclDestroyTensor(gs);
    if (gh) aclDestroyTensor(gh); if (gw) aclDestroyTensor(gw);
    if (gb) aclDestroyTensor(gb); if (ns) aclDestroyIntArray(ns);
    if (goA) aclrtFree(goA); if (inA) aclrtFree(inA);
    if (meA) aclrtFree(meA); if (rsA) aclrtFree(rsA);
    if (scA) aclrtFree(scA); if (shA) aclrtFree(shA);
    if (wtA) aclrtFree(wtA); if (biA) aclrtFree(biA);
    if (giA) aclrtFree(giA); if (gsA) aclrtFree(gsA);
    if (ghA) aclrtFree(ghA); if (gwA) aclrtFree(gwA);
    if (gbA) aclrtFree(gbA);
    if (ws > 0 && wsAddr) aclrtFree(wsAddr);
    aclrtDestroyStream(stream); aclrtDestroyContext(context); aclrtResetDevice(deviceId); aclFinalize();
    return rc;
}

extern "C" int aclnnAdaLayerNormBackward_error_fuzz(int argc, char *argv[]);
int aclnnAdaLayerNormBackward_error_fuzz(int argc, char *argv[])
{
    return RunRepro();
}

💡 该问题由 fuzz 自动化压测平台发现;同接口其余 nullptr 参数(gradInputOut/gradScaleOut/gradShiftOut)分别独立提单,一个场景一个 issue。


迁移说明:本 issue 由 fuzz 自动化压测平台于 2026-10-21 自 cann/ops-nn#7022 迁移至长尾责任仓(责任人维护仓)。原 issue 将关闭并指向本单。

likedislike
严明奎
严明奎
23 days ago Comments:

问题:aclnnAdaLayerNormBackward 在可选输出为 nullptr 时 SIGSEGV

原A2/A3引入 非A5长尾算子支持代码引入问题 与issue173问题重复

根因

image.png

op_api 未对可选输出做空指针判断,对 nullptr 的 aclTensor 调用了 GetDataType()。

  • 文件:norm/ada_layer_norm_grad/op_host/op_api/aclnn_ada_layer_norm_backward.cpp
  • GenOutWithMask()(L352-363):
    if (mask) {
    CHECK_RET(tempOut != nullptr, ACLNN_ERR_INNER_NULLPTR);
    auto tempCast = l0op::Cast(tempOut, output->GetDataType(), executor); // output 为 nullptr 时崩溃
  • L455-457 对 gradInputOut/gradScaleOut/gradShiftOut 硬编码 mask=true(而 L458-459 对 gradWeightOut/gradBiasOut 用了 != nullptr),导致这三个输出任一为空即空指针解引用。
likedislike
Alice_zhou
23 days ago Comments:

📎 复现附件下载(aclnnAdaLayerNormBackward gradInputOut nullptr 进程core 场景:执行步骤说明 + 压测 CPP + plog + 执行日志 + 分析报告):

aclnnAdaLayerNormBackward_error.zip

附件已存放在 Alice_zhou/issue 仓,点击上方链接直接下载(原结果服务器附件链接因服务器网络故障不可用,已改用本仓托管)。

likedislike
Alice_zhou
22 days ago Comments:

DTS2026102323776

likedislike
AAlice_zhou
22 days ago Close issue
Alice_zhou
9 days ago Comments:

复测验证 OK(2026-11-04,CANN 9.3.0):error 场景 1000 条压测无 SIGSEGV,gradInputOut=nullptr 时 GetWorkspaceSize 段错误已消除。

likedislike
Alice_zhou
14 hours ago Comments:

回归验证通过(2026-11-14,CANN 9.3.0,issue 回归测试)

按 issue 附件最小复现 CPP(base 构造满足 md 全部约束、仅注入单参数 nullptr)验证修复效果:

验证场景 原现象 现结果
gradInputOut=nullptr(本 issue 场景) GWS 段错误 SIGSEGV(退出码 139,崩溃于 aclTensor::GetDataType() 空指针解引用) 无崩溃(退出码 0),GWS ret=0 正常返回 ✅
gradScaleOut=nullptr(责任方根因中同款 GenOutWithMask 硬编码 mask=true 的输出) 同类崩溃风险 无崩溃,GWS ret=0 ✅
gradShiftOut=nullptr(同上) 同类崩溃风险 无崩溃,GWS ret=0 ✅

结论:GenOutWithMask()(aclnn_ada_layer_norm_backward.cpp L352-363)对 gradInputOut/gradScaleOut/gradShiftOut 的空指针崩溃已消除,修复生效,回归验证通过。

遗留观察(非阻塞):三个必需输出 nullptr 时 GWS 现返回 ret=0(执行成功)而非 md 错误码表规定的 161001(ACLNN_ERR_PARAM_NULLPTR)——崩溃已修复,但参数空指针校验缺失与 md 错误码描述仍不一致(与 changwei#204 中可选输出 gradWeightOut/gradBiasOut nullptr 合法不同,这三个为必需输出)。可另行确认是否需要补充 161001 校验,不影响本 issue 关闭。

likedislike