is this right way of deleteing reference for jclass and jobject
JNIEXPORT void JNICALL Java_method(JNIEnv *env,jobject, jobject objArray)
{
int n = env->GetArrayLength(objArray);
for (int i = 0; i<n ; ++i)
{
jobject sObject = env->GetObjectArrayElement(objArray, i);
jclass sObjectClass = env->GetObjectClass(sObject);
dosomething(sObjectClass, sObject);
env->DeleteLocalRef(sObject);
env->DeleteLocalRef(sObjectClass);
}
Short answer:
Yes it is a right way. The call DeleteLocalRef is not necessary but it is useful if the objArray is big or if the function execution time is long.
Longer answer:
Oracle reference documentation states
Primitive types, such as integers, characters, and so on, are copied
between Java and native code. Arbitrary Java objects, on the other
hand, are passed by reference. The VM must keep track of all objects
that have been passed to the native code, so that these objects are
not freed by the garbage collector. The native code, in turn, must
have a way to inform the VM that it no longer needs the objects. In
addition, the garbage collector must be able to move an object
referred to by the native code.
So any object that native code use must be marked as eligible for garbage collection from native code point of view when native code does need the object anymore. JNI has two types of references - global and local references. The references retrieved from GetObjectArrayElement and GetObjectClass are local because:
All Java objects returned by JNI functions are local references.
VM automatically frees all local references when a native function returns. So it is not necessary to free these references by DeleteLocalRef in most cases because VM frees them automatically.
But if there are a lot of local references required in one function call or the call takes long time then it is worth to free them explicitly immediately when they are not needed and do not wait to function returns. Freeing helps VM to do better memory management.
Related
Upfront disclosure: I think the entire thing is nonsense and "works" by chance, but I found this code and it seems to "work" for low-enough values of work (as in it does not crash when run, which doesn't mean much), and I don't get why.
The issue at hand is an extern "C" API exposed as a DLL/so, which is then called over FFI (by Python in this case), but the extern "C" code uses shared_ptr. And yet it moves.
The C++ code:
#include <memory>
extern "C" {
int make(std::shared_ptr<int> p) {
p = std::make_shared<int>(42);
return 0;
}
int get(std::shared_ptr<int> p) {
return *p;
}
}
the caller:
import ctypes
lib = ctypes.CDLL('lib.so')
p = ctypes.c_void_p()
lib.make(ctypes.byref(p))
print(lib.get(ctypes.byref(p)))
After building the C++ code as a shared library (named lib.so), the Python code runs fine and does print 42. This code was tested on macOS/ARM64 compiled with Clang but the original code this was munged from reportedly works on Linux/ARM32 (compiled with GCC) and Windows/AMD64 (compiled with msvc).
My working hypothesis is that in all these runtimes shared_ptr happens to have the object pointer as first members, and the compilers decide to pass it by reference in order to avoid the copy (and thus incref/decref), thus make writes the object pointer over Python's p, and writes the control block into space (maybe somewhere on the stack). When the shared pointer is freed the memory remains accessible (possibly because it's in a small object pool / page rather than being unmapped).
Then get does not need to touch the refcount (because gain passed by ref) so it just double-derefs our pointer, which is an UAF but the memory is still around and it works out.
Note: in the original there is no UAF because the shared_ptr is obtained from a longer-lived structure, so this simplified version is a touch worse than the original.
Some speculative facts:
A shared_ptr is often 16 bytes (on 64-bit architectures) while void* is 8 bytes. A shared_ptr contains a pointer to the object it refers to, then another pointer to a "control block" containing the refcount and destructor. (This is just one possible implementation of shared_ptr)
Overwriting memory doesn't have to immediately lead to a crash; often the memory allocator even allocates more memory than you ask for (e.g. it may round up to a multiple of 16 bytes)
Non-trivial class types are passed by reference. Yes, really. Just like you wrote & after the type. I'm not making this up. See for example the Itanium ABI on which a lot of ABIs are based. In order to simulate the parameter not being a reference, the caller makes a copy and then destroys it after the call. You didn't.
So, probably: You were meant to pass a reference to a shared_ptr to the make function. You did. The make function overwrote it with a real bona-fide shared_ptr. Then, instead of destroying the object like you were supposed to by the ABI (and thereby making it pretend to not be a reference), you passed the same reference to the get function which read the new value assigned inside make.
Suppose I'm using JNI to call some Java method that returns String, i. e. jstring in native code:
jstring jStr = (jstring)env->CallStaticObjectMethod(myApplicationClass, getString);
Do I then need to call env->DeleteLocalRef(jStr)? I think I do, but I can't find any specific instructions that state so in the JNI reference, and I can see I have a lot of code that doesn't call it - tried and true code. But if there was a minor memory leak, no one would notice since this code doesn't create many objects.
Every local reference you create is automatically freed when your JNI-called function returns to Java.
The JNI specification outlines two cases where you might want to use DeleteLocalRef:
A native method accesses a large Java object, thereby creating a local reference to the Java object. The native method then performs
additional computation before returning to the caller. The local
reference to the large Java object will prevent the object from being
garbage collected, even if the object is no longer used in the
remainder of the computation.
In other words, if you allocated a multi-megabyte string and no longer need it, you can delete the reference immediately, instead of leaving it to the JVM when you return to it. However, this is only useful if you need to perform additional steps in the JNI world before returning.
Note that this situations talks about a JNI function that is called from Java.
By attaching native threads to the JVM you can end up in the reverse situation, where your native code calls into the JVM. In that situation the JVM will not auto-free your local references and you need to delete local references yourself.
As a concrete example of that case, all the local references created in this function in the JNI cookbook will linger; they are never cleaned up manually.
A native method creates a large number of local references, although not all of them are used at the same time. Since the VM needs
a certain amount of space to keep track of a local reference, creating
too many local references may cause the system to run out of memory.
For example, a native method loops through a large array of objects,
retrieves the elements as local references, and operates on one
element at each iteration. After each iteration, the programmer no
longer needs the local reference to the array element.
This one is simpler: there is an upper limit to the number of local references.
Yes you must dispose the local references returned by Java callbacks. The standard rules apply: instead of DeleteLocalRef(), you can use PushLocalFrame()/PopLocalFrame(), or the local reference will be released automatically when the thread is detached from JVM, or the native method returns to Java (if this happens inside a native method).
I'm using the JNI Invocation API in an attempt to wrap a Java library in C++.
My C++ classes are essentially containers for JNI jobjects with setter/getter methods to call JNI and retrieve data from said jobjects. What I am trying to figure out is how exactly I should go about trying to copy my class instances. For example, I want to do this:
absolute_date CURRENT_DATE = DATE;
My solution to this at the moment is to have a copy constructor which works like so:
Make JNI calls to retrieve the member data of DATE.
Make JNI calls to create a new jobject with the retrieved data.
Set the jobject in CURRENT_DATE equal to the newly created jobject
This method is of course somewhat arduous, both programmatically and in terms of efficiency.
Copying over the jobject would be ideal however it means that if DATE goes out of scope then the absolute_date constructor will be called and in turn calling DeleteLocalRef (thus making the jobject for the newly created object invalid).
Is there a way to do what I want? I.e. is it possible to create unique clones of java objects within the JVM via JNI so that I can have 2 or more unique jobject references that each refer to unique java objects that have the same state (i.e. same member values etc)? I should mention that I cannot touch the Java source code. This all has to be done via calls to the invocation API.
If not, is there a way to do this using multiple jobject references i.e. if I have ten copies of DATE, each sharing the same jobject, is it somehow possible to get the destructor to ONLY call when the last remaining DATE Object gets destroyed? Smart pointers perhaps? If so how would I go about doing this as I am relatively new to this.
Thanks,
Question 1:
jstring jstrKey;
for(int i=1;i<=1000;++i) {
LPWSTR strKey = L"string";
jstrKey = env->NewString((jchar *)strKey, wcslen(strKey));
}
env->DeleteLocalRef(jstrKey);
Question 2:
for(int i=1;i<=1000++i) {
LPWSTR strKey = L"string";
jstring jstrKey = env->NewString((jchar *)strKey, wcslen(strKey));
env->DeleteLocalRef(jstrKey);
}
Am i using DeleteLocalRef properly in both questions?
Especially in Question 1, I am deleting local ref after the loop. I think that is correct, and need not call deletelocalref inside the loop since I am not creating any new local ref.
So no issues with respect to usage of DeleteLocalRef right?
In both cases you should call DeleteLocalRef() inside the loop because each NewString() crerates a new local ref.
Local references will be discarded by JNI on return from a native method, but this process has nothing to do with Java garbage collection. Usually, we don't need to worry about local references. But the local ref table is usually quite small, therefore we must discard unused references which are created on a significantly long loop.
The first loop is certainly not correct, but the incorrectness may be benign. It isn't the same thing.
I'm using Visual Studio 2013 and C++11. I want to pass the address of a C++ object back to C. The C code will treat it as a opaque handle; C will never reference it. The only use will be to pass it back to C++ where it will again be used as a pointer to object.
I'm finding that if I create the object in C++ and pass it back to C, the object will be destroyed because it goes out of scope. As a work around, I created a global variable to hold the object so it won't be destroyed upon returning to C. What is the best practice? Should I use a ref-counted pointer type such as shared_ptr? How? I don't like the idea of casting to size_t or such.
The following is an attempt to demonstrate the question. Code won't work.
extern "C" _declspec(dllexport) void __stdcall SwbHttpListenW(const wchar_t *route, SwbHttpListen **listener)
{
*listener = &SwbHttpListen(route); // new will work but how about without new?
}
[Edited the code to re-ask for a solution not using new.]
How about heap allocating the C++ object using the new operator, and getting its address by using the ampersand (&) operator? By heap allocating the object, you ensure it will never be deleted until you actually use the delete operator on it, and the address could be stored/passed as an int.
A simple example:
int main() {
Person *a = new Person("Paul");
doSomething(a); //Passes the memory address of a to the function doSomething
//...and once you're finished using the object, you have to:
delete a;
return 0;
}
It's always going to be messy when you do this sort of thing, how you handle it really depends upon what you want the lifetime of your c++ object to be and, to a lesser extent, how you are going to get rid of it in the end. But clearly the c++ has to do any destruction, you cannot get the c to do that.
This sort of thing is an example of when it is not necessarily A Bad Thing to have global objects - though of course that means you cannot get rid of it freely. Alternatively, you could create it dynamically using new but you then will need an arrangement between the c and the c++ so that it gets deleted at the right time - you might end up with a global object pointer or maybe the c could pass the pointer back to get it destroyed - that would be the nicest solution.
Some trouble may be if some automated Garbage Collector are in use (it may be in C++). std::declare_reachable , std::undeclare_reachable may help.
Else the trouble really doesn't concern passing a pointer to C. And you need to develop some way to achieve a proper pointers to valid objects at the places where necessary... :-)