Bizarre InterruptedException thrown if threads are interrupted

D

Daniel

Hi,

I've just run into some really strange behavior with the Sun JVM
(using Java 1.4.2 on Windows). If I have a few threads performing
certain security or JCE operations simultaneously (e.g. generating key
pairs), and if one or more of those threads' state is "interrupted",
then I receive an InterruptedException out of the blue! I'm not sure
if this problem is limited to the JCA/JCE or not.. it doesn't seem to
be cryptography-related to me. The following short program illustrates
the problem:

import java.security.KeyPairGenerator;

public class GenerateKeyTest extends Thread
{
public void run()
{
try
{
interrupt(); // Comment out this line and it works OK
System.out.println("About to generate keys");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kpg.generateKeyPair();
System.out.println("Keys successfully generated");
}
catch (Exception e)
{
e.printStackTrace();
}
}

public static void main(String[] args)
{
for (int i = 0; i < 5; i++)
new GenerateKeyTest().start();
}
}


It simply generates 5 key pairs "simultaneously" in 5 different
threads. It works fine if the threads are not interrupted, but if you
call interrupt() before doing the operation (as in the above program),
the following exception stack trace results:


java.lang.InterruptedException
at COM.rsa.jsafe.SunJSSE_df.j(DashoA6275)
at COM.rsa.jsafe.SunJSSE_df.c(DashoA6275)
at com.sun.net.ssl.internal.ssl.JS_KeyPairGenerator.generateKeyPair(DashoA6275)
at java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:475)
at GenerateKeyTest.run(GenerateKeyTest.java:13)


My two main questions are:

1) Has anyone run into this before, or does anyone have any idea what
can possibly be going on here?

2) Can such behavior even "legally" happen in Java?
InterruptedException is a checked exception (i.e. not a
RuntimeException or an Error) so how can it possibly be thrown and
propogate all the way up to my run() method? If any of the methods in
the stack trace threw an InterruptedException, they would have to
declare it in a "throws" clause, and I would be forced to catch it.

If no one has any further insights, I'll file a bug report. Thanks in
advance for any help,

Daniel

P.S. This happens with other JCE calls as well (e.g. Getting a key
factory while performing asymmetric decryption) and possibly in other
scenarios too. It also occurs when using the Bouncy Castle provider
instead of the SunJCE provider.
 
X

xarax

Sigh...

Daniel said:
Hi,

I've just run into some really strange behavior with the Sun JVM
(using Java 1.4.2 on Windows). If I have a few threads performing
certain security or JCE operations simultaneously (e.g. generating key
pairs), and if one or more of those threads' state is "interrupted",
then I receive an InterruptedException out of the blue! I'm not sure
if this problem is limited to the JCA/JCE or not.. it doesn't seem to
be cryptography-related to me. The following short program illustrates
the problem:

import java.security.KeyPairGenerator;

public class GenerateKeyTest extends Thread
{
public void run()
{
try
{
interrupt(); // Comment out this line and it works OK
System.out.println("About to generate keys");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kpg.generateKeyPair();
System.out.println("Keys successfully generated");
}
catch (Exception e)
{
e.printStackTrace();
}
}

public static void main(String[] args)
{
for (int i = 0; i < 5; i++)
new GenerateKeyTest().start();
}
}


It simply generates 5 key pairs "simultaneously" in 5 different
threads. It works fine if the threads are not interrupted, but if you
call interrupt() before doing the operation (as in the above program),
the following exception stack trace results:


java.lang.InterruptedException
at COM.rsa.jsafe.SunJSSE_df.j(DashoA6275)
at COM.rsa.jsafe.SunJSSE_df.c(DashoA6275)
at com.sun.net.ssl.internal.ssl.JS_KeyPairGenerator.generateKeyPair(DashoA6275)
java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:47
5)
at GenerateKeyTest.run(GenerateKeyTest.java:13)


My two main questions are:

1) Has anyone run into this before, or does anyone have any idea what
can possibly be going on here?

Yes, you called interrupt() to interrupt the current Thread.
2) Can such behavior even "legally" happen in Java?
InterruptedException is a checked exception (i.e. not a
RuntimeException or an Error) so how can it possibly be thrown and
propogate all the way up to my run() method? If any of the methods in
the stack trace threw an InterruptedException, they would have to
declare it in a "throws" clause, and I would be forced to catch it.

The run() method doesn't have to declare checked exceptions,
which is why you can encounter such exceptions anywhere in
the callstack of the thread.
If no one has any further insights, I'll file a bug report. Thanks in
advance for any help,

File the bug report to yourself, because it's your code
that's broken.
Daniel

P.S. This happens with other JCE calls as well (e.g. Getting a key
factory while performing asymmetric decryption) and possibly in other
scenarios too. It also occurs when using the Bouncy Castle provider
instead of the SunJCE provider.

The pending interrupt that you created by calling interrupt()
will be thrown at the next opportunity (usually when calling
an I/O service).


--
----------------------------------------------
Jeffrey D. Smith
Farsight Systems Corporation
24 BURLINGTON DRIVE
LONGMONT, CO 80501-6906
http://www.farsight-systems.com
z/Debug debugs your Systems/C programs running on IBM z/OS!
 
C

Chris Uppal

Daniel said:
java.lang.InterruptedException
at COM.rsa.jsafe.SunJSSE_df.j(DashoA6275)
at COM.rsa.jsafe.SunJSSE_df.c(DashoA6275)
at ....
1) Has anyone run into this before, or does anyone have any idea what
can possibly be going on here?

You've set the interupted flag in the thread before you start processing (in
your example code, I don't know how that flag gets set in your real code).
That means that the next time the thread does one of a class of "long lived"
operations it will be interrupted. See the javadoc for Thread.interrupt() for
a list of the operations that check the flag. My guess is that the crypto
stuff is either doing some IO (reading property files or keyrings or something)
or possible doing a wait() while another thread collects entropy, and so the
system is checking the interrupted flag and throwing the exception.

2) Can such behavior even "legally" happen in Java?
InterruptedException is a checked exception (i.e. not a
RuntimeException or an Error) so how can it possibly be thrown and
propogate all the way up to my run() method?

Well, just because the Java compiler would reject code that does this, doesn't
mean that it can't happen. The Java compiler is *not* the same as the JVM and
the compiler's rules are irrelevant at runtime. As it happens the JVM has no
concept of checked exception declarations, so there's nothing to stop code
circumenting the Java *language's* rules. Exactly how it's doing it, I don't
know, but there are many possibilities, for instance it could be being thrown
from JNI.

Just guesses, of course....

-- chris
 
D

Daniel

xarax said:

Sigh? What is that for..?
Yes, you called interrupt() to interrupt the current Thread.

I am unaware of any documentation stating the dangers of leaving a
thread in the interrupted state while calling other API methods. In
fact, the documentation that talks about situations where methods may
catch an unexpected InterruptedException recommends code similar to
the following:

if (Thread.interrupted()) // ignore interrupts while waiting
wasInterrupted = true;
....
if (wasInterrupted) // reassert interrupt status on exit
current.interrupt();

Code such as this is on both Sun's site, as well as Doug Lea's.
The run() method doesn't have to declare checked exceptions,
which is why you can encounter such exceptions anywhere in
the callstack of the thread.

Your argument here is flawed on 2 levels. Firstly, your statement that
the run method doesn't have to declare checked exceptions is
incorrect. Try compiling code for a thread with the following run
method:

public void run()
{
throw new Exception();
}

Secondly, even if your incorrect statement happened to be true, it
does nothing to prove your point. The exception is *not* thrown from
the run() method, but somewhere in the JCA/JCE classes, and these
obviously have to declare any checked exceptions in a throws clause.
The fact that none of the KeyPairGenerator methods are declared to
throw InterruptedException implies that I should not receive it when
calling these methods.
File the bug report to yourself, because it's your code
that's broken.

How about being a little more polite, especially when it's you that
has your facts upside down. I didn't come out here accusing anyone of
anything, I'm just trying to understand the situation better.
The pending interrupt that you created by calling interrupt()
will be thrown at the next opportunity (usually when calling
an I/O service).

No, interrupt() should not affect any normal I/O operations. It will
only affect nio operations, and I'm sure that none of these are being
called (since I have verified this behavior on a 1.1 JVM as well). The
other non-I/O Java operations that an interrupt() will affect are
wait, join, and sleep. All 3 of these are declared to throw an
InterruptedException. Therefore if the exception wasn't being caught
and dealt with (or ignored) at any of the methods between the
exception's source and my run method, then it would have to be
declared in a throws clause in one of the KeyPairGenerator methods
(which it isn't).

Daniel
 
D

Daniel

Hi Chris,

Chris Uppal said:
You've set the interupted flag in the thread before you start processing (in
your example code, I don't know how that flag gets set in your real code).

This is not really a "real-app situation", but something I came across
when doing some testing for a multi-threaded server type app. In the
particular test program, it was not really necessary to "synchronize"
interrupts() with sleeps() and other methods, so there were certain
times where a thread could be in the interrupted state just before
doing a lot of crypto code. In the real app everything is nicely
synchronized, so I don't actually experience this problem. But, as I
mentioned in my reply to Jeffrey, I'm not aware that's it considered
wrong for a thread in the interrupted state to call a Java API method.
Is it? I'd be interested to find any docs on this...
That means that the next time the thread does one of a class of "long lived"
operations it will be interrupted. See the javadoc for Thread.interrupt() for
a list of the operations that check the flag. My guess is that the crypto
stuff is either doing some IO (reading property files or keyrings or something)
or possible doing a wait() while another thread collects entropy, and so the
system is checking the interrupted flag and throwing the exception.

I'm aware of all these situations where an InterruptedException will
be thrown, but none of them seem feasible to me for the following
reason: these methods are all declared to throw an
InterruptedException. This would *have* to be caught and dealt with,
ignored, or reasserted (by calling thread.interrupt()) at the
exception's source, or they would have to be declared in a throws
clause. The fact that none of the KeyPairGenerator methods throw an
InterruptedException means that if an InterruptedException was thrown
for any of these reasons, then it should have been dealt with,
ignored, or reasserted somewhere along the way before coming back to
my run() method.
Well, just because the Java compiler would reject code that does this, doesn't
mean that it can't happen. The Java compiler is *not* the same as the JVM and
the compiler's rules are irrelevant at runtime. As it happens the JVM has no
concept of checked exception declarations, so there's nothing to stop code
circumenting the Java *language's* rules.

Right. Perhaps I was a little vague here.. I know the JVM can do
whatever it wants. My question should have been something along the
lines of "you shouldn't be able to write and compile Java code to do
this, under normal circumstances (i.e. not hacking class files,
etc.)?".
Exactly how it's doing it, I don't
know, but there are many possibilities, for instance it could be being thrown
from JNI.

Yeah I thought about that.. it's a little odd though, since I've also
received this exception with a stack trace originating in the Bouncy
Castle BigInteger class... which is definitely 100% Java. Other than
JNI, I have no other guesses about where it could come from. (I'm not
really sure about JNI either.. one would hope that native methods obey
Java's general exception "rules").
Just guesses, of course....

-- chris

Thanks for your input/guesses Chris :) I still feel this is a bug
since a checked exception shouldn't come from nowhere.. I guess it
just depends on one's point of view.

Regards,
Daniel
 
C

Chris Uppal

Daniel said:
Yeah I thought about that.. it's a little odd though, since I've also
received this exception with a stack trace originating in the Bouncy
Castle BigInteger class... which is definitely 100% Java.

Can you find a (statistically) reproducible case that doesn't use the Java
crypto stuff (which has the disadvantage of being obfuscated) ?

I looked at this a little more, and now I'm as confused as you ;-) The stack
trace you posted doesn't make sense to me at all; the methods in question
aren't doing any IO or anything like it (as far as I can tell through the fog
of obfuscation) and it does indeed look as if the VM is triggering the
exception at a random point in the code.

I tried your example on my system (Sun JDK 1.4.2 / Win XP) and I don't get the
same results as you -- it consistently (more or less) produces:

java.lang.InterruptedException
at
java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:146)
at Test.run(Test.java:12)

However, KeyPairGenerator.getInstance() isn't doing *anything* that could
possibly cause that exception, so I can only presume that the exception is
happening elsewhere (perhaps in a AccessController.doPrivileged() block) and
the reported stack trace is just not properly representing that.

I did find that if I generated a key pair before entering the loop that starts
the threads, then everything works OK, so it must be something to do with the
initialisation phase that's doing something that trips the interrupt.

So, my best guess is as follows:

The initialisation phase of the crypto stuff (by some unguessed-at magic) uses
facilities that trigger the InterruptedException in a context where
Java-the-language wouldn't allow it. Possibly because of the use of that
magic, and quite probably compounded by the use of an
AccessController.doPrivileged() block, the VM is unable to create an accurate
stack trace for the InterruptedException. The exception percolates back out to
your user-level code because nothing traps it (since the checked exception is
not declared, they don't realise they "have" to) where you trap it. When you
print out the stack trace, the results are misleading, suggesting that the
exception was thrown from code that had already executed with no problems.

Ugh!

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,814
Latest member
SpicetreeDigital

Latest Threads

Top