This is with 5.5 release on i386 (32 bit).

When main program has more than one function pointer declared
with the *same names* as functions in a shared library, and
initializes one (at least) with the symbol from that library
with dlsym(), and references the second in some way (take
address, dereference/call. etc.), and the shared library
calls the second function, then the program segfaults at
the point of the lib making that call, but after ld.so has
printed messages like:
        "WARNING: symbol(fn_02) size mismatch, relink your program"
apparently one for each reference to that symbol in either the
main program or library.

This is reliably repeatable, and is probably easier to understand
in code than in my description, so a near-minimal program and
Makefile are appended to this message.

For the test prog try:
# bug
% make clean; make
# workaround 1 -- initialize symbol in main prog
% make clean; make fix
# workaround 2 -- do not reference symbol in prog
% make clean; make fix2
# still bug, different output (FPIC defaults empty)
% make clean; make FPIC="-fPIC"

I'm sure this was not a problem with OpenBSD 4.9 because
the code that raised the issue was fine on that.

-Ed

FILES:
/** BEGIN dltst.c */
#include <stdio.h>

#ifdef BUILDPROG
#ifdef LOADRUNTIME
#include <dlfcn.h>
void (*fn_01)();
#if FIXHACK == 1
void (*fn_02)() = 0;
#else
void (*fn_02)();
#endif
void loadsyms()
{       /*
         * RTLD_LAZY reorders "size mismatch, relink your program"
         * message and backtrace is different, but segfaults IAC
         */
        void* handle = dlopen(DLTST_SONAME, RTLD_NOW);
        fn_01 = dlsym(handle, "fn_01");
        /* a reference to fn_02 (here and main()) will trigger bug */
        #if FIXHACK != 2
        fn_02 = dlsym(handle, "fn_02");
        #endif
}
#else /* LOADRUNTIME */
void fn_01();
void fn_02();
void loadsyms()
{
}
#endif /* LOADRUNTIME */

int main()
{
        loadsyms();
        /* look at addresses *of* and *in* pointers */
        printf("From main prog; fn_01 at %p points to %p\n", &fn_01, fn_01);
        #if FIXHACK != 2
        printf("From main prog; fn_02 at %p points to %p\n", &fn_02, fn_02);
        #endif
        /* call 1st func only; it calls the 2nd within so */
        fn_01();
        return 0;
}
#else /* BUILDPROG */
/* this section compiles for shared lib */
void fn_02()
{
        void (*p)() = fn_02;
        /* look at this func address */
        printf("From shared lib; %s at %p\n", __FUNCTION__, p);
}
void fn_01()
{
        void (*p)() = fn_01;
        /* look at this func address */
        printf("From shared lib; %s at %p\n", __FUNCTION__, p);
        p = fn_02;
        /* look at *2nd* func address; before segfault */
        printf("From shared lib; %s -- fn_02 is at %p\n", __FUNCTION__, p);
        fn_02();
}
#endif /* BUILDPROG */
/** END dltst.c */

## BEGIN Makefile
NAME = dltst
SONAME = lib$(NAME)
SRC = $(NAME).c
SOSRC = so_$(NAME).c
PROG = $(NAME)_lt
PROGRT = $(NAME)_rt
SO = $(SONAME).so
# not for OpenBSD, but others use -ldl
#LIBS = -ldl
LIBS =
# pic difference? yes, but still gets message and segfault
#FPIC = -fPIC
FPIC =

# default: build and run program w/ runtime loading that will segfault
all: run_rt

# 1st run prog w/o runtime loading (no core), then as above
both check compare: run_lt run_rt

# workaround: initialize (assign 0) pertinent global symbol: no segfault
fix:
        rm -f $(PROGRT)
        make CFLAGS="$(CFLAGS) -DFIXHACK=1" run_rt
# workaround: declare but do not reference pertinent global symbol: no segfault
fix2:
        rm -f $(PROGRT)
        make CFLAGS="$(CFLAGS) -DFIXHACK=2" run_rt

run_rt: $(PROGRT)
        @echo === running $(PROGRT) -- runtime load
        LD_LIBRARY_PATH=$$PWD ./$(PROGRT)

run_lt: $(PROG)
        @echo === running $(PROG) -- implicit link
        LD_LIBRARY_PATH=$$PWD ./$(PROG)

$(SO) mk_so: $(SOSRC)
        $(CC) $(CFLAGS) -shared $(FPIC) -o $(SO) $(SOSRC)

$(PROG) mk_prog_lt: $(SRC) $(SO)
        $(CC) $(CFLAGS) -DBUILDPROG -o $(PROG) $(SRC) $(LIBS) -L$$PWD -l$(NAME)

# make program using runtime loading
$(PROGRT) mk_prog_rt: $(SRC) $(SO)
        $(CC) $(CFLAGS) -DBUILDPROG -DLOADRUNTIME -DDLTST_SONAME=\"$(SO)\" -o 
$(PROGRT) $(SRC) $(LIBS)

# copy source to new name for so; this is for clarity in gdb
$(SOSRC): $(SRC)
        @rm -f $@; cp -p $(SRC) $@

clean:
        rm -f $(PROG) $(PROGRT) $(SO) $(SOSRC) *.core core

## END Makefile

Reply via email to