Memory leaks with strtok - c++

I'm getting some memory leaks in valgrind with strtok and I'm not sure why it's happening.
Possibly lost: 281 bytes in 8 blocks.
Still reachable: 64 bytes in 1 blocks.
I've also tried to call the function with a temporary char pointer instead of the one returned by getenv, but that didn't help.
void parsePath(const char * line, vector<string> &pathing) {
if (line == NULL)
return;
char * s = strdup(line);
if (!s)
exit(1);
char * pch;
pch = strtok(s, ":");
while (pch!=NULL) {
string tmp = string(pch);
pathing.push_back(tmp);
pch = strtok(NULL, ":");
}
free(s);
}
I call the function in my main with.
const char *pPath;
pPath = getenv("PATH");
if (pPath == NULL)
perror("PATH");
parsePath(pPath, pathing);

It's most likely a false positive from valgrind.
In general, memory leaks aren't a big problem in modern C++, but you're clearly using an older style. If you'd use just std::string and e.g. Boost.Tokenizer, there wouldn't be anything to leak.

Related

Memory corruption on multiple 'strcat' with same src

This is a very easy problem but im stunned that i cant find a easy solution.
I am tring to create two strings that are path to files.
/Metadata/bitmap
/Metadata/Metadata.bin
but the second time i try to do the strcat() with the same src variable explodes into memory corruption
//create the dir strign to append
char* metadata_dir = strdup(MNT_POINT);
strcat(metadata_dir, "Metadata/");
char* bitmap_file = strdup("");
strcat(bitmap_file,metadata_dir);
strcat(bitmap_file,"bitmap");
printf("%s\n",bitmap_file);
char* meta_file = strdup("");
strcat(meta_file, metadata_dir);
strcat(meta_file, "Metadata.bin");
printf("%s\n",meta_file);
rigth in the line
strcat(meta_file, metadata_dir);
the memory corruption happens.
I am shure that metadata_dir is not corrupted because i can print it anywhere in the code and it looks fine.
The weird thing is that this happens depenend on the machine that is running on. In Ubuntu 64 works just fine. But in the 32bits version no.
strdup is only guaranteed to return a buffer big enough for the string you're duplicating (null terminator included); it may not (and often will not) have room for concatenating other things to it. You're overwriting random memory when you write past the end of the string with strcat.
EDIT: the solution, of course, is to malloc a buffer large enough in advance, instead of letting strdup do that.
Code fails as metadata_dir is only certainly big enough for MNT_POINT, not MNT_POINT and "Metadata/"
char* metadata_dir = strdup(MNT_POINT);
strcat(metadata_dir, "Metadata/");
To allocate and concatenate:
char *allocate_cat(const char *s1, const char *s2) {
size_t len1 = strlen(s1);
size_t size2 = strlen(s2) + 1;
char *s12 = malloc(len1 + size2); // allocate enough room for both
if (s12) {
memcpy(s12, s1, len1);
memcpy(s12 + s1, s2, size2);
}
return s12;
}

Heap corruption in code

According to the Visual C++ runtime there is a heap corruption when calling free in the destructor. But I don't understand why there is a heap corruption, can anyone explain why? The precise error is:
CRT detected that the application wrote to memory after end of heap buffer.
Also, if I ignore the error the program doesn't crash, it keeps running and when I press a key it returns 0.
The class only contains a constructor and destructor and the private vars FILE* target and char* raw_data.
foo::foo (wchar_t* path)
{
size_t size;
target = _wfopen (path, L"rb+");
if (!target) {
char* error = strerror (errno);
printf ("The file could not be opened: %s\n", error);
_exit (1);
}
fseek (target, 0L, SEEK_END);
size = ftell (target);
fseek (target, 0, SEEK_SET);
raw_data = (char*) malloc (size);
size = fread (raw_data, 1, size, target);
raw_data[size] = '\0';
}
foo::~foo ()
{
fclose (target);
free (raw_data);
}
int main ()
{
nbt* klas = new nbt (L"C:\\Users\\Ruben\\level");
puts ("Success?!");
delete klas;
getchar ();
return 0;
}
When writing the NUL terminator as you do:
raw_data[size] = '\0';
... you are using one byte more than the bytes you allocated. There may be other errors but there is definitely an error on this line -- writing to memory you have not allocated is "undefined behaviour" and could explain the crash you're observing.
One sure problem is this code:
raw_data = (char*) malloc (size);
size = fread (raw_data, 1, size, target);
raw_data[size] = '\0';
You cannot access raw_data[size], because it is beyond the allocated size. Indexed access in C/C++ is zero based. As a result, the last element of raw_data that can be accessed with your existing code is raw_data[size-1]. To be able to set the byte which is at offset size to zero you need to change your malloc to:
raw_data = (char*) malloc (size+1);
Since this is a C++ application, you may want to use streams and new/delete instead of FILE pointers and malloc/free.

Ustring error (during printing)

I want to parse UTF-8 file to ustring, I read this file in str.
There is an error:
terminate called after throwing an instance of 'Glib::ConvertError'.
What should I do?
char* cs = (char*) malloc(sizeof(char) * str.length());
strcpy(cs, str.c_str());
ustring res;
while (strlen(cs) > 0) {
gunichar ch = g_utf8_get_char(cs);
res.push_back(ch);
cs = g_utf8_next_char(cs);
}
wofstream wout("output");
cout << res << endl;
This looks very wrong:
char* cs = (char*) malloc(sizeof(str.c_str()));
as sizeof(str.c_str()) is bound to give you some small number like 4 or 8 (whichever is the size of a pointer on your machine, as the result of str.c_str().
Of course, it doesn't REALLY matter, since the next line, you are leaking the memory you just allocated incorrectly:
cs = const_cast<char*> (str.c_str());
I'm far from convinced that you need the const_cast<char *> (it is certainly WRONG to do this, since modifying the string inside a string is undefined behaviour).

realloc() issue,was not allocated

I'm trying to read a string
char *string=malloc(sizeof(char));
char *start_string=string; //pointer to string start
while ((readch=read(file, buffer, 4000))!=0){ // read
filelen=filelen+readch; //string length
for (d=0;d<readch;d++)
*start_string++=buffer[d]; //append buffer to str
realloc(string, filelen); //realloc with new length
sometimes this crashes with the following error:
malloc: *** error for object 0x1001000e0: pointer being realloc'd was not allocated
but sometimes not, I have no idea how to fix it.
realloc() does not update the pointer passed in to it. If realloc() is successful the pointer passed in is free()d and the address of the allocated memory is returned. In the posted code realloc() will attempt to free(string) multiple times, which is undefined behaviour.
Store the result of realloc():
char* t = realloc(string, filelen);
if (t)
{
string = t;
}
The address of string may change when you call realloc().
char *string=malloc(sizeof(char));
char *start_string=string; //pointer to string start
while ((readch=read(file, buffer, 4000))!=0){ // read
filelen=filelen+readch; //string length
for (d=0;d<readch;d++)
*start_string++=buffer[d]; //append buffer to str
char* tempPtr = realloc(string, filelen); //realloc with new length
if( tempPtr ) string = tempPtr;
else printf( "out of memory" );
}

Why does this code leak?

Well, here again, this time the compiler is showing me a memory error (leak):
otest(18015,0xacae32c0) malloc: * error for object 0x194e734:
incorrect checksum for freed object - object was probably modified
after being freed.
* set a breakpoint in malloc_error_break to debug
I'm using clang with ARC activated and STL, this is a C++ file (.cpp).
What I found: If I comment the "delete" line it runs without problems. It makes me wonder who is freeing my allocated memory (cStr).
Btw. This code takes a query string (arg=abc&arg2=asdb) and returns a map whit those values.
static map<string, string> getDecodedQueryString( string qs ) {
map<string, string> r;
qs = qs+"&";
char key[100], value[100], * cStr, *ptr;
cStr = new char[ qs.length() ];
memcpy( cStr, qs.c_str(), url.length()-1);
cStr[qs.length()]=0;
ptr = strtok(cStr, "&");
while ( ptr != NULL && sscanf( ptr, "%[^=]=%[^&]", &key, &value ) == 2) {
r[key]=value;
ptr = strtok(NULL, "&");
}
delete [] cStr; //leaking?
return r;
}
Thanks
The problem is likely in these lines:
cStr = new char[ qs.length() ];
memcpy( cStr, qs.c_str(), url.length()-1);
cStr[qs.length()]=0;
Even without the memcpy() (which may have its own problems due to the length of url, as I mentioned above in a comment), the cStr[qs.length()] = 0 writes one byte past the end of the buffer.
If your compiler has strdup() available (it's nonstandard, but most do), you can replace this with:
cStr = strdup(qs.c_str());
// ...
free(cStr);
This saves you from having to mess around with manually allocating bytes, copying them, null terminating in the right place, etc.
Str = new char[ qs.length() ];
...
cStr[qs.length()]=0;
That write is invalid, it's one past the end of cStr. If the allocator stored a checksum right after the allocation, and checks it at delete time, you've just stomped on it.
Something along the lines of below will do the same thing.
std::stringstream ss(qs);
std::string temp;
std::string key;
std::string value;
while(std::getline(ss, temp, '&')) {
std::stringstream equal(temp);
std::getline(equal, key, '=');
std::getline(equal, value, '=');
r[key] = value;
}