Reputation: 1148
Edit: See answer bellow code has been updated and has been tested. It runs correctly again kudos to WhozCraig.
I am writing a simple header file that contains functions that manipulate wide strings dynamically. For example my header includes a copy function that expands the destination buffer if need be. The current function that I am writing copies only a segment of a provided buffer into a provided destination buffer. Originally I used a destination buffer that was more than large enough for my test case and the function had no problems at all. But I wanted to test my realloc() logic so I set the destination buffer's size to 1 so that the function would have to realloc() the destination buffer. But it looks like to me realloc() is changing the values of the contents of the destination buffer. I have tracked the error down to the third realloc() call. Here is the function and the test case that I have been using.
#include <wchar.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#define DWS_DEF_SIZ 16
#define DWS_ENOMEM -1
#define DWS_EINVAL -2
int scpydws(wchar_t* *des, size_t *siz, int argc, wchar_t *src, size_t num, ...)
{
size_t i = 0;
size_t j = 0;
va_list argv;
wchar_t *tmp = NULL;
size_t x = 0;
if(des == NULL) return DWS_EINVAL;
if(siz == NULL) return DWS_EINVAL;
if(*siz == 0 && *des != NULL) return DWS_EINVAL;
if(*des == NULL)
{
if(*siz == 0)
{
if((*des = malloc(DWS_DEF_SIZ * sizeof(wchar_t))) == NULL) return DWS_ENOMEM;
*siz = DWS_DEF_SIZ;
}
else if((*des = malloc(*siz * sizeof(wchar_t)) == NULL) return DWS_ENOMEM;
}
for(va_start(argv, num); argc > 0; argc--, src = va_arg(argv, wchar_t*), num = va_arg(argv, size_t))
{
if(src == NULL || src[0] == 0) continue;
for(j = 0; j < num; j++, i++)
{
for(x = 0; x < i; x++) putwchar((*des)[x]);
wprintf(L" | %i == %i\n", i, *siz - 1);
if(i == *siz - 1)
{
if((tmp = realloc(*des, *siz * 2 * sizeof(wchar_t))) == NULL)
{
va_end(argv);
return DWS_ENOMEM;
}
*siz *= 2;
*des = tmp;
}
(*des)[i] = src[j];
}
}
(*des)[i] = 0;
va_end(argv);
return 0;
}
int main()
{
int ret = 0;
size_t siz = 1;
wchar_t *des = NULL;
wchar_t src1[] = L"123456789";
wchar_t src2[] = L"abcdefghijklmnopqrstuvwxyz";
wchar_t src3[] = L"blahblah";
//The syntax is fairly straight forward the numbers following the
//buffers represent how many characters to copy into the destination buffer
ret = scpydws(&des, &siz, 3, src1, 2, src2, 3, src3, wcslen(src3));
wprintf(L"ret = %i\n", ret);
return 0;
}
Here is the output from the test case. Everything works fine until the third realloc() the characters before "|" represent the destination buffer during the functions operation. What follows the "|" represents a comparison between the function's index variable for the destination buffer (integer on the left of the "==") and the destination buffer's last valid index (integer on the right of the "==") if the statement is true than the function would realloc() the destination buffer. So my question is basically where the hell does the 'Y' come from (see bellow)? Also as I side note I compiled the code on a Windows Vista SP3 system with MinGW-GCC (I do not know what MinGW-GCC version) and instead of the random 'Y' character I got a ENOMEM error from realloc(), ironically on the third realloc() call but I do not really care why that happens.
| 0 == 0
1 | 1 == 1
12 | 2 == 3
12a | 3 == 3
12ab | 4 == 7
12abc | 5 == 7
12abcb | 6 == 7
12abcbl | 7 == 7 Note: The function realloc()s here
12abcYla | 8 == 15 Note: Notice how the 'b' changes to a 'Y'?
12abcYlah | 9 == 15
12abcYlahb | 10 == 15
12abcYlahbl | 11 == 15
12abcYlahbla | 12 == 15
ret = 0
Upvotes: 1
Views: 367
Reputation: 1148
The size arguments for malloc()
and realloc()
need to be multiplied by sizeof(wchar_t)
.
I changed this:
*des = malloc(DWS_DEF_SIZ))
to this:
*des = malloc(DWS_DEF_SIZ * sizeof(wchar_t)))
and this:
tmp = realloc(*des, *siz * 2)
to this:
tmp = realloc(*des, *siz * 2 * sizeof(wchar_t))
Thanks to WhozCraig.
Upvotes: 3