Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / Virtual Machine / March 2004

Tip: Looking for answers? Try searching our database.

JNI - DetachCurrentThread leads to Signal 11 (SIGSEGV) on Linux

Thread view: 
Reto Stahel - 22 Mar 2004 14:41 GMT
Hi,

I've got a strange JNI threading/signal handling problem. The attached
sample files do exactly reproduce the problem I'm fighting with:

File Descriptions
-----------------
- signaltest.java: This is the main app which starts a thread which itself
calls the native C-function raisesignal(). This native function simply
raises a SIGSEGV.
- raisesignal.cpp: Functions which reside in a shared library. The purpose
of this functions are to install a signal handler for SIGSEGV (Signal 11),
to raise such a signal and to catch and handle the signal correctly. At the
end of the signal handler, the current thread will be stopped with
pthread_exit().
- compile: compile-script which I used to build this sample
- run: run-script to run the sample

This is the effect I'm experiencing only on Linux (I've testet Solaris and
AIX as well, see below):
- All signals are masked while the signal handler is running
- While handling the correctly raised signal 11, the call to
jvm->DetachCurrentThread() raises another signal 11 (but the jvm pointer is
valid) and the signal handler will be invoked recursively forever until the
stack overflows.

This is the output of the sample:

java version "1.4.2_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
Java HotSpot(TM) Client VM (build 1.4.2_03-b02, interpreted mode)
01. Before installing c++ signal handler
02. New c++ signal handler installed for signal SIGSEGV
03. After installing c++ signal handler
04. Wait for Thread to be completed
05. Before java sigtest.raisesignal();
06. Before raise SIGSEGV
07. In signal handler, thread = 131081, handling signal 11
08. SignalHandler: Before detaching current thread
07. In signal handler, thread = 131081, handling signal 11
07. In signal handler, thread = 131081, handling signal 11
07. In signal handler, thread = 131081, handling signal 11

<snip>
07. In signal handler, thread = 131081, handling signal 11
./run: line 3: 13012 Segmentation fault      java -Djava.library.path=.
signaltest

This is the correct output of the same code on Solaris and on AIX:

java version "1.4.2_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
Java HotSpot(TM) Client VM (build 1.4.2_03-b02, interpreted mode)
01. Before installing c++ signal handler
02. New c++ signal handler installed for signal SIGSEGV
03. After installing c++ signal handler
04. Wait for Thread to be completed
05. Before java sigtest.raisesignal();
06. Before raise SIGSEGV
07. In signal handler, thread = 11, handling signal 11
08. SignalHandler: Before detaching current thread
09. SignalHandler: Before canceling current thread
13. Thread completed, we're done.

Remarks:
- If I leave out the DetachCurrentThread() call, the thread never stops and
therefore the call t1.join(); will never return.
- I already tested several Java versions (1.3.1, 1.4.1, 1.4.2), all of then
showed the same effect.
- I tested it with and without JIT

Now my questions are:
1. Why does jvm->DetachCurrentThread() raise a signal 11?
2. Why is the signal mask for SIGSEGV (on Linux) not working?

Thanks for any help
Reto
Signature

Remove nsp- for email

Reto Stahel - 22 Mar 2004 14:45 GMT
> Hi,
>
> I've got a strange JNI threading/signal handling problem. The attached
> sample files do exactly reproduce the problem I'm fighting with:

It seems that the attachments get deleted on certain systems, so here is the
code:

***
* signaltest.java
***
import java.lang.*;

class signaltest {
public native void installsignalhandler();
public native void raisesignal();

public void throwexception(){
 signaltest sigtest = null;
 // The following code will throw a null pointer exception
 sigtest.raisesignal();
}

public static void main(String[] args) {

 System.out.println("01. Before installing c++ signal handler" );
 signaltest sigtest = new signaltest();
 sigtest.installsignalhandler();
 System.out.println("03. After installing c++ signal handler" );

 worker w1 = new worker(sigtest);
 Thread t1 = new Thread(w1);
 t1.start();

 System.out.println("04. Wait for Thread to be completed");
 try{
  t1.join();
 }catch(java.lang.InterruptedException ex){
  System.out.println("Thread interrupted, ex=" + ex);
 }
 System.out.println("13. Thread completed, we're done.");

}
static {
 System.loadLibrary("raisesignal");
}
}

class worker implements Runnable  {

private signaltest m_sigtest;

worker(signaltest sigtest) {
 m_sigtest = sigtest;
}

public void run ()  {
 System.out.println("05. Before java sigtest.raisesignal();" );
 m_sigtest.raisesignal();
 System.out.println("12. After java sigtest.raisesignal();" );
}
}

***
* raisesignal.cpp
***
#include <jni.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>

#include "signaltest.h"

struct sigaction oldHandlerSIGSEGV;

JavaVM *jvm = NULL;

void sh( int i, siginfo_t *siginfo, void *context )
{
JNIEnv *env = NULL;

fprintf(stdout, "07. In signal handler, thread = %d, handling signal %d\n",
pthread_self(), i); fflush(stdout);

jvm->AttachCurrentThread((void**)&env, NULL);

if (env == NULL){
 fprintf(stdout, "env is NULL!\n"); fflush(stdout);
}else{
 if (env->ExceptionOccurred()){
  env->ExceptionDescribe();
  env->ExceptionClear();
 }
}

fprintf(stdout, "08. SignalHandler: Before detaching current thread\n");
fflush(stdout);

jvm->DetachCurrentThread();

fprintf(stdout, "09. SignalHandler: Before canceling current thread\n");
fflush(stdout);

void* retval;
pthread_exit(retval);

fprintf(stdout, "10. SignalHandler: Before leaving signal handler\n");
fflush(stdout);
}

JNIEXPORT void JNICALL Java_signaltest_raisesignal(JNIEnv *env, jobject
obj){
printf( "06. Before raise SIGSEGV\n" );

raise(SIGSEGV);

printf( "11. After raise SIGSEGV\n" );

return;
}

JNIEXPORT void JNICALL Java_signaltest_installsignalhandler(JNIEnv *env,
jobject obj)
{
struct sigaction sigActSIGSEGV;
int status;

// acquire a pointer to the Java VM and cache it globally
env->GetJavaVM( &jvm );

////
//Install my SignalHandler for signals
////
sigActSIGSEGV.sa_handler   = 0;                // set to 0 since we are
using sa_sigaction
sigActSIGSEGV.sa_sigaction = sh;     // Our signal handler
sigfillset( &sigActSIGSEGV.sa_mask );          // Disable all signals for
our handler
sigActSIGSEGV.sa_flags = SA_SIGINFO;         // sa_sigaction specifies the
handler

status = sigaction( SIGSEGV, &sigActSIGSEGV, &oldHandlerSIGSEGV );
if (status != 0) {
 perror("Failed to install handler for signal SIGSEGV");
 return;
}

printf("02. New c++ signal handler installed for signal SIGSEGV\n");

return;
}

***
* compile
***
javac signaltest.java
javah -jni signaltest
g++ -shared -I $JDK_HOME/include -I $JDK_HOME/include/linux/ -o
libraisesignal.so raisesignal.cpp

***
* run
***
java -Xint  -version

java -Djava.library.path=. signaltest

> File Descriptions
> -----------------
[quoted text clipped - 68 lines]
> Thanks for any help
> Reto
Juergen Kreileder - 22 Mar 2004 21:29 GMT
>> I've got a strange JNI threading/signal handling problem. The
>> attached sample files do exactly reproduce the problem I'm fighting
>> with:

I haven't looked at the rest of your code but this is already bogus:

> void sh( int i, siginfo_t *siginfo, void *context )
> {
[quoted text clipped - 6 lines]
>
> if (env == NULL){

[...]

Calling anything but async-signal safe functions (see
http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_04.html#tag_0
2_04_03
)
from a signal handler is unsafe.

Also note that HotSpot handles some signals (e.g. SIGSEGV) internally
by default.  See
http://java.sun.com/j2se/1.4.2/docs/guide/vm/signal-chaining.html

       Juergen

Signature

Juergen Kreileder, Blackdown Java-Linux Team
http://www.blackdown.org/java-linux/java2-status/

Reto Stahel - 23 Mar 2004 14:49 GMT
> Calling anything but async-signal safe functions (see

http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_04.html#tag_0
2_04_03
)
> from a signal handler is unsafe.

I know but unfortunately we must be able to cancel only the thread which
raised the signal, so at least the calls to DetachCurrentThread() and
pthread_exit() must be made. The point is that we don't want to recycle the
server application everytime a signal happens, even if it's a SIGSEGV,
because even the rare SIGSEGV will most likely come from a dereferenced
NULL-pointer which didn't do any harm to the rest of the server application.

I also know that the best way to handle such things is of course to check
pointers before using them, but we're talking about hunderts of thausends of
lines of existing code which must be stabilized without beeing changed too
much.

Is there a better (say safer) method to cancel the current thread in case of
a signal?

Thanks,
Reto
Juergen Kreileder - 23 Mar 2004 22:09 GMT
>> Calling anything but async-signal safe functions (see
>>
[quoted text clipped - 4 lines]
> which raised the signal, so at least the calls to
> DetachCurrentThread() and pthread_exit() must be made.

You can't do that reliable in a signal handler.

> The point is that we don't want to recycle the server application
> everytime a signal happens, even if it's a SIGSEGV, because even the
[quoted text clipped - 8 lines]
> Is there a better (say safer) method to cancel the current thread in
> case of a signal?

Move your cleanup code to some function.  In the signal handler change
the pc to that cleanup function and return.
I.e. on x86, do something like:

void cleanup(void)
{
   ...
}

void handler(int sig, siginfo_t *info, void *uc)
{
   ucontext_t *context = (ucontext_t *) uc;
   context->uc_mcontext.gregs[REG_EIP] = (greg_t) cleanup;
}

       Juergen

Signature

Juergen Kreileder, Blackdown Java-Linux Team
http://www.blackdown.org/java-linux/java2-status/

Reto Stahel - 24 Mar 2004 10:20 GMT
> > Is there a better (say safer) method to cancel the current thread in
> > case of a signal?
[quoted text clipped - 13 lines]
>     context->uc_mcontext.gregs[REG_EIP] = (greg_t) cleanup;
> }

Thanks for your idea. I did exactly as above but the symptons are exactly
the same, so the call "jvm->DetachCurrentThread()" raises signal 11 again
and again. And if I don't detach the current thread, the thread justs stays
even after the call to pthread_exit (I did check that both with "ps -FH" and
with printing out the current Java Threads).
So it seems not to be a problem of unsafe/unreliable functions called in
signal handler, but what it is instead?

Thanks,
Reto


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.