7

Linuxの場合。dlsym(3)Linuxのマニュアルページによると、

    *Since the value of the symbol could actually be NULL
    (so that a NULL return from dlsym() need not indicate an error),*

シンボル(具体的には関数の場合)が実際にNULLになるのはなぜですか?コードを確認しているところ、最初にdlerrorを使用してクリーンアップし、次にdlsymを使用して、エラーをチェックするためにdlerrorを使用している部分を見つけました。ただし、呼び出す前に、結果の関数がnullであるかどうかはチェックされません。

  • dlerror();
  • a_func_name = ... dlsym(...);
  • if(dlerror())goto end;
  • a_func_name(...); // a_func_name==NULLかどうかはチェックしません;

私は単なるレビュー担当者なので、チェックを追加するオプションはありません。そして、おそらく作者はNULLが返されることは決してないことを知っています。私の仕事はそれに挑戦することですが、これが有効なNULLを返す原因がわからないため、このコードのコンテキストでそのような条件が満たされるかどうかを確認できます。グーグルで読むべき正しいものを見つけていないので、あなたがどれが素晴らしいかを明確に説明したいのでなければ、良いドキュメントへのポインタで十分でしょう。

4

4 に答える 4

3

dlsym()によって返されるシンボル値がNULLになる可能性がある特定のケースを知っています。これは、GNU間接関数(IFUNC)を使用している場合です。ただし、 dlsym(3)のマニュアルページのテキストはIFUNCの発明よりも前のものであるため、おそらく他の場合もあります。

IFUNCを使用した例を次に示します。まず、共有ライブラリの作成に使用されるファイル:

$ cat foo.c 
/* foo.c */

#include <stdio.h>

/* This is a 'GNU indirect function' (IFUNC) that will be called by
   dlsym() to resolve the symbol "foo" to an address. Typically, such
   a function would return the address of an actual function, but it
   can also just return NULL.  For some background on IFUNCs, see
   https://willnewton.name/uncategorized/using-gnu-indirect-functions/ */

asm (".type foo, @gnu_indirect_function");

void *
foo(void)
{
    fprintf(stderr, "foo called\n");
    return NULL;
}

foo次に、共有ライブラリでシンボルを検索するメインプログラム:

$ cat main.c
/* main.c */

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    void *handle;
    void (*funcp)(void);

    handle  = dlopen("./foo.so", RTLD_LAZY);
    if (handle == NULL) {
        fprintf(stderr, "dlopen: %s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();      /* Clear any outstanding error */

    funcp = dlsym(handle, "foo");

    printf("Results after dlsym(): funcp = %p; dlerror = %s\n",
            (void *) funcp, dlerror());

    exit(EXIT_SUCCESS);
}

次に、ビルドして実行し、がdlsym()戻るケースを確認します。またNULL、次をdlerror()返しますNULL

$ cc -Wall -fPIC -shared -o libfoo.so foo.c
$ cc -Wall -o main main.c libfoo.so -ldl
$ LD_LIBRARY_PATH=. ./main
foo called
Results after dlsym(): funcp = (nil); dlerror = (null)
于 2018-12-03T08:32:24.303 に答える
2

エラーなしで返された場合、ポインタは有効でありNULL、共有オブジェクトからのランダムなポインタとほぼ同じくらい違法です。間違った関数、データなどのように。

于 2012-12-18T21:45:00.320 に答える
1

ライブラリ/PIEが通常のCコンパイルの製品であるかどうかはわかりません。これは、Cがアドレスにグローバルオブジェクトを配置することはないためですが、特別なリンカートリックNULLを使用して解決するシンボルを取得できます。NULL

null.c:

#include <stdio.h>
extern char null_addressed_char;
int main(void) 
{
    printf("&null_addressed_char=%p\n", &null_addressed_char);
}

コンパイル、リンク、および実行:

$ clang null.c -Xlinker --defsym -Xlinker null_addressed_char=0 && ./a.out
&null_addressed_char=(nil)

そのような奇妙さを許可しない場合は、NULLからの返品dlsymをエラーとして扱うことができます。

于 2018-12-03T09:24:28.100 に答える
-2

dlerror()最後の呼び出しのステータスではなく、最後のエラーを返します。したがって、他に何も表示されない場合、有効な結果が得られdlsym()、エラーが発生したと思われる可能性があります(キューにまだエラーがあったため)。dlerrorの背後にある目的は、人間が読める形式のエラーメッセージを提供することです。結果を印刷していない場合は、間違って使用しています。

于 2012-12-18T22:08:57.877 に答える