LLVM: Почему я получаю ошибки по умолчанию при создании вызовов? - PullRequest
0 голосов
/ 31 мая 2019

Я использую LLVM C API.Я думаю, что я должен использовать LLVMBuildCall неправильно, потому что большинство звонков, которые я делаю ему, segfault.Я публикую минимальный пример, где это происходит ниже.Но у меня есть другие примеры, где я использую гораздо более сложные LLVMBuildCall вызовы, и это не вызывает ошибки.

Код немного длинный, но большая часть его является шаблонной;может быть, перейдем к комментарию // Here's the function type we'll use.Это вызов LLVMBuildCall(builder, f, params, PARAM_COUNT, "call"), который segfaults.Вот код:

#include <stdio.h>

#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h>
#include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h>

int
main() {
    // a lot of setup...
    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    char* triple = LLVMGetDefaultTargetTriple();
    char* error;
    LLVMTargetRef target_ref;
    if (LLVMGetTargetFromTriple(triple, &target_ref, &error)) {
        printf("Error: %s\n", error);
        return 1;
    }
    LLVMTargetMachineRef tm_ref = LLVMCreateTargetMachine(
      target_ref,
      triple,
      "",
      "",
      LLVMCodeGenLevelDefault,
      LLVMRelocStatic,
      LLVMCodeModelJITDefault);
    LLVMDisposeMessage(triple);

    LLVMContextRef context = LLVMContextCreate();
    LLVMModuleRef module = LLVMModuleCreateWithNameInContext("module_name", context);
    LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);

    LLVMTypeRef i64t = LLVMInt64TypeInContext(context);

    const int PARAM_COUNT = 1;

    LLVMTypeRef param_types[PARAM_COUNT] = {
      i64t,
    };

    // Here's the function type we'll use
    LLVMTypeRef func_type = LLVMFunctionType(i64t, param_types, PARAM_COUNT, 0);

    // start building it
    LLVMValueRef func = LLVMAddFunction(module, "func1", func_type);
    LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context, func, "entry");
    LLVMPositionBuilderAtEnd(builder, entry);

    LLVMValueRef c = LLVMConstInt(i64t, 0, 0);

    // If I try to call, I get a seg fault
    LLVMValueRef f = LLVMBuildBitCast(builder, c, func_type, "cast");
    LLVMValueRef params[PARAM_COUNT];
    for (int i = 0; i < PARAM_COUNT; i++) {
        params[i] = LLVMGetParam(f, i);
    }
    LLVMValueRef call = LLVMBuildCall(builder, f, params, PARAM_COUNT, "call");
    LLVMBuildRet(builder, call);

    // but if I comment the above and uncomment this, it works fine
    // LLVMBuildRet(builder, c);

    LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
    LLVMDisposeMessage(error);
}

И как я его запускаю:

$ llvm-config --version
8.0.0
$ clang++ trash.cpp `llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`
$ ./a.out 
Segmentation fault: 11

FWIW, когда я запускаю memcheck Вальгринда, я получаю это (с отсеченным дополнительным материалом):

==58974== Invalid read of size 8
==58974==    at 0x10084DA72: llvm::Use* llvm::copy<llvm::ArrayRef<llvm::Value*>&, llvm::Use*>(llvm::ArrayRef<llvm::Value*>&, llvm::Use*) (in ./a.out)
==58974==    by 0x10084D9E2: llvm::CallInst::init(llvm::FunctionType*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value*> >, llvm::Twine const&) (in ./a.out)
==58974==    by 0x100814CCA: llvm::CallInst::Create(llvm::FunctionType*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value*> >, llvm::Twine const&, llvm::Instruction*) (in ./a.out)
==58974==    by 0x1008137FD: llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>::CreateCall(llvm::FunctionType*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::Twine const&, llvm::MDNode*) (in ./a.out)
==58974==    by 0x1008137B9: LLVMBuildCall (in ./a.out)
==58974==    by 0x10000281A: main (trash.cpp:62)
==58974==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

Так что я предполагаю, что что-то обращается к нулевому указателю.

Еще один бит информации: один из каждых 20 запусков или около того, это не ошибка сегмента.Поэтому я вставил код, чтобы найти LLVMTypeKind переменной call, и он отличается LLVMTypeKind от типа возврата f.Я не думаю, что это должно быть.

1 Ответ

0 голосов
/ 31 мая 2019

Оказывается, что вместо использования LLVMBuildBitCast я должен вместо этого использовать LLVMConstIntToPtr. То, что получается из LLVMBuildBitCast, выглядит как указатель на функцию, но каким-то образом повреждено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...