Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 May 1998 20:40:06 +1000
From:      Stephen McKay <syssgm@dtir.qld.gov.au>
To:        Terry Lambert <tlambert@primenet.com>
Cc:        freebsd-current@FreeBSD.ORG, syssgm@dtir.qld.gov.au
Subject:   Re: Fix for undefined "__error" and discussion of shared object versioning 
Message-ID:  <199805231040.UAA02235@troll.dtir.qld.gov.au>
In-Reply-To: <199805211742.KAA18688@usr01.primenet.com> from Terry Lambert at "Thu, 21 May 1998 17:42:41 %2B0000"
References:  <199805211742.KAA18688@usr01.primenet.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thursday, 21st May 1998, Terry Lambert wrote:

>> All I did was add a variable (fake_used) that is incremented every time
>> the __error stand-in (called ___error) is called.  In other words, I
>> instrumented your solution, nothing more.  The instrumentation shows
>> that ___error is called when we expect it not to be called.  This is
>> why I claim that this fix doesn't work.
>
>You renamed the symbol, and didn't reacquire it from a subsequently
>loaded shared library.

I'm sure you have misread my message.  Here is a diff from the test code
you sent on 20 May 1998 03:12:25 +0000 to the test code I sent back on
20 May 1998 17:47:10 +1000:

----------------------------------------------------------------------------
diff -ru terry/errno.h me/errno.h
--- terry/errno.h       Fri May 22 13:11:00 1998
+++ me/errno.h  Fri May 22 13:12:04 1998
@@ -2,7 +2,8 @@
 #include <sys/cdefs.h>
 __BEGIN_DECLS
 int *   __error __P((void));
-static int *___error(void) { extern int errno; return &errno; }
+extern int fake_used;
+static int *___error(void) { extern int errno; fake_used++; return &errno; }
 #pragma weak __error = ___error
 #warning "using a fake errno.h"
 __END_DECLS
diff -ru terry/foo.c me/foo.c
--- terry/foo.c Fri May 22 13:11:12 1998
+++ me/foo.c    Fri May 22 13:22:04 1998
@@ -1,7 +1,10 @@
 #include "errno.h"      /* use hacked errno.h because of paranoia*/
 #include <stdio.h>
 
+int fake_used;
+
 main()
 {
         printf( "default errno is %d\n", errno);
+        printf("fake_used is %d\n", fake_used);
 }
----------------------------------------------------------------------------

All I did was count the number of times ___error() is called.  I didn't
rename the symbol.  Since ___error() is called even when linked with -lc_r
I conclude that __error() in libc_r is not overriding the weak __error
supplied by your modified errno.h.  Thus, threaded applications would
all share the same errno instead of getting one each, which led to my
claim that a more extensive multithreaded test case is required.

>Because libc (or libc_r) is loaded before the libraries which depend on
>its symbols, its weak symbols should take precedence.
>
>Loading should occur in reverse link order.

Having spent a bit of time poking around in rtld just now, I'd say this
is exactly the opposite of what happens.  Proof to follow.

Since I'm hazy on the theory of this, I'm attacking from both angles.
I want to see tests work that should work, and I want to see tests
fail that should fail.  That is not what I see right now.

>> To show it really working (if it does work) would require multiple
>> threads that have different errno values.  Showing one thread having
>> a single errno value is not sufficient.
>
>I don't understand your claim.

See above, a couple paragraphs back.

Here is my first ever pthreads program:
--- thr.c -------------------------------------------------------------------
#include <stdio.h>
#include <pthread.h>
#include <errno.h>

void *doit(void *arg);

int
main(int argc, char **argv)
    {
    pthread_t id1, id2;
    int v1 = 1, v2 = 2;
    void *r1, *r2;

    printf("Starting\n");

    pthread_create(&id1, NULL, doit, &v1);
    pthread_create(&id2, NULL, doit, &v2);

    pthread_join(id1, &r1);
    printf("T1 returned %d\n", (int)r1);

    pthread_join(id2, &r2);
    printf("T2 returned %d\n", (int)r2);

    printf("errno = %d\n", errno);

    return 0;
    }

void *
doit(void *arg)
    {
    int x = *(int *)arg;
    errno = x * 100;
    printf("I'm thread %d, errno = %d\n", x, errno);
    return (void *)x;
    }
-----------------------------------------------------------------------------
When compiled with 'gcc -pthread -o thr -O2 thr.c' on a recent -current,
I get:
-----------------------------------------------------------------------------
Starting
I'm thread 1, errno = 100
T1 returned 1
I'm thread 2, errno = 200
T2 returned 2
errno = 0
-----------------------------------------------------------------------------
When I put your mods in errno.h, I get:
-----------------------------------------------------------------------------
Starting
I'm thread 1, errno = 100
T1 returned 1
I'm thread 2, errno = 200
T2 returned 2
errno = 200
-----------------------------------------------------------------------------

In other words, there is now just one errno because ___error from errno.h
is used in preference to __error in libc_r.

>Have you looked at:
>
>	/usr/src/lib/libc_r/sys/__error.c
>	/usr/src/lib/libc_r/uthread/uthread_seterrno.c

Yes, I've looked at these.  That's why I'm so disappointed that the
technique doesn't work.  Having played with it a bit, I'm now convinced
that no tweaking with errno.h can ever fix the problem.

>I *EXPECT* the the stand-in will be called by programs that are
>*bogusly* NOT relinked against libc, as they should be.

I'm only running the test case.  It is always linked against the current
libc, whatever that is.  I have now run the test case on an April 20
-current (pre errno change), and a more recent -current (post errno change).
Both show that ___error is being called when we want it to be not called.

>For programs *already* linked against libc_r instead of libc, or
>linked against the new libc, I *EXPECT* the standin to *NEVER* be
>called.

Yes!  This is where I claim the experimental evidence is against you.

Spurred by your description of load ordering, I built a small library
(lib__error.so) containing just /usr/src/lib/libc/sys/__errno.c with
an execution counter in __error_unthreaded.  I linked this to a small
test program, using -lc_r as well.

--- foo.c -------------------------------------------------------------------
#include <errno.h>
#include <stdio.h>

int fake_count;

int
main(int argc, char **argv)
    {
    printf("errno is %d\n", errno);
    printf("count is %d\n", fake_count);
    open("/", 1);
    printf("errno is %d\n", errno);
    printf("count is %d\n", fake_count);
    return 0;
    }
-----------------------------------------------------------------------------
Output of ldd:

foo:
	-l__error.0 => /syshome/syssgm/lib/lib__error.so.0.0 (0x20014000)
	-lc_r.3 => /usr/lib/libc_r.so.3.0 (0x20019000)
	-lc.3 => /usr/lib/libc.so.3.1 (0x2009b000)
-----------------------------------------------------------------------------
Output of foo:
-----------------------------------------------------------------------------
errno is 0
count is 1
errno is 21
count is 3
-----------------------------------------------------------------------------

In practice, __error_unthreaded from my lib__error is used instead of
__error from libc_r.  Even without libc_r, my lib__error is used instead
of __error from libc.  Same again on -current from April 20 (before the
errno change).

Now on to a hack that actually works:

-----------------------------------------------------------------------------
--- rtld.c.dist	Wed Feb 11 22:44:02 1998
+++ rtld.c	Sat May 23 19:50:52 1998
@@ -1629,6 +1629,15 @@
 		LM_SYMBOL(smp,RELOC_SYMBOL(&LM_REL(smp)[index]))->nz_strx;
 
 	np = lookup(sym, &src_map, 1);
+#ifdef SGM_HACK
+	if (np == NULL && strcmp(sym, "___error") == 0) {
+		char *path;
+
+		if ((path = rtfindlib("__error", 0, 0)) != NULL)
+		    __dlopen(path, RTLD_LAZY);
+		np = lookup(sym, &src_map, 1);
+	}
+#endif
 	if (np == NULL)
 		errx(1, "Undefined symbol \"%s\" called from %s:%s at %p",
 				sym, main_progname, smp->som_path, jsp);
-----------------------------------------------------------------------------

This hack to binder() in ld.so is at the point where a lazy relocation
fails because the symbol is unknown.  I check for ___error and specially
load lib__error (previously built from lib/libc/sys/__error.c) if this
is indeed the missing symbol.

This hack is incomplete because it doesn't fix non-lazy binding.  I have
not been able to make this fail, especially with my thr.c above, but it
is still early days.  I'll probably make the library path absolute and
remove the rtfindlib() call.  And this might not be the simplest hack yet.

So, for the folks that really care about this, we now have 3 possible
options:

1) back out the errno change, and possibly put it back after ELF.

2) hack ld.so (prototype works fine)

3) bump ALL library major numbers

Which will it be?

Stephen.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805231040.UAA02235>