1

I have a driver that I am modifying that was written by someone else in C. Since I need to add some C++ function calls I am now building the driver with C++ compiler versus C compiler (in Visual Studio 2012). When I changed to C++ I received a lot of build errors, all of which I have been able to fix except for a few. The few errors are all related to calls to the same function. I have searched the web extensively to try to find a solution to this issue without any success. So below are the components to this issue that I hope will allow someone to help me with this issue.

First, here is the function that is being called. You may be wondering why the original S/W developer created their own custom free memory function when they could have just used the free() function in the standard C library. I do not know why this was but since it was working just fine, I hesitate to change it.

void freeMemory(void **pBuffer)
{
    BOOL result;
    ASSERT(pBuffer != NULL);

    // see if buffer is already been freed
    if (*pBuffer == NULL)
    {   
        return;
    }

    result = VirtualFree(
        *pBuffer,                   // LPVOID lpAddress,   // address of memory
        0,                          // SIZE_T dwSize,      // size of memory
        MEM_RELEASE                 // DWORD dwFreeType    // operation type
        );
    // see of we were able to successfully free the memory  
    if (result == FALSE)
    {   
        ASSERT(FALSE);
        return;
    }

    // Mark the buffer pointer as now being free
    *pBuffer = NULL;
}  

So the next piece to this puzzle is a #define as follows:

#define FREE(pBuffer) freeMemory(&(pBuffer))

Finally, below is one of the many calls to this FREE function:

FREE(Buffer);

In this example, "Buffer" is a pointer to an unsigned char.

unsigned char *Buffer;

For reference purposes, the error that I am receiving, for this particular example, is "cannot convert parameter 1 from 'unsigned char *' to 'void **'"

It's been a long time since I have done much with straight C or C++ and pointers were never my strong suite. Based on the error, my assumption was that this error is related to not providing a cast in the function call, but considering how the free() function is used from the standard C library, it doesn't seem like this should be necessary. Any help on what I need to do with respect to how the FREE function is called to eliminate these errors would be greatly appreciated.

Pungo120
  • 105
  • 1
  • 13

2 Answers2

0

The freeMemory is used to create a safe free, since you can call it twice for the same pointer with no harm. I don't like this, it will only hide your mistake, but is very common to see it around.

The cause of this error is explained here, as pointed by Quentin.

An alternative for you code is:

#define FREE(pBuffer) \
{ \
    void *tmp; \
    tmp = pBuffer; \
    freeMemory(&tmp); \
    pBuffer = tmp; \
}
Community
  • 1
  • 1
Jonatan Goebel
  • 1,107
  • 9
  • 14
  • 3
    you are missing a couple of `;` in your answer. – ryyker Feb 05 '15 at 16:13
  • I added the necessary ';' to the lines of code in Jonatan's answer but I am now getting a build error for that code that says "error C2447: '{' : missing function header (old-style formal list?)" – Pungo120 Feb 05 '15 at 16:23
  • @Pungo120 - is it possibly a reference to needing a function prototype? By the way, I implemented Jonatan's code, into your's, ran it, and `VirtualFree(...)` fails to free the memory. Other than that, I get no error messages. Taht could be because the second argument is 0. I am looking at the ***[documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892%28v=vs.85%29.aspx)*** now. – ryyker Feb 05 '15 at 16:45
  • @ryyker - the function prototype exists for freeMemory(). It exists in the same header file as the #define FREE(pBuffer)... I moved the #define below the function prototype just in case that was an issue but no difference. – Pungo120 Feb 05 '15 at 16:58
  • Ok. I eliminated the "error C2447: '{' : missing function header (old-style formal list?)", but now I get a slightly different error. For clarification purposes, the "full" original error message was "error C2664: 'freeMemory' : cannot convert parameter 1 from 'unsigned char *' to 'void **'". Replacing the original #define with Jonatan's suggested code, I now get "error C2440: '=' : cannot convert from 'void *' to 'unsigned char *'" – Pungo120 Feb 05 '15 at 17:23
  • Although a not the desired fix for the last error message I mentioned, because there were only a few calls to to FREE(), I ended up eliminating the macro and just putting the code in-line. No build errors after this. Based on @ryyker comment about freeMemory() not freeing the actual memory, I will have to see what other comments are provided to make sure this function does what it is supposed to. – Pungo120 Feb 05 '15 at 17:42
  • @Pungo120 - have you reviewed comments in my answer? – ryyker Feb 05 '15 at 17:46
  • @ryyker - Yes, I have reviewed your comments in your answer. I am reviewing your answer and trying to figure out how best to adapt this to my needs. – Pungo120 Feb 05 '15 at 19:29
0

The problem I had when running variations of your code, was with inconsistent usage of VirualFree and VirtualAlloc, i.e. in your provided code example I could see no indication of VirtualAlloc() usage, which should be used in conjunction with VirtualFree().

Also, when I tried to assign memory to a specific address using VirtualAlloc(), It always failed, so I let the system specify the address. Below is a code snippet that demonstrates allocating and freeing page memory.

EDIT This now addresses your macro question, It uses the macro definition suggestion from Jonaton (with the two extra ;).

Adapted from here: (this built and ran without error, demonstrating usage of VirtualAlloc() used in conjunction with VirtualFree())

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>             

#define PAGES 100            

LPTSTR lpNxtPage;               
DWORD dwPages = 0;              
DWORD dwPageSize;

void freeMemory(void **pBuffer);

#define FREE(pBuffer) \
{ \
    void *tmp; \
    tmp = pBuffer; \
    freeMemory(&tmp); \
    pBuffer = tmp; \
}

void main(void)
{
    LPVOID lpvBase;               
    LPTSTR lpPtr;                 
    BOOL bSuccess;                
    DWORD i;                      
    SYSTEM_INFO sSysInfo;         

    GetSystemInfo(&sSysInfo);     


    dwPageSize = sSysInfo.dwPageSize;


    lpvBase = VirtualAlloc(
                     NULL,                 
                     PAGES*dwPageSize, 
                     MEM_RESERVE,          
                     PAGE_NOACCESS);       
    if (lpvBase == NULL )//do nothing

    lpPtr = lpNxtPage = (LPTSTR) lpvBase;


   // bSuccess = VirtualFree(
   //                    lpvBase,       
   //                    0,             
   //                    MEM_RELEASE); 
    FREE(lpvBase)  //replace in-line VirtualFree with macro

    ;
}


void freeMemory(void **pBuffer)
{
    BOOL result;
    assert(pBuffer != NULL);

    // see if buffer is already been freed
    if (*pBuffer == NULL)
    {   
        return;
    }

    result = VirtualFree(
        *pBuffer,                   // LPVOID lpAddress,   // address of memory
        0,                          // SIZE_T dwSize,      // size of memory
        MEM_RELEASE                 // DWORD dwFreeType    // operation type
        );
    // see of we were able to successfully free the memory  
    if (result == FALSE)
    {   
        assert(FALSE);
        return;
    }

    // Mark the buffer pointer as now being free
    *pBuffer = NULL;
} 
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • ryyker - as stated in my comments above, if I replace the old macro with your new one I now get "error C2440: '=' : cannot convert from 'void *' to 'unsigned char *'". Because there were only a few calls to to FREE(), I ended up eliminating the macro and just putting the code in-line which eliminated the build errors. As long as I know that it is freeing the memory correctly I feel OK. Relative to you comment about VirualAlloc() usage, the program has another function similar to freeMemory that wraps VirualAlloc() and effectively matches your code. – Pungo120 Feb 06 '15 at 14:25