My program is crashing every time I try to store a COM pointer into a struct, and then later try to use the original pointer. I don't have debug access to tell exactly what's wrong.
pRend->cp = cpRT;
ID2D1SolidColorBrush *scBrush;
ERF(cpRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::CornflowerBlue), &scBrush));
It crashes on CreateSolidColorBrush. However, if I comment out pRend->cp = cpRT, it doesn't.
By the way, pRend->cp and cpRT are of type ID2D1HwndRenderTarget *.
Instead of assigning directly QI and then store i.e.,
pRend->cp = cpRT;
should be replaced with
cpRT->QueryInterface(&pRend->cp);
It's unclear how much code exists between when you assign it into the struct and later use it in CreateSolidColorBrush. If it's a non-trivial amount of time, it's possible that you have a reference counting issue.
Are you storing a raw pointer in the struct? If so, switch it to a CComPtr and see if the crash goes away.
For instance. If you had the following type definition for the value of pRend (call it Render) and the value pRend was destroyed before making the CreateSolidColorBrush call, you could see this behavior.
struct Render {
ID2D1HwndRenderTarget *pCt;
~Render() {
pCt->Release();
}
};
As it turns out, I managed to stop the crashing by allocating pRend with malloc. This is not a problem because I will call free when I don't need it anymore. I'm interested in why calling malloc fixes this though. I'm used to just doing Datatype * var; and then just using var. Is that bad?
It's a smart pointer. I'm guessing you're inadvertantly calling release on it. In particular, it's addressof operator (unary op&) is overriden to call Release().
See what happens if you instead assign it to a reference, an ID2D1HwndRenderTarget*&.
Obviously, if you assign to a reference, you won't be able to reseat it.
Related
I am currently trying to call a sqlite3 library function, and it expects me to pass it a sqlite3**.
Here is my current code. I have one working part, and one part that gives me an error:
sqlite3 *sqlite = m_db.get();
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite))
{
}
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &(m_db.get()) ))
{
}
My m_db field looks like this:
std::unique_ptr<sqlite3> m_db = nullptr;
Of the two examples I displayed, the first one is working perfectly fine. However, the second gives me this error. Note that this is coming from the &(m_db.get()) part:
“Address expression must be an lvalue or a function designator”
I read up a little bit about lvalues and rvalues, but I can't seem to figure out why this syntax would not be possible. As far as I understood by now, the problem is that the return value of the .get() operation is merely only a temporary expression result, and therefore doesn't have an identifiable location in memory where I could fetch the adress from.
There has to be a way to achieve this in one statement, I guess.
Can anyone explain to me why this is not working and how I can possibly fix it?
The & operator can only be used with an lvalue (or with a qualified id when making pointers-to-member). The expression m_db.get() is an rvalue because it returns a pointer by value, not by reference, so you cannot take its address.
unique_ptr provides no method for accessing the underlying pointer as a reference, you'll need to store a copy somewhere as in your first example.
A smart pointer stores a pointer and returns it on get. What you want to do here is the opposite: you get a pointer from sqlite3_open and want to store it in a smart pointer. So you would do something like
sqlite3* db = nullptr;
sqlite3_open(..., &db);
m_db.reset(db);
As the main feature of the unique_ptr is to delete the contained pointer in its destructor, I'm not sure if it makes sense to use it here. As far as I understand it, you are supposed to call sqlite3_close on the returned pointer, not delete it.
There has to be a way to achieve this in one statement, I guess.
I'm not quite sure about that; the point about temporary values really might be that it takes a statement to get a permanent one.
Also, you're messing with the semantics of the smart pointer, which you shouldn't do – .get should really not be used here.
Soooo, what I'd do is rely on C++ scoping here, and don't care about the fact that I declare a "normal" pointer first to make a smart pointer later.
your_class::initialize_db() {
sqlite3 *sqlite;
int retval = sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite);
if(retval == SQLITE_OK)
m_db = std::unique_ptr<sqlite3>(sqlite);
}
An lvalue is basically something which can appear on the left hand side of the assignment operator. So the error says that you can only retrieve the address of something which can be assigned to, or a function. It would have worked if you had member access to the sqlite3* pointer inside the unique_ptr, but you don't, and for good reason.
More to the point, you should not use a smart pointer in this case. If sqlite3_open requires an sqlite3** argument, then it means that the function will provide a value for the sqlite3* pointer. Basically it is an out parameter form C# or other such languages. It would have been clearer for it to be provided as a function result, but that was taken away by the result code. This is all well and good, but the smart pointer wants to have control over this value. You set the value once at initialization, but after that, the smart pointer takes care of it. And it needs to do this in order to maintain its constraints: uniqueness of ownership, deallocation when the pointer itself goes out-of-scope etc. If you basically go and overwrite the sqlite3* pointer inside, then that can't happen anymore, because the smart pointer has no way of intercepting the overwrite and deallocating the object it is currently using.
I need to pass the address of my ID3D11RenderTargetView pointer to a function, and I use a com_ptr_t to hold it. So first I tried:
ID3D11RenderTargetViewPtr pRenderTargetView; = ID3D11RenderTargetViewPtr(NULL);
pImmediateContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
However, the & operator turns the pointer to null. I then went over the com_ptr_t functions again and saw that I could write:
pImmediateContext->OMSetRenderTargets(1, &pRenderTargetView.GetInterfacePtr(), nullptr);
It does work, but isn't there a simpler way to get the address of the underlying pointer without losing it? By simpler, I mean shorter, syntax wise.
Igor's comment is correct. The purpose of _com_ptr_t is pretty straightforward, and trivial conversion to raw interface pointers is almost always the wrong thing to do.
For example, the primary reason why the & operator releases the interface is that the number one reason people take the address of a smart pointer is to pass it as an out parameter to some factory function. If the & didn't release the pointer, then the old value would leak.
This happened a lot.
Now, there are much rarer cases, such as the one you have, where you pass the address of an interface to a function that isn't going to set it, and in those cases, you have the GetInterfacePtr function.
I have a situation in which I have an object of type Foo, in which calling its own methods somehow loses track of its own address in "this". I have defined these functions:
// Bar has an instance of foo, and wishes to call a function001()...
Bar::doThingWithFoo(){
// foo is at address 0x1a7bbb70 here...
foo->function001();
}
// The definition of function001(). The address of "this" is as expected.
Foo::function001(){
// the address of "this" is 0x1a7bbb70 here...
this->function002();
}
Foo::function002(){
// but the address of "this" is 0xbfffe090 here!!!
// bad things happen, as you might expect.
this->getMyProperty()->doThing();
}
Why might something like this happen?
Perhaps you are using multiple inheritance, which causes the pointer value of this to be context-dependent:
http://frogchunk.com/documentation/lang/cpp/Multiple_inheritance_and_the_this_pointer.pdf
That causes problems if you use C casts instead of dynamic_cast.
I agree with the comments that we need to see the actual code. I will speculate that 0xbfffe090 looks like an address on the stack which means you may have accidentally copied your object and then invoked a method on the copy. It would also be consistent with some kind of memory corruption (overwriting a local array, for example) with some local address.
Wild speculative guess would be what others have also eluded to that you might be having some sort of buffer over-flow case at other place in your code where the buffer overflow is corrupting this.
It would help to know the code.
I would imagine if its a memory corruption it would cause it have a core dump, did you notice one ?
Answering my own question : alltom's answer was actually closer than it might seem, but ultimately it was of course memory corruption. Memory became corrupted inside function001 prior to function002 being called because of an object being used as a delegate. The delegate had been passed and stored as a void*, and C-style cast back into its object type to call its relevant methods.
The issue was resolved by storing the delegate object in a variable (eg: MyDelegate* delegate) rather than storing as void* and casting.
A pointer that is passed-in-by-reference. Why? aren't pointers just references anyways? What's really happening to this parameter?
void someFunc(MyPtr*& Object)
{
}
Simply speaking, it gives you the ability to change the pointer itself: it can be changed to point to another location in the function.
And the change will be reflected outside.
It enable you to:
void someFunc(MyPtr*& Object)
{
//Modify what Object is pointing to
Object=&old_Object;
//You can also allocate memory, depending on your requirements
Object=new MyPtr;
//Modify the variable Object points to
*Object=another_object;
}
Other's will have to vote to verify this cause I'm a bit rusty on my C++ but I believe the idea here is you'd pass in a pointer by reference, that is instead of creating a new space to store the pointer itself you use a reference to the pointer so if you were to modify the pointer not just the value it would be modified after returning from the function, whereas otherwise all you could do is modify the value at position passed in. Hope that makes sense.
The difference to passing just a pointer is that if the pointer is changed (Object = x) then this change will be seen by the calling function. You could achieve the same when you pass MyPtr** Object and dereference the pointer *Object = x;. With the second approach you could pass NULL to the function. This is not possible for references.
You are not quite right. The pointer content is passed by reference but the pointer itself is still passed by value, i.e. reassinging it to some other pointer will not be reflected upon the exit from the method because the pointer will be set to point to the same memory block as before the call. Think of it as a simple int variable. However with &* or ** you can reassign the pointer and that will be visible outside the scope of this method.
Why?
For the same reason that you would pass in anything else by reference.
aren't pointers just references anyways?
Dear god, no. Not even remotely the same thing. Look, you can try to build a mental model of a reference by starting with a pointer, but by the time you've fixed up all the differences, you have a horrible illogical mess.
References are a much simpler and more intuitive concept, and there are only "historical reasons" for trying to understand pointers before them. Modern C++ uses raw pointers only rarely, and treats them as an implementation detail as much as possible.
A reference is another name for an already-existing thing. That's it. When used as a function parameter, they thus allow the called function to refer to the caller's data.
It also means the pointer can be 0 (NULL) which can having meaning to the method. A reference must always be valid and cannot be made 'nothing'
I'm working with C++ unmanaged, the problem that I have happens when I call a method that returns an LPVOID.
LPVOID MyMethod(...);
The problem is that this method sometimes returns a Bad Ptr and I want to know if there is a way of detecting this, if the value returned is a Bad Ptr.
I have tried asking if it is NULL with no luck.
The only way in which I realize if the result is a Bad Ptr is while I'm debugging, I have tried some different ways but still unable to do it.
No, there is no easy way to determine if a pointer is bad.
Windows does have IsBadReadPtr, IsBadWritePtr. These functions are inherently flawed - they only determine if a function is readable or writable in your address space at the moment of the call. They can also be the cause of security issues and should never be used.
The main issue is that there is no way to differentiate between a "bad" pointer that is still accessible to your process, and a good pointer.
For instance,
int g[5];
int somethingElse;
void* GetPointer()
{
return &g[5]; // Whoops, off by one.
}
&g[5] is probably a valid pointer in your process, and might be pointing to somethingElse, you'll be able to access it without crashing but writing to it will corrupt your state.
Your real problem is that you're calling a function that returns bad pointers. Do you have access to its source code? 90% of the time I've encountered problems like this, it's because either:
1) The function is returning a pointer to the stack; e.g.,
char a[10];
...
return a;
2) The function is returning a pointer that was never assigned valid memory to begin with:
char* foo; // Invalid pointer
...
return foo;
3) The function is returning a pointer that was already deleted (or free'd):
char* foo = new char[10];
...
delete[] foo;
return foo;
You really need to find the real problem, rather than work around it.
LPVOID is a typedef to a pointer to void, Visual studio typically displays NULL values as "bad pointer" in the watch pane, are you sure that this pointer is not NULL?
No, you cant.
However, if you can create an auxiliary data structure to store locations and ensure you remove them from that auxiliary data structure when they get deleted (maybe add it to the destructor) you can check whether the pointers are in that structure before de-referencing them.