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

从AST生成LLVM代码时出现内存错误,请求排查原因

问题排查:LLVM BuildStore 内存访问错误

测试代码:

start
int a;
a = 5;
end

AST结构定义

struct ASTNode {
    NodeType type;       
    LLVMValueRef llvmValue;
    union {
        int intValue;                            
        double doubleValue;                      
        bool boolValue;                           
        char *identifier;                        
        struct BinaryOpNode binaryOp;            
        struct AssignmentNode assignment;        
        struct VariableDeclarationNode variableDeclaration; 
    } data;
};

LLVM初始化代码

void setupLLVM() {
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();

GlobalContext = LLVMContextCreate();
GlobalModule = LLVMModuleCreateWithNameInContext("test_module", GlobalContext);
GlobalBuilder = LLVMCreateBuilderInContext(GlobalContext); }

AST相关实现代码(ast.c)

变量声明节点创建函数

ASTNode* createVariableDeclarationNode(char *type, char *identifier) {
    ASTNode* node = malloc(sizeof(ASTNode));
    node->type = AST_VARIABLE_DECLARATION;
    node->data.variableDeclaration.type = _strdup(type);
    node->data.variableDeclaration.identifier = _strdup(identifier);
    
    LLVMTypeRef varType = 0;

    if (strcmp(type, "int") == 0) {
        varType = LLVMInt32TypeInContext(GlobalContext);
    }
    else if (strcmp(type, "double") == 0) {
        varType = LLVMDoubleTypeInContext(GlobalContext);
    }
    else if (strcmp(type, "bool") == 0) {
        varType = LLVMInt1TypeInContext(GlobalContext);
    }

    LLVMValueRef var = LLVMAddGlobal(GlobalModule, varType, identifier);
    LLVMSetInitializer(var, LLVMConstInt(varType, 0, 0));
    node->llvmValue = var;

    printNode(node);
    return node;
}

常量整数节点创建函数

ASTNode* createIntNode(int value) {
    ASTNode* node = malloc(sizeof(ASTNode));
    node->type = AST_INTEGER;
    node->data.intValue = value;
    node->llvmValue = LLVMConstInt(LLVMInt32TypeInContext(GlobalContext), value, 0);
    printNode(node);
    return node;
}

赋值节点创建函数(崩溃位置)

ASTNode* createAssignmentNode(char *identifier, ASTNode *expression) {
    ASTNode* node = malloc(sizeof(ASTNode));
    node->type = AST_ASSIGNMENT;
    node->data.assignment.identifier = _strdup(identifier);
    node->data.assignment.expression = expression;
    LLVMValueRef var = LLVMGetNamedGlobal(GlobalModule, identifier);

    if (!var || !expression->llvmValue) {
        printf("assigment error\n");
    }
    // 崩溃位置
    node->llvmValue = LLVMBuildStore(GlobalBuilder, expression->llvmValue, var);
  
    printNode(node);
    return node;
}

错误现象

执行LLVMBuildStore时出现内存访问错误,错误地址为0x0000000000000050。


错误原因分析

  1. Builder未设置有效插入点:LLVMBuildStore生成的IR指令必须属于某个函数的基本块,但当前setupLLVM仅创建了Builder,未为其绑定任何函数或基本块。直接在全局上下文调用该函数会导致访问非法内存。
  2. 全局变量操作不符合LLVM规范:全局变量的初始化应通过LLVMSetInitializer完成,运行时赋值操作必须放在函数体内执行,当前代码试图在全局作用域生成Store指令,违反了LLVM的IR结构要求。

解决方案

步骤1:完善LLVM初始化,创建主函数与基本块

修改setupLLVM,添加主函数和入口基本块,并设置Builder的插入点:

void setupLLVM() {
    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeAsmParser();

    GlobalContext = LLVMContextCreate();
    GlobalModule = LLVMModuleCreateWithNameInContext("test_module", GlobalContext);
    GlobalBuilder = LLVMCreateBuilderInContext(GlobalContext);

    // 创建int main()函数类型
    LLVMTypeRef mainFuncType = LLVMFunctionType(LLVMInt32TypeInContext(GlobalContext), NULL, 0, 0);
    LLVMValueRef mainFunc = LLVMAddFunction(GlobalModule, "main", mainFuncType);
    
    // 创建主函数入口基本块并设置Builder插入点
    LLVMBasicBlockRef entryBlock = LLVMAppendBasicBlockInContext(GlobalContext, mainFunc, "entry");
    LLVMPositionBuilderAtEnd(GlobalBuilder, entryBlock);
}

步骤2:修正赋值节点函数

确保Store指令在有效基本块内生成,同时完善错误处理:

ASTNode* createAssignmentNode(char *identifier, ASTNode *expression) {
    ASTNode* node = malloc(sizeof(ASTNode));
    node->type = AST_ASSIGNMENT;
    node->data.assignment.identifier = _strdup(identifier);
    node->data.assignment.expression = expression;
    LLVMValueRef var = LLVMGetNamedGlobal(GlobalModule, identifier);

    if (!var || !expression->llvmValue) {
        printf("assignment error\n");
        free(node);
        return NULL;
    }

    // Builder已绑定有效插入点,可安全生成Store指令
    node->llvmValue = LLVMBuildStore(GlobalBuilder, expression->llvmValue, var);
  
    printNode(node);
    return node;
}

步骤3:可选补充主函数返回指令

解析完成所有语句后,为主函数添加返回指令,确保IR完整性:

// 解析结束后调用
void finalizeLLVM() {
    LLVMBuildRet(GlobalBuilder, LLVMConstInt(LLVMInt32TypeInContext(GlobalContext), 0, 0));
    // 验证IR合法性
    char *errMsg = NULL;
    if (LLVMVerifyModule(GlobalModule, LLVMAbortProcessAction, &errMsg)) {
        printf("Module verification failed: %s\n", errMsg);
        LLVMDisposeMessage(errMsg);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 10:45:04