Bug 269 - PPC64 bit longjmp doesn't establish saved TOC properly
Summary: PPC64 bit longjmp doesn't establish saved TOC properly
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.3
: P2 normal
Target Milestone: ---
Assignee: GOTO Masanori
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-07-16 17:29 UTC by Steven Munroe
Modified: 2019-04-10 11:11 UTC (History)
2 users (show)

See Also:
Host: powerpc64--linux
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steven Munroe 2004-07-16 17:29:57 UTC
Mark Mendell <mendell@ca.ibm.com> reports:

Hardware Environment:
p690 (actually any 64 bit PPC)

Software Environment:
RHEL 3 QU2 and SLES9 RC5

Steps to Reproduce:
1. t.c:
#include <setjmp.h>

jmp_buf buf1;
jmp_buf buf2;
int *p;
int n_x = 6;

static int g_counter = 0;
#define g(x) \
{		\
  int a[n_x], i;  \
  g_counter++;  \
  p = &a[0];	\
  if( g_counter < 5 ) longjmp(buf1, 2);  \
  else if( g_counter == 5 ) longjmp(buf1, 101);  \
  else { setjmp(buf2); longjmp(buf1, 101); }  \
}

int f(int n)
{
  static int counter = 0;
  int i;


  if( setjmp(buf1) != 101 ) {
    g(6);
  }

  if( counter == 0 ) {
    counter++;
    g(6);
  }

  if( counter == 1 ) {
    counter++;
    longjmp(buf2, 2);
  }

  return n;
}

int main( )
{
  f(6);
}

2. gcc -m64 t.c; a.out

Actual Results:
Segmentation fault

Expected Results:
<none>

Additional Information:

This is a previously seen problem with longjmp on AIX.  It is essential that 
longjmp store gpr2 at 40(sp) before returning to the user program.  This is 
because the call to setjmp is probably followed by a reload of gpr2.  If an
alloca (or VLA in C99) has been done between the setjmp and the longjmp, then
the saved TOC at 40(sp) may not be set.  The easiest fix is to add
'std r2,40(r1)' to the end of longjmp just before returning to the user code.

This was actually seen with a similar program compiled with xlc at -O4, but
I rewrote it for general distribution.
Comment 1 Steven Munroe 2004-07-16 17:38:53 UTC
This test messes with the stack pointer by dynamically allocating automatic
storage. So by the time longjmp (buf2, 2) the orginal TOC save area has been
clobbered by the stack extention. 

Either way if the solution is to have longjmp restore the TOC save area 
__longjmp must abtain the orginal TOC value before the call to setjmp. 

In this (simple) case the appl calls [bsd]_setjmp() which transfers to 
__setjmp.  Both are in libc.so.  So by the time __setjmp() gets control 
libc.so's TOC is already loaded.  In this case we need to reach back into the 
callers frame and retrieve the callers TOC from the TOC save area. But in the 
static case the TOC is not saved and has not changed.

In GLIBC sysdeps/powerpc/powerpc64/setjmp.S is built 4 times (static, shared,
profiled, and a special version (rtld-setjmp) for the dynamic linker.  In the 
SHARED case (libc.so), external calls to setjmp will save the TOC on the 
stack, but internal libc calls will not.  So the trick is to do the correct 
thing for each case.
Comment 2 Steven Munroe 2004-07-16 18:10:21 UTC
Patch submitted to libc-alpha.

http://sources.redhat.com/ml/libc-alpha/2004-07/msg00048.html
Comment 3 Sourceware Commits 2004-07-16 23:08:31 UTC
Subject: Bug 269

CVSROOT:	/cvs/glibc
Module name:	libc
Changes by:	drepper@sources.redhat.com	2004-07-16 23:08:13

Added files:
	setjmp         : bug269-setjmp.c 

Log message:
	Test for setjmp problem on ppc64 (bz 269).

Patches:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/setjmp/bug269-setjmp.c.diff?cvsroot=glibc&r1=NONE&r2=1.1

Comment 4 Jakub Jelinek 2004-07-23 13:38:55 UTC
Fixed in CVS.