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.
Related
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.
In our C++ code, we have our own string class (for legacy reasons). It supports a method c_str() much like std::string. What I noticed is that many developers are using it incorrectly. I have reduced the problem to the following line:
const char* x = std::string("abc").c_str();
This seemingly innocent code is quite dangerous in the sense that the destructor on std::string gets invoked immediately after the call to c_str(). As a result, you are holding a pointer to a de-allocated memory location.
Here is another example:
std::string x("abc");
const char* y = x.substr(0,1).c_str();
Here too, we are using a pointer to de-allocated location.
These problems are not easy to find during testing as the memory location still contains valid data (although the memory location itself is invalid).
I am wondering if you have any suggestions on how I can modify class/method definition such that developers can never make such a mistake.
The modern part of the code should not deal with raw pointers like that.
Call c_str only when providing an argument to a legacy function that takes const char*. Like:
legacy_print(x.substr(0,1).c_str())
Why would you want to create a local variable of type const char*? Even if you write a copying version c_str_copy() you will just get more headache because now the client code is responsible for deleting the resulting pointer.
And if you need to keep the data around for a longer time (e.g. because you want to pass the data to multiple legacy functions) then just keep the data wrapped in a string instance the whole time.
For the basic case, you can add a ref qualifier on the "this" object, to make sure that .c_str() is never immediately called on a temporary. Of course, this can't stop them from storing in a variable that leaves scope before the pointer does.
const char *c_str() & { return ...; }
But the bigger-picture solution is to replace all functions from taking a "const char *" in your codebase with functions that take one of your string classes (at the very least, you need two: an owning string and a borrowed slice) - and make sure that none of your string class does cannot be implicitly constructed from a "const char *".
The simplest solution would be to change your destructor to write a null at the beginning of the string at destruction time. (Alternatively, fill the entire string with an error message or 0's; you can have a flag to disable this for release code.)
While it doesn't directly prevent programmers from making the mistake of using invalid pointers, it will definitely draw attention to the problem when the code doesn't do what it should do. This should help you flush out the problem in your code.
(As you mentioned, at the moment the errors go unnoticed because for the most part the code will happily run with the invalid memory.)
Consider using Valgrind or Electric Fence to test your code. Either of these tools should trivially and immediately find these errors.
I am not sure that there is much you can do about people using your library incorrectly if you warn them about it. Consider the actual stl string library. If i do this:
const char * lala = std::string("lala").c_str();
std::cout << lala << std::endl;
const char * lala2 = std::string("lalb").c_str();
std::cout << lala << std::endl;
std::cout << lala2 << std::endl;
I am basically creating undefined behavior. In the case where i run it on ideone.com i get the following output:
lala
lalb
lalb
So clearly the memory of the original lala has been overwritten. I would just make it very clear to the user in the documentation that this sort of coding is bad practice.
You could remove the c_str() function and instead provide a function that accepts a reference to an already created empty smart pointer that resets the value of the smart pointer to a new copy of the string. This would force the user to create a non temporary object which they could then use to get the raw c string and it would be destructed and free the memory when exiting the method scope.
This assumes though that your library and its users would be sharing the same heap.
EDIT
Even better, create your own smart pointer class for this purpose whose destructor calls a library function in your library to free the memory so it can be used across DLL boundaries.
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... :-)
Suppose we have a situation like this. Suppose instead of "p = &global;" we called some function(written by someone which invalidate our pointer). How to handle this problem? How to protect code from crashes? I know about and use boost smart pointers. But what to do if we have this situation.
struct Test
{
int a;
int b;
int c;
};
Test global;
int main()
{
Test *p = new Test;
p->a = 1;
p->b = 2;
p->c = 3;
p = &global;
delete p;
return 0;
}
You handle it by fixing the bug and recompiling your program. Anything else makes no sense.
You can't and you shouldn't try to deal with this situation other then not letting it occur in the first place.
There are some basic rules in C++ that simply have to be obeyed.
Nothing. If you do this, then you get what you get. Don't do this.
Once you reassign p, you leak the Test object that p originally pointed at. You've now lost that memory for the duration of this app's runtime. Then when you delete a non-heap object, you're running into undefined behaviour and anything at all can happen (usually the runtime library will crash trying to delete non-heap memory - but you have no guarantees). There's absolutely nothing reliable that you can do once you've tried to delete non-heap memory.
You've already mentioned smart pointers, which is part of the solution. The other part is just being careful.
Unfortunately there's nothing you can do. The C++ compiler can't tell from your code whether or not you might delete a pointer in the future, so you have to be sure to manage them correctly in your code. This means that if you put the address of a non-heap-allocated item into a pointer, it's your responsibility nto to delete that pointer.
In short, C++ can't protect you from every possible mistake you can write.
You can use the code below to find out if a pointer points to a stack area or heap area:
bool IsMemoryOnStack( void* p )
{
void* dwStackTop = 0;
void* dwStackLowCurrent = 0;
__asm {
mov EAX, FS:[4]
mov dwStackTop, eax
mov EAX, FS:[8]
mov dwStackLowCurrent, eax
}
return ( p<= dwStackTop && p>= dwStackLowCurrent );
}
You need to swap the assignment and delete statements:
delete p;
p = &global;
BUT I would suggest never using the same variable to point at data that requires an explicit free and data that does not. Pick one or the other for each variable, so you can either always delete the memory before reassigning it or never delete it. If you try to keep track of how you're pointers got set, you'll wind up spending all your time whining about how C++ provides no memory management and forces you to write unmaintainable code.
The primary way to avoid this is to simply avoid using new or delete under any but the most tightly controlled circumstances.
Using new inside of main is particularly suspect -- the reason to use new in C++ is when you need to create an object that needs to outlive the scope in which it's being created (e.g., when you reach the end of that function, it must not be destroyed). In the case of main, the only reason to do what would be if you were allocating something in main that would not be deleted in main, but used by some the destructor of some global object as it ran after you returned from main (which is rarely done and even more rarely a good idea).
Most uses of new should be in the ctor of an object, and most uses of delete should be in the dtor of an object. If you have something like a collection, it can also make sense to use new and/or delete in some other member function(s) that handle(s) things like re-sizing the collection.
Other than that, there are entity objects that generally aren't ever assigned or copied. For example, consider a call routing system, where you create a "call" object when somebody dials their phone, and you destroy the object when they hang up. In nearly every such case, you have a global collection (or more than one) that holds pointers to these objects, so as soon as you create the object, its address goes into the (correct) global collection. Interesting point: nearly all code that I've seen where this pattern made sense did not have any external code that destroyed the object -- rather, the object itself was responsible for removing itself from the global connection, and using the (much argued-about) delete this; to destroy itself when the real-world connection (or whatever) it was attached to ended.
It is possible to overload delete. In theory you could have your overloaded delete refuse to do anything unless the address is valid. But how do you know if it's valid? The best you can say is "this wasn't allocated with new," but you'll probably have to overload new to do that.
For the record, the standard new and delete crash in this case because delete determines the address didn't come from new and assumes the worst. Assuming the worst is probably the best thing to do in that situation, though; at least it beats assuming the best.
So I'll second the advice to not protect against this in code, and simply don't do that.
i am passing HBuf to function
but it crashes i don't know whether i am following right way or not
//case 1:
HBufC8* iBuffer2 = HBufC8::NewL(1000 );
TPtr8 bufferPtr( iBuffer2->Des() );
//assigning value to HBuf code
StartParsingL(iBuffer2);
StartParsingL(HBufC8* aHBufPtr)
{
iBuffer = HBufC8::NewL(aHBufPtr->Length());//it crashes here
bufferPtr.Copy(aHBufPtr->Des());//also here
}
Not answering your question (as there isn't really enough information). I would recommend using an RBuf instead of a HBuf as they are the recommended heap buffer descriptor going forward, and a bit easier to use.
In the Symbian coding convention, "i" prefixed variables are member variables.
In your snippet you have it as a local declaration. It could be that you just put in the type for clarity of the snippet, but if you've declared it both as a member variable and as a local declaration, that could explain plenty of crashes :-)
You should have:
class C....: public CBase?....
{
private:
HBufC8* iBuffer2;
};
...
void C...::ConstructL()
{
...
iBuffer2 = HBufC8::NewL(1000);
...
}
This code does not directly show the reason for crashing. Please post actual snippets next time.
Also, when posting about a crash, it is good to know how it is crashing. I assume it is a KERN-EXEC 3 panic. But please be explicit about it yourself.
I guess the aHBufPtr passed to StartParsingL is either zero or otherwise does not point to a valid HBuf8 object. That would be the immediate reason for the crash. Why it is not a valid pointer is not visible in the code, but one reason could be shadowing a member variable with a local variable as suspected by #Will.
Some further points, not related to crash here but Symbian C++ in general:
When passing descriptors around, you should use the most general read-only TDesC or TDesC8 type references or read-write TDes or TDes8 type references. Use HBufC or HBufC8 pointers only if you are transferring ownership to the callee.
In this snippet:
bufferPtr.Copy(aHBufPtr->Des());
Copy accepts a TDesC& so you do not need to call Des:
bufferPtr.Copy(*aHBufPtr);
Though if you just want to copy a descriptor, you could use any of the descriptor Alloc functions such as AllocL.