-
Notifications
You must be signed in to change notification settings - Fork 159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove Desc<JClass> implementation for JObject and &JObject #412
Conversation
2d35279
to
ca7097c
Compare
That's probably because the tests use
Have you tried that? I would expect it to fail reliably without UB when
True, but note that it is possible to get a |
I didn't try it out yet - I just noticed that specific restriction when I ended up looking at the spec for It sounds quite likely that we'd get a reliable runtime error via the MethodID lookup, like you say, which would be convenient here so there wouldn't be any need to have other explicit checks that he class isn't an array class. |
It was surprising that these called `.get_object_class()` and let code pass object instances in place of any class argument. A simpler implementation that would instead transmute the reference from a JObject to a JClass (like GlobalRef does) would make it too easy to pass an instance as a class which can lead to undefined behaviour for some JNI apis (such as JNIEnv::new_object()) Fixes: jni-rs#118
This test verifies that we get a safe, runtime error if we try and instantiate an array object via `env.new_object()` considering that the JNI spec states that `NewObjectA` "must not refer to an array class". Our expectation is that `env.new_object` will never get as far as calling `NewObjectA` in this case since it will first fail to find any constructor `MethodId` for an array class; consistent with how Java's `Class::getConstructors()` method doesn't expose array class constructors.
ca7097c
to
fe30084
Compare
I've added a test that confirms that |
Just a quick ping @argv-minus-one - any objection to me landing this PR now? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. Looks good to me.
It was surprising that these called
.get_object_class()
and let code pass object instances in place of any class argument.A simpler implementation that would instead transmute the reference from a
JObject
to aJClass
(likeGlobalRef
does) would make it too easy to pass an instance as a class which can lead to undefined behaviour for some JNI apis (such asJNIEnv::new_object()
)Fixes: #118
--
For reference; I looked at adding a unit test to verify that you can't just pass an instance as a class any more but realized that doesn't just lead to a recoverable jni error / exception - it's undefined behaviour (at least for
NewObjectA
) and trying this I see an error like:FATAL ERROR in native method: JNI received a class argument that is not a class
and the process aborts.Although it's not something changed by this PR; it seems worth highlighting that currently "safe" APIs like like
new_object
don't double check that a givenJClass
really corresponds to a class, even though they could trigger undefined behaviour if that's not the case. (further it's also notable thatNewObjectA
additionally requires that the class "must not refer to an array class" which isn't something that's checked)That should generally be OK since it shouldn't really be possible to get a
JClass
that isn't a class without unsafe code but one exception to that currently is theDesc<JClass>
implementation forGlobalRef
that simply assumes its safe totransmute
the global reference into aJClass
(and so passing a global reference to an instance toJNIEnv::new_object
can lead to undefined behaviour - with or without this change.)We have discussed before that
GlobalRef
should ideally be revised at some point to not erase the type of reference it holds, and that could go some way to making things safer here.A bit of a side thought, but considering the overlooked requirement foredit: (redundant sinceNewObjectA
that the class "must not refer to an array class" makes me wonder ifnew_object
should perhaps have its own wrapper type for a validatedJClass
that would additionally validate the class isn't an array but also allow the reference to be cached via aGlobalRef
(that wouldn't erase the type) so this validation wouldn't need to be repeated if instantiating the same type. (This is just thinking out loud for something that should be dealt with as a separate issue though imho)NewObjectA
won't be reached before failing to find an array class constructor)Definition of Done