This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[greg@surety.com] libc/1593: dlopen maps multiple loads of different versions of the same object into the same memory space, or something



Hi glibc developers,

we've received the appended bug report.  What's wrong here?

The output of the testprogram is:
0x4001713c blown was: 0
loaded ./libblow.so.1 at 0x8049ef0
0x4001713c blown was: 47806
loaded d1/libblow.so.1 at 0x804a2c8
0x4001713c blown was: 0
loaded d2/libblow.so.1 at 0x804a660
0x4001713c blown was: 47806
0x4001713c blown was: 27315
0x4001713c blown was: 47806

Andreas




>Number:         1593
>Category:       libc
>Synopsis:       dlopen maps multiple loads of different versions of the same object into the same memory space, or something
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    libc-gnats
>State:          open
>Class:          sw-bug
>Submitter-Id:   unknown
>Arrival-Date:   Thu Feb 10 13:40:00 EST 2000
>Last-Modified:
>Originator:     greg@surety.com
>Organization:
net
>Release:        2.1.1-6
>Environment:
red hat linux 6.0, intel arch, glibc-2.1.1-6
>Description:
this silly little test program demonstrates a bug in dlopen in glibc 2.1.1-6
as shipped with Red Hat Linux 6.0.  the bug: loading up the same shared
object from multiple locations ends up loading the object mutliple times,
but each version is mapped into the same location, or something, so that
the initializers are invoked on the same memory locations on each load.
this is demonstrated by loading up three copies of the same shared object.
each load causes the constructor for a static object to be invoked.  it is
invoked on the same object each time.  this is no good.

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-02-10 13:29 EST by <greg@surety.com>.
# Source directory was `/home/greg/surety/testblow'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    498 -rw-r--r-- Makefile
#    435 -rw-r--r-- blow.cpp
#   1433 -rw-r--r-- testblow.cpp
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh04671; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Makefile for testblow
X
CXX = g++
CXXFLAGS = -Wall -ggdb -fpic
CPPFLAGS = -D_GNU_SOURCE
LDLIBS = -ldl
X
X.PHONY : all clean
X
all : testblow libblow.so.1 d1/libblow.so.1 d2/libblow.so.1
X
clean :
X	-rm testblow blow.o libblow.so.1 d1/libblow.so.1 d2/libblow.so.1
X	-rmdir d1 d2
X
testblow : testblow.cpp
X
libblow.so.1 : blow.o
X	$(CXX) $^ -shared -Wl,-h,$@ -o $@
X
d1/libblow.so.1 : d1 libblow.so.1
X	cp libblow.so.1 d1
X
d2/libblow.so.1 : d2 libblow.so.1
X	cp libblow.so.1 d2
X
d1 :
X	mkdir d1
X
d2 :
X	mkdir d2
SHAR_EOF
  $shar_touch -am 02101326100 'Makefile' &&
  chmod 0644 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
5c82c32c18326a141e964c225ef1a851  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 498 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '498,' 'current size' "$shar_count!"
  fi
fi
# ============= blow.cpp ==============
if test -f 'blow.cpp' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'blow.cpp' '(file already exists)'
else
  $echo 'x -' extracting 'blow.cpp' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'blow.cpp' &&
#include <stdio.h>
X
class blow {
public:
X    				 blow(void) throw();
X				~blow(void) throw();
X
private:
X    unsigned short		 _blown;
X
X    static blow			 _instance;
}; // class blow
X
X
blow::blow(
X    void
X    ) throw()
{
X    printf("%p blown was: %hu\n", this, _blown);
X    _blown ^= 0xBABE;
}
X
X
blow::~blow(
X    void
X    ) throw()
{
X    printf("%p blown was: %hu\n", this, _blown);
X    _blown ^= 0xD00D;
}
X
X
blow				 blow::_instance;
SHAR_EOF
  $shar_touch -am 02101229100 'blow.cpp' &&
  chmod 0644 'blow.cpp' ||
  $echo 'restore of' 'blow.cpp' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'blow.cpp:' 'MD5 check failed'
99cb31723ab463a42ede102ba205c6a5  blow.cpp
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'blow.cpp'`"
    test 435 -eq "$shar_count" ||
    $echo 'blow.cpp:' 'original size' '435,' 'current size' "$shar_count!"
  fi
fi
# ============= testblow.cpp ==============
if test -f 'testblow.cpp' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'testblow.cpp' '(file already exists)'
else
  $echo 'x -' extracting 'testblow.cpp' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testblow.cpp' &&
/*
X * testblow.c
X *
X * this silly little test program demonstrates a bug in dlopen in glibc 2.1.1-6
X * as shipped with Red Hat Linux 6.0.  the bug: loading up the same shared
X * object from multiple locations ends up loading the object mutliple times,
X * but each version is mapped into the same location, or something, so that
X * the initializers are invoked on the same memory locations on each load.
X * this is demonstrated by loading up three copies of the same shared object.
X * each load causes the constructor for a static object to be invoked.  it is
X * invoked on the same object each time.  this is no good.
X *
X * greg thompson <greg@surety.com>
X * 2000-02-10
X */
X
#include <stdio.h>
#include <dlfcn.h>
X
X
extern "C" int main(
X    int				 argc,
X    char			*argv[]
X    ) throw()
{
X    void			*b, *o, *l;
X
X    if ((b = dlopen("./libblow.so.1", RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
X	printf("%s\n", dlerror());
X	return 1;
X    }
X
X    printf("loaded ./libblow.so.1 at %p\n", b);
X
X    if ((o = dlopen("d1/libblow.so.1", RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
X	printf("%s\n", dlerror());
X	dlclose(b);
X	return 1;
X    }
X
X    printf("loaded d1/libblow.so.1 at %p\n", o);
X
X    if ((l = dlopen("d2/libblow.so.1", RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
X	printf("%s\n", dlerror());
X	dlclose(o);
X	dlclose(b);
X	return 1;
X    }
X
X    printf("loaded d2/libblow.so.1 at %p\n", l);
X
X    dlclose(l);
X
X    dlclose(o);
X
X    dlclose(b);
X
X    return 0;
}
SHAR_EOF
  $shar_touch -am 02101327100 'testblow.cpp' &&
  chmod 0644 'testblow.cpp' ||
  $echo 'restore of' 'testblow.cpp' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'testblow.cpp:' 'MD5 check failed'
4fd04e6d887282a2a3e0642af2aa9dda  testblow.cpp
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'testblow.cpp'`"
    test 1433 -eq "$shar_count" ||
    $echo 'testblow.cpp:' 'original size' '1433,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh04671
exit 0

>How-To-Repeat:

>Fix:
>Audit-Trail:
>Unformatted:




-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.rhein-neckar.de

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]