Bug 124114

Summary: 7.0 shared libs cannot read errno when loaded into a 6.0 pthreaded program
Product: Base System Reporter: martin
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 7.0-RELEASE   
Hardware: Any   
OS: Any   

Description martin 2008-05-29 23:00:10 UTC
There is something wrong with the way that errno is resolved when running 6.0 programs on 7.0-RELEASE with the compat6x-i386-6.3.602114.200711 pkg.

If a 7.0 shared library that uses errno is loaded into a 6.0 program that uses pthreads, then the value of errno in the library code will be incorrect.  In particular, it will access the global errno value instead of the thread-specific one.

I've included two test cases.  The X11 one is pretty much how the problem was discovered.  The libc one is doing the same thing as the libX11 function _XRead, where the problem occurs in the X11 example.

It also fails when compiled on FreeBSD 5.4 and run on FreeBSD 7.0 with compat5x.

This kind of code worked without any problems when built and run on FreeBSD 5 and also when run on FreeBSD 6 with compat5x.

How-To-Repeat: Test case 1: X11
----------------
a. Make the file below available on a 6.0 machine.

$ cat xerror.c
#include <X11/Xlib.h>
#include <stdio.h>
#include <pthread.h>

void *do_x11(void *arg)
{
  Display *disp;
  Atom primary;
  Window root;
  Atom actual_type;
  int actual_format;
  unsigned long nitems;
  unsigned long bytesafter;
  unsigned char *prop;
  int i;

  printf("Opening display\n");
  disp = XOpenDisplay(NULL);
  primary = XInternAtom(disp, "PRIMARY", 0);
  root = XRootWindow(disp, DefaultScreen(disp));
  printf("Atom is %d\nRoot is %d\n", (int)primary, (int)root);
  fflush(stdout);

  for (i = 0; i < 10000; i++) {
    XGetWindowProperty(disp, root, primary, 0, 0, False, primary,
		       &actual_type,
		       &actual_format,
		       &nitems,
		       &bytesafter,
		       &prop);
  }

  printf("Closing display\n");
  fflush(stdout);
  XCloseDisplay(disp);
  return NULL;
}

int main()
{
  pthread_t pt;

  pthread_create(&pt, NULL, do_x11, NULL);
  pthread_join(pt, NULL);

  return 0;
}


b. Compile it on a 6.0 machine to make a.out:
$ cc -pthread -I/usr/X11R6/include xerror.c -L/usr/X11R6/lib -lX11

c. Copy a.out to a 7.0 machine and run it with compat6x installed.
$ ./a.out
Opening display
Atom is 1
Root is 91
XIO:  fatal IO error 0 (Unknown error: 0) on X server "heap:0.0"
      after 8 requests (7 known processed) with 0 events remaining.

d. It should return without printing any X errors


Test case 2: libc
-----------------
a. Make the two files below available on a 6.0 machine.

$ cat lib.c
#include <errno.h>
#include <unistd.h>
int readerror()
{
  char buf[1];
  read(-1, buf, 1);
  return errno;
}

$ cat user.c
#include <stdio.h>
#include <pthread.h>

extern int readerror(void);

void *do_error(void *arg)
{
  printf("errno = %d\n", readerror());
}

int main()
{
  pthread_t pt;

  pthread_create(&pt, NULL, do_error, NULL);
  pthread_join(pt, NULL);

  return 0;
}

b. Compile them on a 6.0 machine to make lib.so and a.out:
$ cc -shared -o lib.so lib.c
$ cc -pthread user.c lib.so

c. Copy a.out and lib.c to a 7.0 machine and compile lib.c again:
$ cc -shared -o lib.so lib.c

d. Run the 6.0 a.out on the 7.0 machine with compat6x installed:
$ env LD_LIBRARY_PATH=`pwd` ./a.out
errno = 0

e. It should print errno = 9 (i.e. EBADF).
Comment 1 Remko Lodder freebsd_committer freebsd_triage 2008-05-30 15:39:24 UTC
Martin Simmons wrote:

The compat packages give the original libraries that were part of the 
6.x release that it's being based upon. Ofcourse a 7.x library wouldn't
work with a 6.x binary (especially if the library had changed or something).

Would it be possible for you to link against the compat-libraries?
(I think they are in /usr/local/lib/compat).

Thanks,
remko

-- 

/"\   Best regards,                      | remko@FreeBSD.org
\ /   Remko Lodder                       | remko@EFnet
  X    http://www.evilcoder.org/          |
/ \   ASCII Ribbon Campaign              | Against HTML Mail and News
Comment 2 Remko Lodder freebsd_committer freebsd_triage 2008-05-30 15:39:36 UTC
State Changed
From-To: open->feedback

I asked for feedback.
Comment 3 Kris Kennaway freebsd_committer freebsd_triage 2008-05-30 20:21:32 UTC
Martin Simmons wrote:

>> Description:
> There is something wrong with the way that errno is resolved when running 6.0 programs on 7.0-RELEASE with the compat6x-i386-6.3.602114.200711 pkg.
> 
> If a 7.0 shared library that uses errno is loaded into a 6.0 program that uses pthreads, then the value of errno in the library code will be incorrect.  In particular, it will access the global errno value instead of the thread-specific one.

This is the expected behaviour.

You *cannot*, in general, expect binaries linked to a mixture of 
libraries from different releases to work.  It is possible in restricted 
circumstances to carefully design your a library so that this will not 
happen, but random libraries do not have this property.

Kris
Comment 4 martin 2008-05-30 21:08:31 UTC
Sorry for the noise.  I've misunderstood the scope of the compat packages.  I
thought they were to designed to allow prebuilt 6.x binaries to run on 7.x,
but I guess that only works if all of the dependencies are core FreeBSD
libraries, not on the ports like X11.

It works fine if I arrange to use the 6.x X11 libraries.  Is there a correct
place to install these or is LD_LIBRARY_PATH the only solution?

__Martin
Comment 5 Remko Lodder freebsd_committer freebsd_triage 2008-06-01 09:27:09 UTC
State Changed
From-To: feedback->closed

This is actually working as designed, both Kris and me explained that to 
the submitter, who understands that. Closing the ticket.