From nobody  Wed Oct 22 13:59:25 1997
Received: (from nobody@localhost)
          by hub.freebsd.org (8.8.7/8.8.7) id NAA27302;
          Wed, 22 Oct 1997 13:59:25 -0700 (PDT)
          (envelope-from nobody)
Message-Id: <199710222059.NAA27302@hub.freebsd.org>
Date: Wed, 22 Oct 1997 13:59:25 -0700 (PDT)
From: tadhunt@bell-labs.com
To: freebsd-gnats-submit@freebsd.org
Subject: libc_r, buggy setjmp implementation (rookie error)
X-Send-Pr-Version: www-1.0

>Number:         4826
>Category:       i386
>Synopsis:       libc_r, buggy setjmp implementation (rookie error)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jb
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Oct 22 14:00:01 PDT 1997
>Closed-Date:    Tue Apr 28 22:56:57 PDT 1998
>Last-Modified:  Tue Apr 28 22:58:34 PDT 1998
>Originator:     Tad Hunt
>Release:        2.2.5-971018-BETA
>Organization:
Lucent Technologies, Bell Labs
>Environment:
doesn't matter.  It's not specific to a particular version of FreeBSD,
it's incorrect implementation of a library...

>Description:
 
    I was looking at the libc_r implementation of setjmp
(lib/libc_r/uthread/uthread_setjmp.c) from (FreeBSD-2.2.5-101897)

from lib/libc_r/uthread/uthread_setjmp.c:
int
setjmp(jmp_buf env)
{
	return (_thread_sys_setjmp(env));
}

where _thread_sys_setjmp is implemented in lib/libc/i386/gen/setjmp.S
as something like the following:

#ifdef _THREAD_SAFE
ENTRY(_thread_sys_setjmp)
#else
        ENTRY(setjmp)
        #endif
        [... essentially the same implementation for both cases, except
         for some signal stuff]
 
In the case of threaded programs calling setjmp() (instead of calling
_thread_sys_setjmp()) the wrong environment gets saved in the jmp_buf.
When longjmp does it's work, it returns into setjmp() (instead of returning
into the caller of setjmp().  Essentially the following is happening:
 
        jmp_buf foo;
        main()
        {
            bar();
            longjmp(foo, 1);
        }
 
        bar()
        {
            setjmp(foo);
        }
 
-Tad
 

>How-To-Repeat:

% gcc -static foo.c -lc_r
% ./a.out
Memory Fault (core dumped)
%

foo.c:

#include <pthread.h>
#include <setjmp.h>

jmp_buf j;

void
main(void)
{
	if(setjmp(j)) {
		printf("setjmp returned the second time\n");
		exit(1);
	}
	longjmp(j, 69);
}
>Fix:
diff lib/libc/i386/gen/setjmp.orig.S lib/libc/i386/gen/setjmp.S
59,30d58
< #else
< ENTRY(setjmp)
61a60
> ENTRY(setjmp)
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jb 
Responsible-Changed-By: hoek 
Responsible-Changed-When: Sun Mar 22 21:39:06 PST 1998 
Responsible-Changed-Why:  
s/libc_r/threads/ 
State-Changed-From-To: open->closed 
State-Changed-By: jb 
State-Changed-When: Tue Apr 28 22:56:57 PDT 1998 
State-Changed-Why:  
The wrappers will be removed in a commit RSN. Using setjmp etc in 
a user-threaded program will likely end in tears, though. 
>Unformatted:
