After allocating memory for a wchar_t*
parameter and copying a string into the buffer, when returning from the function the buffer can not be read. Per the debugger:
machineName 0xcccccccccccccccc <Error reading characters of string.> wchar_t *
given the following code
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
file test.cpp ...
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
file sysCertStore.h ...
#ifdef __cplusplus
extern "C"
{
// only need to export C interface if
// used by C++ source code
BOOL c_GetMachineName(wchar_t* machineName);
};
#endif
file sysCertStore.cpp ...
BOOL c_GetMachineName(wchar_t* machineName) {
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1];
int i = 0;
LPWSTR infoBuf = new wchar_t[MAX_COMPUTERNAME_LENGTH + 1]; // = {'\0'};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
memset(Name, 0, MAX_COMPUTERNAME_LENGTH + 1);
if (GetComputerNameW(infoBuf, &bufCharCount))
{
for (i = 0; i < MAX_COMPUTERNAME_LENGTH + 1; i++)
{
Name[i] = infoBuf[i];
}
delete[] infoBuf;
INT strln= wcslen(Name)+1;
machineName = (wchar_t*)malloc(strln * sizeof(wchar_t)); // new wchar_t[strln];
wcscpy_s(machineName, strln, Name);
return TRUE;
} else
{
wcscpy_s(Name,7+1, L"Unknown");
return FALSE;
}
return FALSE;
}
I'm expecting the test to print the machine name and free the memory of the allocated string/buffer, allocated in the c_GetMachineName
function.
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
The machineName
parameter of c_GetMachineName()
is being passed in by value, so the caller's variable gets copied and c_GetMachineName()
modifies the copy instead.
The local machineName
variable declared inside of your test is uninitialized (and thus set to 0xcccccccccccccccc
in debug mode), and c_GetMachineName()
cannot change it to point at a valid address. That is why the test crashes trying to read from an invalid address 0xcccccccccccccccc
.
To do what you are attempting, c_GetMachineName()
needs to take in its machineName
parameter by pointer instead, so it can modify the caller's variable to point at the memory returned by malloc()
.
Also, your infoBuf
variable is redundant and can be eliminated. So can your use of wcslen()
, since GetComputerNameW()
tells you how many chars it writes to the buffer.
Try this instead:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName;
EXPECT_TRUE(c_GetMachineName(&machineName));
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
BOOL c_GetMachineName(wchar_t** machineName) {
if (!machineName)
return FALSE;
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1] = {};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(Name, &bufCharCount))
return FALSE;
++bufCharCount;
*machineName = (wchar_t*) malloc(bufCharCount * sizeof(wchar_t)); // new wchar_t[bufCharCount];
if (!*machineName)
return FALSE;
wcscpy_s(*machineName, bufCharCount, Name);
return TRUE;
/* or simpler:
*machineName = _wcsdup(Name);
return (*machineName != NULL);
*/
}
Alternatively, you can simply return
the malloc
'd pointer instead, eg:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t *machineName = c_GetMachineName();
EXPECT_NE(machineName, nullptr);
setlocale(LC_ALL, "");
printf("%ls", machineName);
free(machineName);
}
wchar_t* c_GetMachineName() {
wchar_t Name[MAX_COMPUTERNAME_LENGTH + 1] = {};
DWORD bufCharCount = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(Name, &bufCharCount))
return NULL;
++bufCharCount;
wchar_t *machineName = (wchar_t*) malloc(bufCharCount * sizeof(wchar_t)); // new wchar_t[bufCharCount];
if (!machineName)
return NULL;
wcscpy_s(machineName, bufCharCount, Name);
return machineName;
/* or simpler:
return _wcsdup(Name);
*/
}
Or, simply have the caller allocate the memory, and let c_GetMachineName()
merely fill it, eg:
#include "sysCertStore.h"
TEST(sysCertStoreC, c_GetMachineName)
{
wchar_t machineName[256];
EXPECT_TRUE(c_GetMachineName(machineName, 256));
setlocale(LC_ALL, "");
printf("%ls", machineName);
}
BOOL c_GetMachineName(wchar_t* machineName, DWORD maxLength) {
return GetComputerNameW(machineName, &maxLength))
}