I am just curious about how memory leaks happens when you write a C program.
Are the following are examples of memory leaks?
Trying to access the part of the memory whose access is not given to your program or when you are trying to access the location of the array which is not there.
#include <stdio.h>
int main(void)
{
int num[5];
int i;
for(i=0;i<5;i++)
scanf("%d", (num+i));
printf("%d\n", num[5]); //printing the data stored at loc num[5] which is not present.
return 0;
}
Printing the value stored in an un-initialized variables.
Use of void*memcpy(const*dst,void const*src,size_t n) function memory leak occurs when src and dst pointers points to the same memory address or function is undefined when addresses overlaps.
Use of free() more than once on the same pointers which has been freed already. For Example:
#include <stdio.h>
int main(void)
{
int*num = NULL;
int i;
num = (int*) calloc(sizeof(int), 5);
for (i = 0; i < 5; i++)
scanf("%d", (num + i));
free(num);
free(num);
return 0;
}
All of aforesaid scenarios cause undefined behavior.
printf("%d\n", num[5]); is out-of-bound memory access.
Printing the value stored in an un-initialized variables, in case of the variable has trap representation, causes UB.
Source and destination overlap in memcpy(), UB.
Multiple free() is also UB.
Also, memory leak is not about any invalid access, it is just wastage of memory leading to out of memory scenario for a system. You can read more about that here.
Related
#include <stdio.h>
int main()
{
int i,a;
int* p;
p=&a;
for(i=0;i<=10;i++)
{
*(p+i)=i;
printf("%d\n",*(p+i));
}
return 0;
}
I tried to assign numbers from 0 to 10 in a sequence memory location without using an array.
You are trying to write to memory that it does not have permission to access.
The variable a is a local variable in the main function, and it is stored on the stack. The pointer p is initialized to point to the address of a. The code then attempts to write to the memory addresses starting at p and going up to p+10. However, these memory addresses are not part of the memory that has been allocated for the program to use, and so the program receives a segmentation fault when it tries to write to them.
To fix this issue, you can either change the loop condition to a smaller value, or you can allocate memory dynamically using malloc or calloc, and assign the pointer to the returned address. This will allow you to write to the allocated memory without causing a segmentation fault.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int* p = malloc(sizeof(int) * 11); // Allocate memory for 10 integers
if (p == NULL) { // Check for allocation failure
printf("Error allocating memory\n");
return 1;
}
for(i=0;i<=10;i++)
{
*(p+i)=i;
printf("%d\n",*(p+i));
}
free(p); // Free the allocated memory when you are done with it
return 0;
}
a is only an integer. not an array.
you need to declare it differently:
int i, a[10];
You can not. Memory of int is 4 bytes and you can store only single number in that memory.
for int: -2,147,483,647 to 2,147,483,647
for unsigned int: 0 to 4, 294, 967 295
There are other types you can use with different sizes, but if you want to put different numbers into one variable you need to use array.
int arr[10];
arr[0] = 0;
arr[1] = 5;
something like this.
I know that on your hard drive, if you delete a file, the data is not (instantly) gone. The data is still there until it is overwritten. I was wondering if a similar concept existed in memory. Say I allocate 256 bytes for a string, is that string still floating in memory somewhere after I free() it until it is overwritten?
Your analogy is correct. The data in memory doesn't disappear or anything like that; the values may indeed still be there after a free(), though attempting to read from freed memory is undefined behaviour.
Generally, it does stay around, unless you explicitly overwrite the string before freeing it (like people sometimes do with passwords). Some library implementations automatically overwrite deallocated memory to catch accesses to it, but that is not done in release mode.
The answer depends highly on the implementation. On a good implementation, it's likely that at least the beginning (or the end?) of the memory will be overwritten with bookkeeping information for tracking free chunks of memory that could later be reused. However the details will vary. If your program has any level of concurrency/threads (even in the library implementation you might not see), then such memory could be clobbered asynchronously, perhaps even in such a way that even reading it is dangerous. And of course the implementation of free might completely unmap the address range from the program's virtual address space, in which case attempting to do anything with it will crash your program.
From a standpoint of an application author, you should simply treat free according to the specification and never access freed memory. But from the standpoint of a systems implementor or integrator, it might be useful to know (or design) the implementation, in which case your question is then interesting.
If you want to verify the behaviour for your implementation, the simple program below will do that for you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The number of memory bytes to test */
#define MEM_TEST_SIZE 256
void outputMem(unsigned char *mem, int length)
{
int i;
for (i = 0; i < length; i++) {
printf("[%02d]", mem[i] );
}
}
int bytesChanged(unsigned char *mem, int length)
{
int i;
int count = 0;
for (i = 0; i < MEM_TEST_SIZE; i++) {
if (mem[i] != i % 256)
count++;
}
return count;
}
main(void)
{
int i;
unsigned char *mem = (unsigned char *)malloc(MEM_TEST_SIZE);
/* Fill memory with bytes */
for (i = 0; i < MEM_TEST_SIZE; i++) {
mem[i] = i % 256;
}
printf("After malloc and copy to new mem location\n");
printf("mem = %ld\n", mem );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
free(mem);
printf("\n\nAfter free()\n");
printf("mem = %ld\n", mem );
printf("Bytes changed in memory = %d\n", bytesChanged(mem, MEM_TEST_SIZE) );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
}
Here is the code I'm using:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
The program doesn't print OK. malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
This is how it was designed more than 40 years ago.
But, at the same time, the calloc() function was created that initializes the allocated memory to zero and it's the recommended way to allocate memory for arrays.
The line:
arr = (int *)malloc(sz * sizeof(int));
Should read:
arr = calloc(sz, sizeof(int));
If you are learning C from an old book it teaches you to always cast the value returned by malloc() or calloc() (a void *) to the type of the variable you assign the value to (int * in your case). This is obsolete, if the value returned by malloc() or calloc() is directly assigned to a variable, the modern versions of C do not need that cast any more.
The man page of malloc says:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
So malloc() returns uninitialized memory, the contents of which is indeterminate.
if (arr[i] != 0)
In your program, You have tried to access the content of a memory block, which is invoked undefined behavior.
malloc isn't supposed to initialize the allocated memory to zero.
Memory allocated by malloc is uninitialised. Value at these locations are indeterminate. In this case accessing that memory can result in an undefined behavior if the value at that location is to be trap representation for the type.
n1570-ยง6.2.6.1 (p5):
Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. [...]
and footnote says:
Thus, an automatic variable can be initialized to a trap representation without causing undefined behavior, but the value of the variable cannot be used until a proper value is stored in it.
Nothing good can be expected if the behavior is undefined. You may or may not get expected result.
From the C Standard 7.22.3.4:
Synopsis
#include <stdlib.h>
void *malloc(size_t size);
Description
The malloc function allocates space for an object whose size is
specified by size and whose value is indeterminate.
The value is indeterminate. So, every compiler is free to behave how it wants. For example, in Microsoft Visual C++, in Debug mode, the area of allocated memory by malloc() is all set to 0xCDCDCDCD and when in Release mode it is random. In modern versions of GCC, it is set to 0x000000 if you don't enable code optimizations, and random otherwise. I don't know about other compilers, but you get the idea.
void *malloc(size_t size) is just supposed to keep aside the specified amount of space. That's all. There is no guarantee as to what will be present in that space.
Quoted from the man pages:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
Apart from calloc() you can use the memset() function to zero out a block of memory.
The first time you call malloc(3), it asks to the operating system to get memory for the heap space.
For security reasons, the unix/linux kernel (and many other operating systems) in general zeroes the page contents that is to be given to a process, so no process can access that memory's previous contents and do nasty things with it (like searching for old passwords, or similar things).
If you do several allocations and deallocations of memory, when the malloc module reuses the previous memory, you'll see garbage coming from malloc(3).
Zero's are assigned to page contents at first time in linux kernel.
Below program explains the memory initialisation difference in malloc and calloc:
#include<stdio.h>
#include<stdlib.h>
#define SIZE 5
int main(void) {
int *mal = (int*)malloc(SIZE*sizeof(int));
int *cal = (int*)calloc(SIZE, sizeof(int));
mal[4] = cal[4] = 100;
free(mal); free(cal);
mal = (int*)malloc(SIZE*sizeof(int));
cal = (int*)calloc(SIZE, sizeof(int));
for(int i=0; i<SIZE; i++) {
printf("mall[%d] = %d\n", i, mal[i]);
}
for(int i=0; i<SIZE; i++) {
printf("call[%d] = %d\n", i, cal[i]);
}
}
I use malloc to allocate everything from the heap(dynamic memory) while i should use calloc instead nowaday , and memset is great for filling you memory segment with any chosen character.
Compile and work great with GCC:
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
memset(arr, 0, sz*sizeof(int) );
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
ref: http://www.cplusplus.com/reference/cstring/memset/
well, the value is not initialized in malloc.
And it does print "OK" in VS Code.
so in VS Code, the output is : "OK" followed by a garbage value.
in a web based compiler (here's the link : https://www.programiz.com/c-programming/online-compiler/ ),
the output was
"LOL" followed by '0'
so some compilers do initialize the value..but actually the value in malloc is not intialized. so it will return a garbage value when printed as in the above example in VS Code.
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; i++)
{
if (arr[i] != 0)
{
printf("OK\n");
break;
}
else
{
printf("LOL \n");
break;
}
}
printf("%d", arr[0]);
free(arr);
I am freeing the memory allocated to b. But I was under the impression that memory allocated dynamically disappears after you "free" it. But I am not getting any errors with this code and I can still access the original values assigned to elements of b even after freeing it. How is this possible ? What should I do to completely erase b ?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc,char* argv[])
{
int i, imax;
int *b;
imax=5;
b=malloc(sizeof(int)*imax);
for (i=0; i < imax; i++)
{
b[i]=i*i;
printf("%d ",b[i]);
}
free(b);
printf("\n memory freed \n");
for (i=0; i < imax; i++)
{
printf("%d ",b[i]);
}
printf("\n");
return 0;
}
result after compiling with gcc and running it
0 1 4 9 16
memory freed
0 1 4 9 16
This is an example of undefined behavior. There are many different possibilities, including:
The memory read is the exact same, because the C library just marked it as free without touching it
The memory read is garbage, because something else reused that newly-freed block
Your program crashes, because the address is no longer acceptable.
Your computer launches a nuclear missile headed for Antarctica, because hey, anything is possible with undefined behavior!
So please, for the sake of the cute little penguins, avoid reading freed memory!
Accessing an object after it has been free'd with free invokes undefined behavior. Don't do it.
That is:
for (i=0; i < imax; i++)
{
printf("%d ",b[i]); // invokes undefined behavior!
}
If you are unlucky nothing will happen but everything can happen from crash to nasal demons.
I know that on your hard drive, if you delete a file, the data is not (instantly) gone. The data is still there until it is overwritten. I was wondering if a similar concept existed in memory. Say I allocate 256 bytes for a string, is that string still floating in memory somewhere after I free() it until it is overwritten?
Your analogy is correct. The data in memory doesn't disappear or anything like that; the values may indeed still be there after a free(), though attempting to read from freed memory is undefined behaviour.
Generally, it does stay around, unless you explicitly overwrite the string before freeing it (like people sometimes do with passwords). Some library implementations automatically overwrite deallocated memory to catch accesses to it, but that is not done in release mode.
The answer depends highly on the implementation. On a good implementation, it's likely that at least the beginning (or the end?) of the memory will be overwritten with bookkeeping information for tracking free chunks of memory that could later be reused. However the details will vary. If your program has any level of concurrency/threads (even in the library implementation you might not see), then such memory could be clobbered asynchronously, perhaps even in such a way that even reading it is dangerous. And of course the implementation of free might completely unmap the address range from the program's virtual address space, in which case attempting to do anything with it will crash your program.
From a standpoint of an application author, you should simply treat free according to the specification and never access freed memory. But from the standpoint of a systems implementor or integrator, it might be useful to know (or design) the implementation, in which case your question is then interesting.
If you want to verify the behaviour for your implementation, the simple program below will do that for you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The number of memory bytes to test */
#define MEM_TEST_SIZE 256
void outputMem(unsigned char *mem, int length)
{
int i;
for (i = 0; i < length; i++) {
printf("[%02d]", mem[i] );
}
}
int bytesChanged(unsigned char *mem, int length)
{
int i;
int count = 0;
for (i = 0; i < MEM_TEST_SIZE; i++) {
if (mem[i] != i % 256)
count++;
}
return count;
}
main(void)
{
int i;
unsigned char *mem = (unsigned char *)malloc(MEM_TEST_SIZE);
/* Fill memory with bytes */
for (i = 0; i < MEM_TEST_SIZE; i++) {
mem[i] = i % 256;
}
printf("After malloc and copy to new mem location\n");
printf("mem = %ld\n", mem );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
free(mem);
printf("\n\nAfter free()\n");
printf("mem = %ld\n", mem );
printf("Bytes changed in memory = %d\n", bytesChanged(mem, MEM_TEST_SIZE) );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
}