Delete a NULL pointer is secure.
int* p = NULL;
delete p; // ok, secure
What ist about Handles?
HANDLE h = NULL;
CloseHandle(h); // allowed?
I am reading MSDN but still not sure. It say something about ERROR_INVALID_HANDLE but it is 6L, not NULL.
I come from a destructor of a class, which gives me a C6387 warning Error
if (m_hThread)
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread); // warninig C6387
m_hThread = NULL;
No. You may not call CloseHandle on a NULL handle. Look at the documentation for the argument. It says:
hObject [in] A valid handle to an open object.
NULL is not a handle to an open object.
The fact that you get C6387 is precisely because you are passing a "possibly-null" handle to CloseHandle.
You must write the code as:
if (m_hThread) {
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
}
(There is no point setting m_hThread to NULL after this - it is going to cease to exist in a very short while).
Related
I have a service that it creates a process and then frees its memory.
I use createprocess() function and then close handle of process and thread,
this is my code:
if (CreateProcessA(NULL,
zAppName,//{ pointer to command line string }
NULL, //{ pointer to process security attributes }
NULL, //{ pointer to thread security attributes }
TRUE, //{ handle inheritance flag }
0,
NULL, //{ pointer to new environment block }
NULL, //{ pointer to current directory name }
&StartupInfo, //{ pointer to STARTUPINFO }
&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,WaitMiliSec);
GetExitCodeProcess(ProcessInfo.hProcess, &Result);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(hRead);
CloseHandle(hWrite);
return (Result);
}
But after closehandle() function, hProcess and hThread still have value!!!
and each time my service runs this code the memory increases and doesn't decrease!!!Is this a memory leak?
what should I do?
As the process is loaded into the memory following elements are loaded :
1.code
2.memory
2.PCB
4.Data etc.
When you close handles only some part of heap (assuming that you are using malloc to create handlers) is freed. So rest of elements still remains into the process stack. So you can't guarantee that memory is not freed.
yes hProcess and hThread might have some values that can create confusion. But these pointers hProcess and hThread will be called as "dangling pointers". So it is a good practice to assign a null value to the pointers after de-allocation.
This question already has answers here:
Handling CoCreateInstance return value
(2 answers)
Closed 8 years ago.
Imagine a situation:
CComPtr<IGraphBuilder> pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
if (SUCCEEDED(hr))
{
CComPtr<IMediaControl> pControl;
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if(SUCCEEDED(hr))
{...}
}
I wonder, if pControl could ever be nullptr inside last block {...}. The question occurred, because I saw that code:
if(SUCCEEDED(hr) && pControl)
{...}
I consider that part && pControl as a redundant one. Am I right?
QueryInterface() is required to provide a valid (so non-null) interface pointer on success and a null pointer on failure. However you don't know whether some specific implementation follows that rule and the code you cite most likely tries to be defensive.
That said, the following
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
also calls QueryInterface() under the hood to retrieve the pointer to the requested interface. If the code wants to be defensive it should check that pGraph is non-null on success too.
The problem here is you don't know how bad it is when you get S_OK and a null pointer. Suppose QueryInterface() works like this (really bad code follows, not for use anywhere):
HRESULT TheClass::QueryInterface( REFIID iid, void** ppv )
{
if( iid == SomeSpecificIID ) {
AddRef();
*ppv = 0; //BAD IDEA, BAD CODE, JUST DON'T
return S_OK;
} else {
//whatever
}
}
great, the defensive code will avoid dereferencing a null pointer retrieved here together with S_OK returned but reference count will be incorrect - noone will have a chance to call matching Release(). So you instantiate such an object, then call QueryInterface() which works as above, the refcount is now 2, then you Release() the object once and it leaks. How bad it happens to turn out depends on a lot of factors.
Same with CoCreateInstance() - it calls the same QueryInterface() under the hood. Both may be broken and your mileage may vary both with and without checking the retrieved pointer against null.
Here's a code sample creating a COM object:
CComPtr<IBaseFilter> pFilter;
auto hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter));
I've seen somewhere that checking if CoCreateInstance() succeeded should look like this:
if (SUCCEEDED(hr) && pFilter != nullptr)
{
// code goes here
}
What if I would check only hr? Wouldn't it be enough? Should I also check that filter != nullptr?
//would this be enough?
if (SUCCEEDED(hr))
{
// code goes here
}
This question also concerns other COM methods like QueryInterface().
Having S_OK result from CoCreateInstance you are guaranteed to get a non-NULL interface pointer, so you don't need to check it additionally. To make it more reliable and be able to detect issues early, you might want to use ATLASSERT there to compare against NULL. This does not produce code in release builds, but generates an early warning in debug if anything goes wrong (esp. you edit or copy paste code later and change the logic of obtaining the pointer.
CComPtr<IBaseFilter> pFilter;
HRESULT hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, reinterpret_cast<VOID**>(&pFilter));
if(SUCCEEDED(hr))
{
ATLASSERT(pFilter); // hr is of the interest because might explain failure
// pFilter is expected to be non-NULL in case of S_OK
const CComQIPtr<IDMOWrapperFilter> pDmoWrapperFilter = pFilter;
if(pDmoWrapperFilter)
{
// We're not really interested in QueryInterface's HRESULT since it's
// either S_OK or E_NOINTERFACE, hr will typically explain nothing special.
// More important is whether we finally obtained the pointer or not
}
}
I think it is redundant and not needed to check both.
If it does fail though, the return value will tell you which error occurred. That's why there's 2 ways of determining if the function succeeded or not.
The following code is copied from MS Async Filter. It is supposed that the following code is calling either CancelIo or CancelIoEx. I don't see where CancelIoEx is called in anyway. It is supposed that the typedef is representing the CancelIoEx but is never called. What exactly the line bResult = (pfnCancelIoEx)(m_hFile, NULL); is doing?
// Cancel: Cancels pending I/O requests.
HRESULT CFileStream::Cancel()
{
CAutoLock lock(&m_CritSec);
// Use CancelIoEx if available, otherwise use CancelIo.
typedef BOOL (*CANCELIOEXPROC)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
BOOL bResult = 0;
CANCELIOEXPROC pfnCancelIoEx = NULL;
HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
if (hKernel32){
//propably bad code !!! Take Care.
bResult = (pfnCancelIoEx)(m_hFile, NULL);
FreeLibrary(hKernel32);
}
else {
bResult = CancelIo(m_hFile);
}
if (!bResult) {
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
Assuming this is all the code, it has a serious bug in it. This:
CANCELIOEXPROC pfnCancelIoEx = NULL;
defines pfnCancelIoEx as a pointer to function whose signature matches that of CancelIoEx. The pointer is initialised to a null value and the obvious intention is to point it at CancelIoEx later.
That function is defined in Kernel32.dll, so loading this is the logical next step. If this succeeds, the code should proceed by doing this:
pfnCancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
And then it should check the result. However, it does not do either of that.
Next, on this line:
bResult = (pfnCancelIoEx)(m_hFile, NULL);
it attempts to call the function pointed to by pfnCancelIoEx. However, this pointer is never changed from its initial null value, so this will attempt to dereference a null pointer, resulting in undefined behaviour and likely a crash.
I have some event handles and I add them to a list. I want to know if I can store these handles, close the local ones and still use the stored ones later.
Example:
std::map<std::string, HANDLE> Events;
DWORD OpenSingleEvent(std::string EventName, bool InheritHandle, DWORD dwDesiredAccess, DWORD dwMilliseconds)
{
Handle hEvent = OpenEvent(dwDesiredAccess, InheritHandle, EventName.c_str()); //Local Handle.
if (hEvent)
{
DeleteSingleEvent(EventName); //Delete the correct/old handle in the map.
Events.insert(EventName, hEvent); //Add this new handle to the map.
DWORD Result = WaitForSingleObject(hEvent, dwMilliseconds);
CloseHandle(hEvent); //Close THIS handle. Not the one in my Map.
return Result;
}
CloseHandle(hEvent); //Close this handle.
return WAIT_FAILED;
}
Will the above work? If not, is there another way to do this? It's for shared memory communication so I cannot duplicate handles since I only have the client PID not the Server's.
Also can someone explain what InheritHandle does? The function I use is OpenEvent and it has that parameter but I'm not sure what it does.
A HANDLE is simply a void *, it's a token which actually represents an object in kernel space. Calling CloseHandle actually deallocates the kernel object so the short answer to your question is no, you can't keep a list of them and then close all the local ones. All you'll have is a list of void* which don't represent anything.
What you can do is use DuplicateHandle which actually creates another kernel object on your behalf. However... why not just close the handles when you've finished with the entry in the list?