FULL PRODUCT VERSION :
[dani@youwish javastack]$ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Server VM (build 14.0-b16, mixed mode)
also occurs with 1.6.0_07 (and probably any other version since libjsig.so was introduced)
FULL OS VERSION :
Red Hat Enterprise Linux ES release 4 (Nahant Update 8):
Linux youwish.esri.com 2.6.9-89.ELsmp #1 SMP Mon Apr 20 10:34:33 EDT 2009 i686 i686 i386 GNU/Linux
Red Hat Enterprise Linux Server release 5.3 (Tikanga):
Linux RHEL5VM0 2.6.18-128.el5 #1 SMP Wed Dec 17 11:42:39 EST 2008 i686 i686 i386 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When libjsig.so is preloaded, the SA_ONSTACK flag to sigaction() is ignored, so sigaltstack() does not work.
THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try
THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
paste the following into a script and run:
#!/bin/sh
PATH=$JAVA_HOME/bin:$PATH
LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
export PATH
export LD_LIBRARY_PATH
javac test.java
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -shared -o libtest.so test.c
LD_PRELOAD=$JAVA_HOME/jre/lib/i386/libjsig.so
export LD_PRELOAD
echo "LD_PRELOAD: $LD_PRELOAD"
java test onstack
java test notonstack
echo "LD_PRELOAD unset:"
unset LD_PRELOAD
java test onstack
EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual behavior:
LD_PRELOAD: /youwish1/Linux/jdk1.6.0/jre/lib/i386/libjsig.so
using SA_ONSTACK: sigaltstack ss = 0x08108c40, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
NOT using SA_ONSTACK: sigaltstack ss = 0x08108c20, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
LD_PRELOAD unset:
using SA_ONSTACK: sigaltstack ss = 0x08108b90, signal handler ss = 0x0810a804, siginfo = 0x0810a820
Expected behavior: When libjsig.so is preloaded, the signal handler uses the given stack provided in sigaltstack(). So the above results would look something kinda like:
LD_PRELOAD: /youwish1/Linux/jdk1.6.0/jre/lib/i386/libjsig.so
using SA_ONSTACK: sigaltstack ss = 0x08108c40, signal handler ss = 0x810A8B4, siginfo = 0x810A8CC
NOT using SA_ONSTACK: sigaltstack ss = 0x08108c20, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
LD_PRELOAD unset:
using SA_ONSTACK: sigaltstack ss = 0x08108b90, signal handler ss = 0x0810a804, siginfo = 0x0810a820
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
3 files are needed: test.java, test.c, test.h
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.java:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class test
{
static private native void doit(int use_onstack);
static {
System.loadLibrary("test");
}
static public void main(String args[])
{
int use_onstack = 0;
if( args.length != 1 ) {
System.out.println("usage: java test <onstack|anything else>");
System.out.println("\tonstack - use SA_ONSTACK/sigaltstack()");
System.out.println("\tanything else - don't use SA_ONSTACK/sigaltstack()");
return;
}
if( args[0].equalsIgnoreCase("onstack") )
use_onstack = 1;
doit(use_onstack);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.c:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "test.h"
#define GET_STACK( x ) __asm__ __volatile("movl %%esp, %0\n\t" : "=q" (x) : :"%0" )
void the_handler(int sig, siginfo_t *info, void *context) {
unsigned long ss_sp;
struct ucontext_t *ctx = (struct ucontext_t *)context;
GET_STACK( ss_sp );
printf("signal handler ss = 0x%08x, siginfo = 0x%08x\n", ss_sp, info);
exit(0);
}
/*
* Class: test
* Method: doit
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_test_doit(JNIEnv *env, jclass cls, jint use_onstack) {
int ret = 0;
struct sigaction sa = {0};
struct sigaltstack sas = {0};
sas.ss_sp = malloc(SIGSTKSZ);
sas.ss_size = SIGSTKSZ;
ret = sigaltstack(&sas, NULL);
printf("%s SA_ONSTACK: sigaltstack ss = 0x%08x, ", use_onstack ? " using" : "NOT using", sas.ss_sp);
sa.sa_sigaction = the_handler;
sa.sa_flags = SA_SIGINFO;
if( use_onstack )
sa.sa_flags |= SA_ONSTACK;
ret = sigaction(11, &sa, 0);
raise(SIGSEGV);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.h: (or just run javah test)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test */
#ifndef _Included_test
#define _Included_test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test
* Method: doit
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_test_doit
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I modified the openjdk jsig.c to pass the flag and built my own custom libjsig.so which seems to work. However, I'm not sure this is the cleanest solution.
[dani@youwish javastack]$ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Server VM (build 14.0-b16, mixed mode)
also occurs with 1.6.0_07 (and probably any other version since libjsig.so was introduced)
FULL OS VERSION :
Red Hat Enterprise Linux ES release 4 (Nahant Update 8):
Linux youwish.esri.com 2.6.9-89.ELsmp #1 SMP Mon Apr 20 10:34:33 EDT 2009 i686 i686 i386 GNU/Linux
Red Hat Enterprise Linux Server release 5.3 (Tikanga):
Linux RHEL5VM0 2.6.18-128.el5 #1 SMP Wed Dec 17 11:42:39 EST 2008 i686 i686 i386 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When libjsig.so is preloaded, the SA_ONSTACK flag to sigaction() is ignored, so sigaltstack() does not work.
THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try
THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
paste the following into a script and run:
#!/bin/sh
PATH=$JAVA_HOME/bin:$PATH
LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
export PATH
export LD_LIBRARY_PATH
javac test.java
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -shared -o libtest.so test.c
LD_PRELOAD=$JAVA_HOME/jre/lib/i386/libjsig.so
export LD_PRELOAD
echo "LD_PRELOAD: $LD_PRELOAD"
java test onstack
java test notonstack
echo "LD_PRELOAD unset:"
unset LD_PRELOAD
java test onstack
EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual behavior:
LD_PRELOAD: /youwish1/Linux/jdk1.6.0/jre/lib/i386/libjsig.so
using SA_ONSTACK: sigaltstack ss = 0x08108c40, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
NOT using SA_ONSTACK: sigaltstack ss = 0x08108c20, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
LD_PRELOAD unset:
using SA_ONSTACK: sigaltstack ss = 0x08108b90, signal handler ss = 0x0810a804, siginfo = 0x0810a820
Expected behavior: When libjsig.so is preloaded, the signal handler uses the given stack provided in sigaltstack(). So the above results would look something kinda like:
LD_PRELOAD: /youwish1/Linux/jdk1.6.0/jre/lib/i386/libjsig.so
using SA_ONSTACK: sigaltstack ss = 0x08108c40, signal handler ss = 0x810A8B4, siginfo = 0x810A8CC
NOT using SA_ONSTACK: sigaltstack ss = 0x08108c20, signal handler ss = 0xb74b387c, siginfo = 0xb74b3b98
LD_PRELOAD unset:
using SA_ONSTACK: sigaltstack ss = 0x08108b90, signal handler ss = 0x0810a804, siginfo = 0x0810a820
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
3 files are needed: test.java, test.c, test.h
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.java:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class test
{
static private native void doit(int use_onstack);
static {
System.loadLibrary("test");
}
static public void main(String args[])
{
int use_onstack = 0;
if( args.length != 1 ) {
System.out.println("usage: java test <onstack|anything else>");
System.out.println("\tonstack - use SA_ONSTACK/sigaltstack()");
System.out.println("\tanything else - don't use SA_ONSTACK/sigaltstack()");
return;
}
if( args[0].equalsIgnoreCase("onstack") )
use_onstack = 1;
doit(use_onstack);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.c:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "test.h"
#define GET_STACK( x ) __asm__ __volatile("movl %%esp, %0\n\t" : "=q" (x) : :"%0" )
void the_handler(int sig, siginfo_t *info, void *context) {
unsigned long ss_sp;
struct ucontext_t *ctx = (struct ucontext_t *)context;
GET_STACK( ss_sp );
printf("signal handler ss = 0x%08x, siginfo = 0x%08x\n", ss_sp, info);
exit(0);
}
/*
* Class: test
* Method: doit
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_test_doit(JNIEnv *env, jclass cls, jint use_onstack) {
int ret = 0;
struct sigaction sa = {0};
struct sigaltstack sas = {0};
sas.ss_sp = malloc(SIGSTKSZ);
sas.ss_size = SIGSTKSZ;
ret = sigaltstack(&sas, NULL);
printf("%s SA_ONSTACK: sigaltstack ss = 0x%08x, ", use_onstack ? " using" : "NOT using", sas.ss_sp);
sa.sa_sigaction = the_handler;
sa.sa_flags = SA_SIGINFO;
if( use_onstack )
sa.sa_flags |= SA_ONSTACK;
ret = sigaction(11, &sa, 0);
raise(SIGSEGV);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
test.h: (or just run javah test)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test */
#ifndef _Included_test
#define _Included_test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test
* Method: doit
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_test_doit
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I modified the openjdk jsig.c to pass the flag and built my own custom libjsig.so which seems to work. However, I'm not sure this is the cleanest solution.