2017-09-04 22 views
1

私はC++を学び、linux(.so)上で共有ライブラリを読み込むことを試しています。C++で共有ライブラリをロードするとセグメント化エラーが発生する

以下のコードを実行すると、セグメント化エラーが発生します。

私はvalgrindのを使用して、コンソールアプリケーションを実行しようとすると、私は次を得る:

valgrind ./TestLoadSo --leak-check=full -v 
==26828== Memcheck, a memory error detector 
==26828== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==26828== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info 
==26828== Command: ./TestLoadSo --leak-check=full -v 
==26828== 
!!!Hello World!!! 
==26828== Jump to the invalid address stated on the next line 
==26828== at 0x0: ??? 
==26828== by 0x53E63F0: (below main) (libc-start.c:291) 
==26828== Address 0x0 is not stack'd, malloc'd or (recently) free'd 
==26828== 
==26828== 
==26828== Process terminating with default action of signal 11 (SIGSEGV) 
==26828== Bad permissions for mapped region at address 0x0 
==26828== at 0x0: ??? 
==26828== by 0x53E63F0: (below main) (libc-start.c:291) 
==26828== 
==26828== HEAP SUMMARY: 
==26828==  in use at exit: 3,126 bytes in 9 blocks 
==26828== total heap usage: 13 allocs, 4 frees, 76,998 bytes allocated 
==26828== 
==26828== LEAK SUMMARY: 
==26828== definitely lost: 0 bytes in 0 blocks 
==26828== indirectly lost: 0 bytes in 0 blocks 
==26828==  possibly lost: 0 bytes in 0 blocks 
==26828== still reachable: 3,126 bytes in 9 blocks 
==26828==   suppressed: 0 bytes in 0 blocks 
==26828== Rerun with --leak-check=full to see details of leaked memory 
==26828== 
==26828== For counts of detected and suppressed errors, rerun with: -v 
==26828== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 
[1] 26828 segmentation fault (core dumped) valgrind ./TestLoadSo --leak-check=full -v 

C++のメインクラス

extern "C" typedef char* (*helloWorld_t)(); 

int main() { 

    void* handle = dlopen("./libMyLib.dll.so", RTLD_LAZY); 

    if (!handle) { 
    cerr << "Cannot open library: " << dlerror() << '\n'; 
    return 1; 
    } 
    helloWorld_t hello = (helloWorld_t)dlsym(handle, "helloWorld"); 
    const char * tmp = hello(); 
    printf("\n%s",tmp); 

    return 0; 
} 

はextern関数は次のとおりです。

extern "C++" char* helloWorld() { 
    char str[25]; 
    strcpy(str, "HelloWorld"); 
} 

extern "C"を使用した場合は、コンパイルが行われますエラー:

error: conflicting declaration of ‘char* helloWorld()’ with ‘C’ linkage 
extern "C" char* helloWorld() { 

私が間違っているところは本当にわかりません。

+0

「helloWorld」関数の実装は何ですか?また、valgrindからより良い情報を得るために-O0でプログラムをコンパイルしてください。 – Serge

+1

'次の行に記載された無効なアドレスにジャンプする '.soの中に* helloWorld *シンボルがないようです。 'extern"の代わりに 'extern" C "'を使うべきではありませんか?C++ "'? – freakish

+2

また、外部のhelloWorldは何も返しません。実際に 'return str'を持っていれば、それは問題になるでしょう - スタック変数へのポインタを返さないでください。 – lxop

答えて

2

多くの問題:

extern "C++" char* helloWorld() { 
    char str[25]; 
    strcpy(str, "HelloWorld"); 
} 

それは"C"リンケージを使用する必要があります。そして、何かを返すべきです。また、文字列をローカル変数にコピーするので、値が返されると値が失われます。したがっておそらく

extern "C" char* helloWorld() { 
    static char str[25]; // will keep its value accross calls, not thread safe 
    return strcpy(str, "HelloWorld"); // return pointer to start of str 
} 

複数の呼び出しはすべて同じ静的バッファを返します。コピーが必要な場合は、呼び出し元にバッファを提供させるか、mallocで割り当てられたバッファを返す必要があります。

+0

ありがとう、これが助けになりました。 – Magick

5

関数はCとC++リンケージの両方を持つことはできません。関数ポインタ型は、そのターゲット関数のリンケージと一致する必要があります。

dlsymextern "C++"の機能は、その未修飾名では機能しません。どちらの場合もextern "C"を使用するか(推奨)、extern "C++"を使用し、dlsym(handle, "helloWorld")の文字列を関数の名前を変更してください(ではなく、を推奨)。

dlsymの結果を常にチェックして、ヌルポインタ(dlopenの場合のようにdlerror()を使用)を返した場合はエラーを報告してください。

文字列を表す文字配列やポインタは使用しないでください。文字列には、std::stringと呼ばれるタイプがあります。

最後に、-Wall -Werrorをコンパイルすると、実際に値を返さない非void関数のようなものが捕捉されます。ここ

関連する問題