LLVM ParseIR Segfault

Я пытаюсь скомпилировать функцию ("fun") для LLVM IR и создать модуль с помощью функции ParseIR. Программа segfaults при вызове ParseIR. Я использую LLVM 3.5, код ниже.

#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>

#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"

using std::cout;
using std::endl;
using std::ostringstream;
using std::string;

using llvm::getGlobalContext;
using llvm::LLVMContext;
using llvm::MemoryBuffer;
using llvm::Module;
using llvm::ParseIR;
using llvm::SMDiagnostic;
using llvm::StringRef;

int main() {
    string fun = "int fun(int x) {return x;}\n";

    string cmd = "echo '" + fun + "' |"
               + " clang++ -cc1 -xc++ -O0 -std=c++1y -fno-use-cxa-atexit"
               + " -I/usr/local/lib/clang/3.5.0/include/"
               + " -I/usr/include/c++/4.9/"
               + " -I/usr/include/x86_64-linux-gnu/c++/4.9/bits/"
               + " -I/usr/include/x86_64-linux-gnu -I/usr/include/"
               + " -I/usr/include/x86_64-linux-gnu/c++/4.9/"
               + " -I/usr/lib/gcc/x86_64-linux-gnu/4.9/include/"
               + " -I/usr/include/c++/4.9/backward/"
               + " -I/usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed/"
               + " -stdlib=libstdc++ -S -emit-llvm"
               + " -o /dev/stdout 2> /dev/stdout";

    FILE *file = popen(cmd.c_str(), "r");
    ostringstream llvm;
    char line[1024];
    while (fgets(line, 1024, file))
        llvm << line;
    pclose(file);

    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMContext &ctx = getGlobalContext();
    SMDiagnostic *err;
    StringRef ref = StringRef(llvm.str().c_str());
    MemoryBuffer *buff = MemoryBuffer::getMemBuffer(ref);

    cout << "***** C++ *****\n" << fun << "\n"
         << "***** LLVM *****\n" << llvm.str() << endl;

    //segfault
    Module *mod = ParseIR(buff, *err, ctx);

    return 0;
}

Я скомпилировал и запустил приведенный выше код, используя следующую команду:

g++ -std=c++14 fun.cpp -o fun `llvm-config --cxxflags --ldflags --libs --system-libs`
./fun
***** C++ *****
int fun(int x) {return x;}

***** LLVM *****
; ModuleID = '-'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind
define i32 @_Z3funi(i32 %x) #0 {
  %1 = alloca i32, align 4
  store i32 %x, i32* %1, align 4
  %2 = load i32* %1, align 4
  ret i32 %2
}

attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"clang version 3.5.1 (branches/release_35 225591)"}

Segmentation fault (core dumped)

person agg212    schedule 21.04.2015    source источник


Ответы (1)


Вы не инициализируете свой SMDiagnostic*, а разыменовываете его при вызове ParseIR. Вот почему ваша программа ошибается. Смотрите комментарии в коде для исправления.

LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMContext &ctx = getGlobalContext();
SMDiagnostic err; // create an SMDiagnostic instance
MemoryBuffer* buff = MemoryBuffer::getMemBuffer(llvm.str());
cout << "***** C++ *****\n" << fun << "\n"
     << "***** LLVM *****\n" << llvm.str() << endl;

Module *mod = ParseIR(buff, err, ctx); // use err directly
person Michael Haidl    schedule 21.04.2015
comment
Это не проблема, но я бы также опасался StringRef(llvm.str().c_str()), потому что StringRef не владеет своим содержимым. - person zneak; 21.04.2015
comment
Я внес изменения в ответ и заменил вашу инициализацию StringRef и MemoryBuffer на способ, который отлично работает в моей программе. Вам не нужно обрабатывать StringRef самостоятельно. Просто передайте параметр std::string параметру StringRef. - person Michael Haidl; 21.04.2015
comment
Это исправило проблему, и ParseIR теперь работает правильно, спасибо! Однако я столкнулся с другим segfault со следующим кодом, который я пытаюсь добавить следующим: for (Module::iterator i = mod->begin(); i != mod->end(); ++i) { ... } - person agg212; 21.04.2015
comment
Я поигрался с этим и обнаружил, что err.getMessage() возвращает ожидаемую сущность верхнего уровня, а err.getLineContents() печатает мусор, поэтому похоже, что LLVM поврежден, но мне неясно, как и почему. - person agg212; 21.04.2015
comment
@agg212 agg212, попробуйте module->dump() и посмотрите, выводит ли он что-то значимое. - person zneak; 21.04.2015
comment
Module, возвращаемый ParseIR, является нулевым указателем, а сообщение от SMDiagnostic является ожидаемым объектом верхнего уровня. Я пытаюсь проследить исходный код LLVM, чтобы увидеть, где они возвращают нулевой указатель. - person agg212; 21.04.2015
comment
Я закончил тем, что сделал string x = llvm.str(), и это решило проблему. Кажется, теперь все работает хорошо, есть идеи, почему? Спасибо! - person agg212; 21.04.2015