Subject: port-i386/16842: setjmp()/longjmp() don't recover %fs register
To: None <gnats-bugs@gnats.netbsd.org>
From: None <kent@netbsd.org>
List: netbsd-bugs
Date: 05/16/2002 01:30:34
>Number:         16842
>Category:       port-i386
>Synopsis:       setjmp()/longjmp() don't recover %fs register
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu May 16 01:31:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     TAMURA Kent
>Release:        -current
>Organization:
>Environment:
NetBSD gabi-n.hauN.org 1.5ZC NetBSD 1.5ZC (GABI-N) #1: Fri Apr 12 12:22:33 JST 2002     kent@gabi-n.hauN.org:/home1/n/src/sys/arch/i386/compile/GABI-N i386
>Description:
The function setjmp() does not save %fs register and longjump() does
not restore %fs register.
If the kernl has "options USER_LDT", userland programs can handle LDT
by setting %fs register.  The current behavior of setjmp()/longjmp()
is not suitable for such programs.

>How-To-Repeat:
Run the following code.  The result in -current is:
  1: fs = 31
  2: fs = 0
  3: fs = 0
3: should be 31.

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

static void inline set_fs(int fs) {
    __asm__ volatile ("
        movl %0,%%eax
        movw %%ax,%%fs"
                      : /* no ret */
                      : "r"(fs) /* input */
                      : "%eax");
}

static int inline get_fs() {
    int fs = 0;

    __asm__ volatile ("movl %%fs,%0" : "=r"(fs));
    return fs;
}

int main() {
    int saved_fs;
    jmp_buf env;

    saved_fs = get_fs();
    printf("1: fs = %d\n", get_fs());
    if (0 == setjmp(env)) {
        set_fs(0);
        printf("2: fs = %d\n", get_fs());
        longjmp(env, 1);
    }
    printf("3: fs = %d\n", get_fs());
    return saved_fs != get_fs() ? EXIT_FAILURE : EXIT_SUCCESS;
}

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted: