Unable to spot Memory leak issue in below code - c++

I am very new to C++. I am facing memory leak issue in my c++ code. Please see the below mentioned piece of code, which is causing the issue.
void a()
{
char buffer[10000];
char error_msg[10000];
char log_file[FILENAME_L] = "error_log.xml";
FILE *f;
f = fopen(log_file,"r");
while (fgets(buffer, 1000, f) != NULL)
{
if (strstr(buffer, " Description: ") != NULL)
{
strcpy(error_msg, buffer);
}
}
fclose(f);
actual_error_msg = trimwhitespace(error_msg);
}
Can anyone please suggest on this. Do I need to use malloc instead of hardcoded size of array?

It seems that there is undefined behaviour if variable actual_error_msg is a global variable and function trimwhitespace does not dynamically alocate memory for a copy of error_msg
actual_error_msg = trimwhitespace(error_msg);
So when the function finishes its execution pointer actual_error_msg will be invalid.
Can anyone please suggest on this
I am suggesting to allocate dynamically memory for a copy of error_msg within function trimwhitespace. Or if you already do it yourself then check whether the memory is freed in time.:)
Take into account that it looks strange that buffer is declared with the size equal to 10000 while in the fgets there is used magic number 1000.
char buffer[10000];
//,,,
while (fgets(buffer, 1000, f) != NULL)

TL;DR - In the code snippet shown above, there is no memory leak.
Do I need to use malloc instead of hardcoded size of array?
I think, you got confused by the possible underuse of char buffer[10000]; and char error_msg[10000];. These arrays are not allocated dynamically. Even the arrays are not used to their fullest capacities, there is no memory leak here.
Also, as Mr. #Vlad metioned rightly about another much possible issue in your case, actual_error_msg being a global, if the trimwhitespace() function does not have a return value which is having a global scope, (i.e., stays valid after the a() has finished execution), it may possibly lead to undefined behaviour.
To avoid that, make sure, trimwhitespace() function is either returning (assuming return type is char *)
a pointer with dynamic memory allocation (Preferred)
base address of a static array. (bad practice, but will work)
To elaborate, from the Wikipedia article about "memory leak"
In computer science, a "memory leak" is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released. ...
and
.. Typically, a memory leak occurs because dynamically allocated memory has become unreachable. ...
When memory is being allocated by your compiler, there is no scope of memory leak, as the memory (de)allocation is managed by the compiler.
OTOH, with dynamic memory allocation, allocation of memory is performed at runtime. Compiler has no information about the allocation, memory is allocated programatically, hence need to be freed programatically, also. Failing to do so leads to the "memory leak".

Related

What is the difference between memory leak, accessing freed memory and double free?

I'm trying to figure out what is the difference between those three kinds of problems associated with memory models.
If I want to simulate a memory leak scenario, I can create a pointer without calling corresponding delete method.
int main() {
// OK
int * p = new int;
delete p;
// Memory leak
int * q = new int;
// no delete
}
If I want to simulate a double free scenario, I can free a pointer twice and this part memory will be assigned twice later.
a = malloc(10); // 0xa04010
b = malloc(10); // 0xa04030
c = malloc(10); // 0xa04050
free(a);
free(b); // To bypass "double free or corruption (fasttop)" check
free(a); // Double Free !!
d = malloc(10); // 0xa04010
e = malloc(10); // 0xa04030
f = malloc(10); // 0xa04010 - Same as 'd' !
However, I don't know what is accessing freed memory. Can anybody give me an example of accessing freed memory?
Memory leaks are bad.
Double frees are worse.
Accessing freed memory is worser.
Memory leaks
This is not an error per se. A leaking program is stil valid. It may not be a problem. But this is still bad; with time, your program will reserve memory from the host and never release it. If the host's memory is full before the program completion, you run into troubles.
Double frees
Per the standard, this is undefined behaviour. In practice, this is almost always a call to std::abort() by the C++ runtime.
Accessing freed memory
Also undefined behaviour. But in some case, nothing bad will happen. You'll test your program, put it in production. And some day, for no apparent reason, it will break. And it will break hard: randomly. The best time to rework your résumé.
And here is how to access freed memory:
// dont do this at home
int* n = new int{};
delete n;
std::cout << *n << "\n"; // UNDEFINED BEHAVIOUR. DONT.
Your examples of a memory leak (allocating memory but freeing it) and double-free (passing a pointer to allocated memory to free / delete more than once) are correct.
Performing a double-free does not however mean that a section of memory will be returned more than once by malloc as your example indicates. What it does do is invoke undefined behavior, meaning the behavior of your program cannot be predicted going forward.
Accessing free'ed memory means freeing a pointer and then subsequently trying to use it:
int *a = malloc(10 * sizeof(int)); // allocate memory
free(a); // free memory
print("a[0]=%d\n", a[0]); // illegal: use after free
You are correct about making a memory leak and a double-free. Accessing freed memory happens when you dereference a pointer that has been freed:
int *ptr = malloc(sizeof(int));
*ptr = 123;
free(ptr);
int invalid = *ptr; // Accessing freed memory
Problems like this are notoriously hard to detect, because the program continues to work as expected for some time. If you expect to reuse the pointer variable at some later time, it is a good idea to assign it NULL immediately after calling free. This way a subsequent dereference would fail fast.
I'm trying to figure out what is the difference between those three kinds of problems associated with memory models.
memory leak - you dynamically allocate memory and never release it.
double free - you dynamically allocate memory and release it multiple times
accessing after free - you dynamically allocate memory then release and access that memory after release.

Memory leak on deallocating char * set by strcpy?

I have a memory leak detector tool which tells me below code is leaking 100 bytes
#include <string>
#include <iostream>
void setStr(char ** strToSet)
{
strcpy(*strToSet, "something!");
}
void str(std::string& s)
{
char* a = new char[100]();
setStr(&a);
s = a;
delete[] a;
}
int main()
{
std::string s1;
str(s1);
std::cout << s1 << "\n";
return 0;
}
According to this point number 3 it is leaking the amount I allocated (100) minus length of "something!" (10) and I should be leaking 90 bytes.
Am I missing something here or it is safe to assume the tool is reporting wrong?
EDIT: setStr() is in a library and I cannot see the code, so I guessed it is doing that. It could be that it is allocating "something!" on the heap, what about that scenario? Would we have a 90 bytes leak or 100?
This code does not leak and is not the same as point number 3 as you never overwrite variables storing pointer to allocated memory. The potential problems with this code are that it is vulnerable to buffer overflow as if setStr prints more than 99 symbols and it is not exception-safe as if s = a; throws then delete[] a; won't be called and memory would leak.
Updated: If setStr allocates new string and overwrites initial pointer value then the pointer to the 100 byte buffer that you've allocated is lost and those 100 bytes leak. You should initialize a with nullptr prior to passing it to setStr and check that it is not null after setStr returns so assignment s = a; won't cause null pointer dereference.
Summing up all the comments, it is clear what the problem is. The library you are using is requesting a char **. This is a common interface pattern for C functions that allocate memory and return a pointer to that memory, or that return a pointer to memory they own.
The memory you are leaking is allocated in the line char* a = new char[100]();. Because setStr is changing the value of a, you can no longer deallocate that memory.
Unfortunately, without the documentation, we cannot deduce what you are supposed to do with the pointer.
If it is from a call to new[] you need to call delete[].
If it is from a call to malloc you need to call std::free.
If it is a pointer to memory owned by the library, you should do nothing.
You need to find the documentation for this. However, if it is not available, you can try using your memory leak detection tool after removing the new statement and see if it detects a leak. I'm not sure if it is going to be reliable with memory allocated from a library function but it is worth a try.
Finally, regarding the question in your edit, if you leak memory you leak the whole amount, unless you do something that is undefined behavior, which is pointless to discuss anyway. If you new 100 chars and then write some data on them, that doesn't change the amount of memory leaked. It will still be 100 * sizeof(char)

Potential memory leak?

The following code resolves the problem of removing the duplicate characters in a string.
void removeDuplicatesEff(char *str)
{
if (!str)
return;
int len = strlen(str);
if (len < 2)
return;
const int sz = (1<<CHAR_BIT);
bool hit[sz] = {false};
int tail = 0;
for (int i=0; i<len; ++i)
{
if (!hit[str[i]])
{
str[tail] = str[i];
++tail;
hit[str[i]] = true;
}
}
str[tail] = 0;
}
After setting str[tail]=0 in the last step, if char *str does contain duplicate characters, its size will be smaller, i.e. tail. But I am wondering whether there is a memory leak here? It seems to me that, later, we cannot releasing all the spaces that is allocated to original char *str. Is this right? If so, how can we resolve it in such situations?
It seems to me that, later, we cannot releasing all the spaces that is allocated to original char *str. Is this right?
No. The length of a zero-terminated string is completely decoupled from the size of the allocated memory buffer, and the system treats it separately. As long as every allocation is followed by a symmetrical deallocation (e.g. there’s a free for every malloc operation), you’re safe.
But I am wondering whether there is a memory leak here?
Arguably, yes, this is still a leak since it (temporarily) uses more memory than required. However, that is usually not a problem since the memory gets released eventually. Except in very special circumstances, this would therefore not be considered a leak.
That said, the code is quite unconventional and definitely longer than necessary (it also assumes that CHAR_BIT == 8 but that’s another matter). For instance, you can initialise your flag array much easier, saving a loop:
bool hit[256] = {false};
And why is your loop going over the string one-based, and why is the first character handled separately?
No, there is no leak. You only modify the contents of the array by putting in 0 and not its length.
Also you shouldn't initialize your hit array by assignment with the for-loop. A standard initialization
bool hit[256] = { 0 };
would suffice and can be replaced by your compiler by the most efficient form of initialization.
There is no memory leak in your case. Memory leak happens when you allocate memory from head and not freeing after using it. In your case you are not allocating any memory from heap. You are using local variables which are stored in stack and freed when control returns from that function.
What you are doing is just changing the placement of the terminator character. It doesn't actually change the size of the allocated memory. It's actually a very common operation, and there is no risk of memory leak from doing it.
No, you will not have a memory leak. Performing a delete [] or free() on str will deallocate all allocated memory just fine because that information is stored elsewhere and does not depend on the type of data being stored in str.
But I am wondering whether there is a memory leak here? It seems to me that, later, we cannot releasing all the spaces that is allocated to original char *str
There's probably no problem here. the storage for str has been allocated in one of the following ways:
reserved space on the stack
malloc space on the heap
reserved space in the data segment.
In the first case, all of the space disappears when the stack frame unwinds. In the second case, malloc records the number of bytes allocated (usually in the memory location just before the first byte pointed to by the malloc return value. In the third case, the space is allocated only once when the program is first loaded.
No possibility of a leak there.

Why are we able to access unallocated memory in a class?

I am sorry if I may not have phrased the question correctly, but in the following code:
int main() {
char* a=new char[5];
a="2222";
a[7]='f'; //Error thrown here
cout<<a;
}
If we try to access a[7] in the program, we get an error because we haven't been assigned a[7].
But if I do the same thing in a class :
class str
{
public:
char* a;
str(char *s) {
a=new char[5];
strcpy(a,s);
}
};
int main()
{
str s("ssss");
s.a[4]='f';s.a[5]='f';s.a[6]='f';s.a[7]='f';
cout<<s.a<<endl;
return 0;
}
The code works, printing the characters "abcdfff".
How are we able to access a[7], etc in the code when we have only allocated char[5] to a while we were not able to do so in the first program?
In your first case, you have an error:
int main()
{
char* a=new char[5]; // declare a dynamic char array of size 5
a="2222"; // assign the pointer to a string literal "2222" - MEMORY LEAK HERE
a[7]='f'; // accessing array out of bounds!
// ...
}
You are creating a memory leak and then asking why undefined behavior is undefined.
Your second example is asking, again, why undefined behavior is undefined.
As others have said, it's undefined behavior. When you write to memory out of bounds of the allocated memory for the pointer, several things can happen
You overwrite an allocated, but unused and so far unimportant location
You overwrite a memory location that stores something important for your program, which will lead to errors because you've corrupted your own memory at that point
You overwrite a memory location that you aren't allowed to access (something out of your program's memory space) and the OS freaks out, causing an error like "AccessViolation" or something
For your specific examples, where the memory is allocated is based on how the variable is defined and what other memory has to be allocated for your program to run. This may impact the probability of getting one error or another, or not getting an error at all. BUT, whether or not you see an error, you shouldn't access memory locations out of your allocated memory space because like others have said, it's undefined and you will get non-deterministic behavior mixed with errors.
int main() {
char* a=new char[5];
a="2222";
a[7]='f'; //Error thrown here
cout<<a;
}
If we try to access a[7] in the program, we get an error because we
haven't been assigned a[7].
No, you get a memory error from accessing memory that is write-protected, because a is pointing to the write-only memory of "2222", and by chance two bytes after the end of that string is ALSO write-protected. If you used the same strcpy as you use in the class str, the memory access would overwrite some "random" data after the allocated memory which is quite possibly NOT going to fail in the same way.
It is indeed invalid (undefined behaviour) to access memory outside of the memory you have allocated. The compiler, C and C++ runtime library and OS that your code is produced with and running on top of is not guaranteed to detect all such things (because it can be quite time-consuming to check every single operation that accesses memory). But it's guaranteed to be "wrong" to access memory outside of what has been allocated - it just isn't always detected.
As mentioned in other answers, accessing memory past the end of an array is undefined behavior, i.e. you don't know what will happen. If you are lucky, the program crashes; if not, the program continues as if nothing was wrong.
C and C++ do not perform bounds checks on (simple) arrays for performance reasons.
The syntax a[7] simply means go to memory position X + sizeof(a[0]), where X is the address where a starts to be stored, and read/write. If you try to read/write within the memory that you have reserved, everything is fine; if outside, nobody knows what happens (see the answer from #reblace).

Run time error while using realloc: " _CrtIsValidHeapPointer(pUserData), dbgheap.c"

The following code is written in C++ but using realloc from stdlib.h because I don't know much about std::vector.
Anyway, I get this weird run time error " " _CrtIsValidHeapPointer(pUserData), dbgheap.c".
If you would like to see the whole method or code please let me know.
I have 2 classes, Student and Grades. Student contains
char _name[21];
char _id[6];
int _numOfGrades;
int* _grades;
float _avg;
and Grade simply contains
Student* _students;
int _numOfStudents;
while the following works
_grades = (int *)realloc(_grades,(sizeof(int)*(_numOfGrades+1)));
this will create that weird run time error:
_students = (Student *)realloc(_students,(sizeof(Student)*(_numOfStudents+1)));
Both _grades and _students are created with new with no problem at all. The problem is only while trying to realloc _students.
Any input will be welcome.
You cannot mix allocators—if you allocate memory with operator new[], you must deallocate it with operator delete[]. You cannot use free(), realloc(), or any other memory allocator (e.g. Windows' GlobalFree()/LocalFree()/HeapFree() functions).
realloc() can only reallocate memory regions which were allocated with the malloc() family of functions (malloc(), calloc(), and realloc()). Attempting to realloc any other memory block is undefined behavior—in this case, you got lucky and the C runtime was able to catch your error, but if you were unlucky, you might silently corrupt memory and then later crash at some random point in an "impossible" state.