从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。
错误原因分析
- Builder未设置有效插入点:
LLVMBuildStore生成的IR指令必须属于某个函数的基本块,但当前setupLLVM仅创建了Builder,未为其绑定任何函数或基本块。直接在全局上下文调用该函数会导致访问非法内存。 - 全局变量操作不符合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
相关产品推荐
相关产品推荐

