Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can the value of the symbol returned by dlsym() be null?

Tags:

linux

dlsym

In Linux. Per the dlsym(3) Linux man page,

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

Why is this, when can a symbol (for a function, specifically) be actually NULL? I am reviewing code and found a piece using dlerror to clean first, dlsym next, and dlerror to check for errors. But it does not check the resulting function from being null before calling it:

  • dlerror();
  • a_func_name = ...dlsym(...);
  • if (dlerror()) goto end;
  • a_func_name(...); // Never checked if a_func_name == NULL;

I am just a reviewer so don't have the option to just add the check. And perhaps the author knows NULL can never be returned. My job is to challenge that but don't know what could make this return a valid NULL so I can then check if such a condition could be met in this code's context. Have not found the right thing to read with Google, a pointer to good documentation would be enough unless you want to explain explicitly which would be great.

like image 323
bokusama Avatar asked Dec 18 '12 21:12

bokusama


People also ask

What does Dlsym return?

Upon successful completion, if name names a function identifier, dlsym() shall return the address of the function converted from type pointer to function to type pointer to void; otherwise, dlsym() shall return the address of the data object associated with the data object identifier named by name converted from a ...

What does dlsym do?

dlsym() allows a process to obtain the address of a symbol defined within an object made accessible through a dlopen() call. handle is the value returned from a call to dlopen() (and which has not since been released via a call to dlclose()), name is the symbol's name as a character string.

How do you use Dlopen and Dlsym?

The main routine for using a DL library is dlsym(3), which looks up the value of a symbol in a given (opened) library. This function is defined as: void * dlsym(void *handle, char *symbol); the handle is the value returned from dlopen, and symbol is a NIL-terminated string.

What is Dlopen in C++?

dlopen() The function dlopen() loads the dynamic library file named by the null-terminated string filename and returns an opaque "handle" for the dynamic library. If filename is NULL, then the returned handle is for the main program.


1 Answers

I know of one particular case where the symbol value returned by dlsym() can be NULL, which is when using GNU indirection functions (IFUNCs). However, there are presumably other cases, since the text in the dlsym(3) manual page pre-dates the invention of IFUNCs.

Here's an example using IFUNCs. First, a file that will be used to create a shared library:

$ 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;
}

Now the main program, which will look up the symbol foo in the shared library:

$ 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);
}

Now build and run to see a case where dlsym() returns NULL, while dlerror() also returns 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)
like image 189
mtk Avatar answered Nov 15 '22 11:11

mtk