Bizarre InterruptedException thrown if threads are interrupted

Discussion in 'Java' started by Daniel, Dec 3, 2003.

  1. Daniel

    Daniel Guest

    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.
     
    Daniel, Dec 3, 2003
    #1
    1. Advertising

  2. Daniel

    xarax Guest

    Sigh...

    "Daniel" <> wrote in message
    news:...
    > 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: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!
     
    xarax, Dec 3, 2003
    #2
    1. Advertising

  3. Daniel

    Chris Uppal Guest

    Daniel wrote:

    > 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
     
    Chris Uppal, Dec 3, 2003
    #3
  4. Daniel

    Daniel Guest

    "xarax" <> wrote in message news:<bvlzb.26612$>...
    > Sigh...


    Sigh? What is that for..?

    > > 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.
    >


    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.

    > > 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.
    >


    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.

    > > 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.
    >


    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
     
    Daniel, Dec 5, 2003
    #4
  5. Daniel

    Daniel Guest

    Hi Chris,

    "Chris Uppal" <-THIS.org> wrote in message news:<3fcdee5b$0$92729$>...

    > 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.

    >
    > > 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.


    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
     
    Daniel, Dec 5, 2003
    #5
  6. Daniel

    Chris Uppal Guest

    Daniel wrote:

    > 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
     
    Chris Uppal, Dec 5, 2003
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Russell Gold

    InterruptedException and I/O?

    Russell Gold, Feb 12, 2004, in forum: Java
    Replies:
    3
    Views:
    1,387
    Chris Smith
    Feb 13, 2004
  2. Ben_
    Replies:
    2
    Views:
    12,682
    Ugo Matrangolo
    Jan 11, 2006
  3. Replies:
    1
    Views:
    763
    Andrew Thompson
    Jul 20, 2006
  4. puzzlecracker
    Replies:
    3
    Views:
    437
    Szabolcs Ferenczi
    May 12, 2008
  5. Alessio Stalla

    Re: InterruptedException handling

    Alessio Stalla, Sep 4, 2009, in forum: Java
    Replies:
    1
    Views:
    454
Loading...

Share This Page