JNI's throw new does not throw an exception

Discussion in 'Java' started by yarona@m-sys.com, Sep 6, 2005.

  1. Guest

    Hi,

    I'm trying to throw an exception from my native C++ code, the code
    snippet looks like this:

    /////////
    jclass clsException = pEnv->FindClass("MyExceptionClass");
    if(clsException )
    {
    pEnv->ThrowNew(clsException, "HelloWorld");
    }
    return;
    /////////

    The 'ThrowNew' method is called, but no exception seems to be thrown or
    caught on the Java side.

    ThrowNew returns 0 if it's any help, and if I call 'ExceptionCheck'
    afterwards, it returns 'true', before that it returns 'false' meaning
    that the exception pending is the one that I have just thrown.

    Any ideas would be appreciated,

    Thanks,

    Yaron
     
    , Sep 6, 2005
    #1
    1. Advertising

  2. On 6 Sep 2005 09:59:07 -0700, wrote:
    > I'm trying to throw an exception from my native C++ code, the code
    > snippet looks like this:
    >
    > /////////
    > jclass clsException = pEnv->FindClass("MyExceptionClass");
    > if(clsException )
    > {
    > pEnv->ThrowNew(clsException, "HelloWorld");
    > }
    > return;
    > /////////
    >
    > The 'ThrowNew' method is called, but no exception seems to be thrown
    > or caught on the Java side.
    >
    > ThrowNew returns 0 if it's any help, and if I call 'ExceptionCheck'
    > afterwards, it returns 'true', before that it returns 'false'
    > meaning that the exception pending is the one that I have just
    > thrown.


    There's nothing wrong with the code you've posted, but there might be
    something wrong in the code you didn't post.

    For example, what is "ExceptionCheck()"? Do you mean
    ExceptionOccurred()?

    Have you tried calling ExceptionDescribe() after ThrowNew() to see
    whether it really is your exception that's been thrown?

    How are you handling this in the caller?

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 6, 2005
    #2
    1. Advertising

  3. Roedy Green Guest

    On 6 Sep 2005 09:59:07 -0700, wrote or quoted :

    >jclass clsException = pEnv->FindClass("MyExceptionClass");
    >if(clsException )
    >{
    > pEnv->ThrowNew(clsException, "HelloWorld");
    >}
    >return;


    Is there a debugger that lets you debug Java when in Java and C++ or
    MASM when in C++?
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 6, 2005
    #3
  4. On Tue, 06 Sep 2005 09:59:07 -0700, yarona wrote:

    >
    > Any ideas would be appreciated,


    I think your problem might be that after a ThrowNew, the native method
    does not abruptly terminate automatically. That is, flow of control
    returns to your native method, and the new exception is pending at this
    point. You need to "abort" your method manually if ExceptionOccurred()
    returns true (or handle the exception in native code, which is something
    i'd call "severe pain").

    --
    You can't run away forever,
    But there's nothing wrong with getting a good head start.
    --- Jim Steinman, "Rock and Roll Dreams Come Through"
     
    Stefan Schulz, Sep 6, 2005
    #4
  5. Roedy Green Guest

    On 6 Sep 2005 09:59:07 -0700, wrote or quoted :

    > pEnv->ThrowNew(clsException, "HelloWorld");


    Insert this after the Throw:

    pEnv->DeleteLocalRef( clsException );

    Your problem basically is that C++ knows nothing about Java
    exceptions. Exceptions are just control blocks lying about. It is up
    to you in some C++ish way, after you set up the exception, return
    quickly and gracefully up the call stack to your caller back in Java
    who can then handle the exception. On your way back, C++ can handle or
    notice the exception by explicitly testing for it with ExceptionCheck.

    In Abundance this is known as a "graceful bailout".


    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 7, 2005
    #5
  6. Roedy Green Guest

    Roedy Green, Sep 7, 2005
    #6
  7. On Tue, 06 Sep 2005 23:01:58 GMT, Roedy Green wrote:
    > On 6 Sep 2005 09:59:07 -0700, wrote or quoted :
    >
    >> pEnv->ThrowNew(clsException, "HelloWorld");

    >
    > Insert this after the Throw:
    >
    > pEnv->DeleteLocalRef( clsException );


    No, don't. There is seldom any need for DeleteLocalRef(), and
    certainly not in this case.

    This is akin to telling him to null method local references before
    returning from a Java method.

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 7, 2005
    #7
  8. Guest

    Hello all, and many thanks for your replies,

    "ExceptionCheck()" is a method which is much like "ExceptionOccured"
    only it returns jboolean rather than a jthrowable.

    I am returning from the native method immidiatly after "ThrowNew" (
    actually I'm calling "ExceptionDescribe" first, and it is my exception
    that is thrown).
    I also put a break point in the exception object's c'tor on the Java
    side, and sure enough it's getting called, meaning that it's being
    created.

    The Java side looks something like this:

    try
    {
    MyThrower thrower = new MyThrower();
    thrower.ExceptionThrowingMethod(); // a native method
    }
    catch(MyExceptionClass e)
    {
    //handle exception
    }

    MyExceptionClass is derived from java.lang.Exception

    But I never reach the catch clause - even though as I've mentioned, the
    "MyExceptionClass" object was constructed.

    Thanks,

    Yaron
     
    , Sep 7, 2005
    #8
  9. On 7 Sep 2005 01:34:10 -0700, wrote:
    > "ExceptionCheck()" is a method which is much like "ExceptionOccured"
    > only it returns jboolean rather than a jthrowable.


    Hmm, I wasn't even aware that that method existed, but I see it now in
    the docs...

    > I am returning from the native method immidiatly after "ThrowNew" (
    > actually I'm calling "ExceptionDescribe" first, and it is my exception
    > that is thrown).


    This could very well be the problem: In my experience,
    ExceptionDescribe() seems to clear the exception, at least sometimes.

    Apparently others have also seen this behaviour:
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4067541

    Try removing these checks from your native code. Just throw the
    exception, then return.

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 7, 2005
    #9
  10. On 7 Sep 2005 08:45:03 +0200, Gordon Beaton wrote:
    > On Tue, 06 Sep 2005 23:01:58 GMT, Roedy Green wrote:
    >> On 6 Sep 2005 09:59:07 -0700, wrote or quoted :
    >>
    >>> pEnv->ThrowNew(clsException, "HelloWorld");

    >>
    >> Insert this after the Throw:
    >>
    >> pEnv->DeleteLocalRef( clsException );

    >
    > No, don't. There is seldom any need for DeleteLocalRef(), and
    > certainly not in this case.


    Additionally, the JNI docs state clearly which JNI functions are safe
    to call when there is a pending exception (as is the case here), and
    DeleteLocalRef() isn't among them:

    http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp17626

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 7, 2005
    #10
  11. Guest

    Also there's no need to call DeleteLocalRef() since I'm running from a
    native method, and not a utility method - the JVM releases all local
    refs for me.
     
    , Sep 7, 2005
    #11
  12. Chris Uppal Guest

    Gordon Beaton wrote:

    > > Insert this after the Throw:
    > >
    > > pEnv->DeleteLocalRef( clsException );

    >
    > No, don't. There is seldom any need for DeleteLocalRef(), and
    > certainly not in this case.


    It's not relevant to this case, but for the record, there is one important
    category of application where DeleteLocalRef() is not optional.

    That is when your application uses JNI to call into Java, rather than the other
    way around. I.e. your main program is written in something like C, and it
    creates a JVM in order to make use of some Java library or other. In such
    cases, the C code that creates the reference has not been called /from/ Java
    so the automatic clean-up of local references does not occur (since that
    happens when the C code returns /to/ Java).

    There are other occasions when you might want to DeleteLocalRef(), but -- as
    Gordon says -- they are atypical. And anyway they are discussed in the JNI
    tutorial and documentation (which is, however, vague on the above point -- the
    writers preferring to pretend that the only reason for using JNI is to call
    "legacy" code from Java, an attitude I find insufferably arrogant).

    I have to make heavy use of the above technique, since I'm using JNI to call
    legacy Java code from Smalltalk...

    -- chris
     
    Chris Uppal, Sep 7, 2005
    #12
  13. On 7 Sep 2005 02:53:48 -0700, wrote:
    > Also there's no need to call DeleteLocalRef() since I'm running from
    > a native method, and not a utility method - the JVM releases all
    > local refs for me.


    I'll assume that "utiltity method" here refers to other methods in
    your native library, i.e. not your native methods themselves, but
    other functions in the native library that might be called by your
    native methods.

    If that's what you mean (and please explain if it isn't), then
    contrary to what you've implied, you wouldn't have needed to use
    DeleteLocalRef() in that case either.

    When a native method is invoked from Java, a local context is created
    to hold all object references created at (or below) that point. When
    you return back to the JVM (and thereby pass that point as you move up
    the stack), the local context is freed and any objects referred to
    (potentially) become eligible for garbage collection.

    So it doesn't matter if you pass the JNIEnv* to a helper function and
    create your objects there instead, as far as the JVM is concerned
    there is no difference.

    Have you solved the original problem?

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 7, 2005
    #13
  14. Guest

    Hi Gordon, thanks for your replies.

    This is going to be long so bare with me, trust me it's interesting :)

    You are correct, When I said "utility functions" I meant helper
    functions in my native code that are called from my native methods.

    You are also correct when you are saying that when returning to the JVM
    all local refs are released, but what happens if I allocate a local ref
    within a helper function, and then return from it to my native method,
    and after that go on doing some more native work? the local refs
    allocated inside the helper would not be released until I return from
    the native method to the JVM, taking up some precious space!!!

    As for the original problem - yes I have solved it, the problem was a
    wierd and suttle one:

    As I've gathered from all the posts here,and the JNI documentation,
    calling JNI functions after a call to ThrowNew, and before returning to
    the JVM is not safe (putting functions like ExceptionOccured and
    ExceptionCheck aside...)

    This means that posting an exception should preferably look like this:

    pEnv->ThrowNew(clsException);
    //no JNI calls here!!!
    return;

    otherwise the exception might never be thrown on the Java side.

    The interesting thing is that my code looks just like the above code(I
    took out the DecribeExceptionCall) - and still no exception - so there
    must have been something between the call to ThreadNew and the return
    that has been implicily put there by the compiler.

    I opened my disassembler, and sure enough I saw what happened:
    I wanted to make my native method thread synchronized, yet release the
    monitor upon an excetpion or returning from the method, in order to
    prevent a deadlock - I didnt want to return from the method and forget
    to call ExitMonitor, so I've written a little guard C++ class:

    class MonitorGuard
    {
    public:
    MonitorGuard(JNIEnv* pEnv, jobject monitor)
    :m_pEnv(pEnv), m_monitor(monitor)
    {
    if(m_pEnv && m_monitor)
    {
    m_pEnv->MonitorEnter(m_monitor);
    }
    }

    ~MonitorGuard()
    {
    if(m_pEnv && m_monitor)
    {
    m_pEnv->ExitMonitor(m_monitor);
    }
    }

    private:
    JNIEnv* m_pEnv;
    jobject m_monitor;
    };

    As you can see this class takes the monitor upon construction, and
    releases it upon destruction, this way, when I return from the native
    method, ExitMonitor is automatically called, and there's no danger for
    a deadlock.

    BUT... I fell in another pittfall, after I do this:

    pEnv->ThrowNew(clsException);
    return;

    the guard's destructor was implicitly called, after ThrowNew, and
    before returning to the JVM, thus calling ExitMonitor, which is
    apparently not included in the functions which are safe to be called
    after ThrowNew - so no exception was thrown.

    I solved it by createing a special scope for the synchronized code,
    throwing the exception outside of it like so:
    ////////////////////////////////////
    bool bThrow = false;
    jclass clsException;
    do
    {
    CMonitorGuard(pEnv, objThis); //objThis is the 'this' object passed
    in the JNI interface.
    //do some native work...
    if(clsException = pEnv->FindClass("MyExceptionClass")
    {
    bThrow = true;
    break;
    }
    //do some more native work;

    }while(0)

    if(bThrow)
    {
    pEnv->ThrowNew(clsException);
    return;
    }
    ///////////////////////////////////////////////////

    And behold, the exception was thrown on the Java side!!! hip hip
    hurray!!!

    That sums it up - JNI has many suttle pit falls, and this is one of
    them - so one has to be carful not to fall in it, be careful of
    implicit JNI code called after ThrowNew!

    Thanks once again for the great help,

    Yaron
     
    , Sep 7, 2005
    #14
  15. On 7 Sep 2005 08:49:50 -0700, wrote:
    > You are also correct when you are saying that when returning to the JVM
    > all local refs are released, but what happens if I allocate a local ref
    > within a helper function, and then return from it to my native method,
    > and after that go on doing some more native work? the local refs
    > allocated inside the helper would not be released until I return from
    > the native method to the JVM, taking up some precious space!!!


    Granted, but in most non-looping code the number of objects created
    this way is usually rather limited, and I'd usually let the JVM handle
    these things automatically for me.

    Still if you want to avoid keeping unused objects around any longer
    than necessary, one suggestion is to wrap those helper functions in
    calls to PushLocalFrame() and PopLocalFrame(), so you at least don't
    need to manage each reference individually.

    [...]

    > I wanted to make my native method thread synchronized, yet release the
    > monitor upon an excetpion or returning from the method, in order to
    > prevent a deadlock - I didnt want to return from the method and forget
    > to call ExitMonitor, so I've written a little guard C++ class:


    Have you considered simply declaring the native method synchronized? I
    realize that only synchronizes among calls to methods on the same
    object, but perhaps that's the case here.

    > As for the original problem - yes I have solved it, the problem was a
    > wierd and suttle one:


    It was, and good work finding the solution!

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Sep 7, 2005
    #15
  16. Roedy Green Guest

    On 7 Sep 2005 11:19:11 +0200, Gordon Beaton <> wrote or
    quoted :

    >Additionally, the JNI docs state clearly which JNI functions are safe
    >to call when there is a pending exception (as is the case here), and
    >DeleteLocalRef() isn't among them:


    Odd. That came straight from Sun's textbook.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 8, 2005
    #16
    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. Kerri
    Replies:
    2
    Views:
    13,034
    Kevin Spencer
    Oct 27, 2003
  2. Jon Maz
    Replies:
    7
    Views:
    4,278
    Jon Maz
    Oct 25, 2004
  3. inquirydog
    Replies:
    21
    Views:
    1,787
    inquirydog
    Sep 11, 2004
  4. Clodoaldo
    Replies:
    4
    Views:
    267
    Jarek Zgoda
    Mar 25, 2008
  5. Emanuele D'Arrigo

    To throw or to throw not?

    Emanuele D'Arrigo, Nov 14, 2008, in forum: Python
    Replies:
    6
    Views:
    321
    Emanuele D'Arrigo
    Nov 15, 2008
Loading...

Share This Page