I am debugging some code written by someone else which has several memory leaks detected by Valgrind. Part of the code which I believe is causing the problems involves void pointers:
int noElements = 100;
void** ptr = malloc( noElements * sizeof(void*));
for(int i = 0; i < noElements; i++)
{
ptr[i] = malloc(sizeof(void*));
}
//Operation filling the array and doing calculation
free(ptr); //This will not clear the underlying array causing the memory leak?
I created a small test program to check the error is where I thought it was (not freeing each ptr[i] before calling free(ptr);), but I am getting errors when trying to free elements. My test program looks like this:
int main()
{
int num = 10000000; //Large array so I can clearly see memory usage
void** ptr = (void**) malloc(sizeof(void*) * num);
for (int i = 0; i < num; i++)
{
ptr[i] = malloc(sizeof(void*));
ptr[i] = &i; //If I never point elements at anything, this code works
}
for (int i = 0; i < num; i++)
{
free(ptr[i]); //Crashes here if the elements have been pointed at a variable
}
free(ptr);
return 0;
}
Why would calling free on each array element cause the program to crash if the pointers have actually been assigned?
In your code
ptr[i] = &i;
creates three issues.
It makes the actual returned pointer by malloc() to be lost (you're overwriting it), so you have no shot at free()-ing it later, leading to memory leak.
i is a local scoped variable (the scope of for loop body), and you're storing the address of the variable to be used outside the scope (i.e., after the lifetime is over). Outside the scope attempt to access the address of it will invoke undefined behavior.
(Ignoring point 2) Attempt to free() the ptr[i] will cause undefined behavior again, as the pointer is not returned by memory allocator function.
Your pointers have been assigned a value which is not what you want.
for (int i = 0; i < num; i++)
{
ptr[i] = malloc(sizeof(void*));
ptr[i] = &i; //If I never point elements at anything, this code works
}
First you assign a valid memory address that is returned by malloc().
This address could be free'd using free().
But then you assign another address. The address of your local variable i. This memory location was not allocated using malloc() and hence cannot be free'd. By assigning this address you've lost the dynamically allocated address causing a memory leak.
Your comment is wrong. You already assigned a value that ptr[i] points to some valid address. You don't need to assign again. And you should not.
Related
I am getting the memory leak due to first malloc call. I tried to comment out and free but there is no way that I can fix it.
The code wants to parse the query than put the information inside the map. At the same time it is going to update struct too
row_ = atoi(strtok(NULL,",:"));
col_ = atoi(strtok(NULL,",:"));
}
}
For starters this for loop
for(int j = 0; j < strlen(query); j++){
if(!strcmp(&query[j], ",")){
count++;
}
}
does not make a sense. It seems you mean instead
for(int j = 0; j < strlen(query); j++){
if( query[j] == ',')){
count++;
}
}
You allocated memory and its address is assigned to the pointer type.
char* type = malloc(sizeof(char *));
// char* char_name= (char *)malloc(1);
then the pointer was reassigned
type = strtok(query, ",:");
So the address of the allocated memory is lost and you have a memory leak.
This commented declaration
char* char_name= (char *)malloc(1);
also invokes a memory leak due to the statement
char_name = strtok(NULL,",:");
This statement
char_name = realloc(char_name, sizeof(char_name)+1);
does not make a sense at least because sizeof( char_name ) is equivalent to sizeof( char * ). It seems you mean at least
char_name = realloc(char_name, strlen(char_name) + 2 );
But in any case you may not reallocate the memory using the pointer because it does not point to a dynamically allocated memory after this statement
char_name = strtok(NULL,",:");
examine these 2 lines of code
char* type=malloc(sizeof(char *)); <<<<<<=======
// char* char_name= (char *)malloc(1);
int row_,col_;
int count =0;
for(int j=0;j<strlen(query);j++){
if(!strcmp(&query[j],",")){
count++;
}
}
count=(count+1)/3;
type = strtok(query, ",:"); <<<<<<=======
You malloc some memory, do nothing with it and then overwrite the pointer. So now there is no way to free it or use it.
As far as I can see you just need
char*type = NULL;
and take out the frees of type too.
Note - I have not verified the rest of the code. Just answered your leak question. The way you are using strtok is certainly not idiomatic. And I suspect that you think
type = strtok(query, ",:");
copies the first token into the buffer pointed at by type. It does not, what you need is this
type = strdup(strtok(query, ",:"));
Likewise the assignments in the loop
char_name = strtok(NULL,",:");
char_name = realloc(char_name, sizeof(char_name)+1);
are very wrong. You cannot realloc the return of strtok. Again you need
char_name = strdup(strtok(NULL,",:"));
I want to allocate memory dynamically inside a function. The function is named func_1 and is declared as follows:
int func_1(int **destination);
Here destination is a pointer to a pointer. This pointer contains the address of the pointer to which I want to allocate memory dynamically inside the function.
The function func_1 has the following code:
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
*destination[i] = i; //segmentation fault comes HERE
}
}
Below is my main() function:
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
When I try to run this program, I get a segmentation fault (SIGSEGV) error. I used GDB to locate the source of this fault, and it turned out that the line inside the for loop is the culprit for this error.
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
I want to know:
Why am I getting this error ?
How can this be fixed ?
Thanks for help !
[] (array subscripting) operator has precedence 2
* (dereference) operator has precedence 3
In your code *destination[i] means the same as *(destination[i]). This value is uninitialized and it leads to segmentation fault.
If you will use explicit priority of operation (*destination)[i] you will get the expected result.
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i; //no segmentation fault
}
}
you can read more about precedence here
Full code:
#include <stdio.h>
#include <stdlib.h>
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i;
}
}
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
Why am I getting this error ?
You are overwriting the destination pointer instead of assigning the value returned by malloc to the pointer pointed to by the destination pointer.
Instead of *destination = (int*)malloc(sizeof(int) * 10) you should type **destination = malloc(sizeof(int) * 10).
Instead of *destination[i] = i you should type (**destination)[i] = i.
In C, the array subscript operator [] has a higher precedence than the indirection operator *. In addition to that, the former is left-to-right associative, while the latter is right-to-left associative.
In your case this means that you need to type (**destination)[i] = i; instead of **destination[i] = i, because otherwise the [i] will be evaluated before the ** and you end up indirecting a wild pointer (which will cause a segmentation fault extremely likely in the general and absolutely certainly in this case, since you are referencing a null pointer when i == 0).
How can this be fixed ?
The "just make it work" fix is the one I presented above.
However, that does not address the fundamental issue with your code, which is that it is unnecessarily complicated. Using a pointer to a pointer is very error-prone and should be avoided. Indeed, there is no need to use one at all in this case.
The following does exactly what you want without all the unnecessary complexity:
int* func_1()
{
int* destination = malloc(sizeof(int) * 10);
for (int i = 0; i < 10; ++i)
{
destination[i] = i;
}
return destination;
}
int main()
{
int* pointer = func_1();
free(pointer);
return 0;
}
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
As I demonstrated above, there is no reason to pass a pointer to the pointer to the function. Memory allocated with malloc is yours to use forever , you just need to keep track of it and release it with a call to free when you no longer need it. How you keep track of the memory doesn't matter - simply returning a pointer is enough in this case. Modifying pointer inside func_1 rather than catching the function's return value provides no additional benefit and only serves to make the code more complicated than it needs to be.
I get the impression that you are somewhat confused about pointers, so I recommend that you revise the subject. Here is a quite clear explanation regarding pointers that also covers pointers to pointeres (and pointers to pointers to pointers): How do pointers work in C?
Read more:
Operator Precedence and Associativity in C
What is a segmentation fault?
int x;
int komsuSayisi;//adjanceny matrix
int **arkadas;
int t;
int komsu[24][24];
scanf("%d",&t);
**arkadas = (int **)malloc( t*sizeof( int* )); //allocating rows
for(i=0; i<t; i++)
{
x=0;
arkadas[i] = (int *)malloc( t*sizeof(int) ); //allocating cow temporarily
for(j=0; j<t; j++)
{
komsu[i][j]=fark(kelime[i],kelime[j]); //fark returns 1 or 0.
//so i put those 1 ones to another matrix,arkadas
if(komsu[i][j]==1){
komsuSayisi++;
arkadas[i][x]=j;
x++;
}
arkadas[i] = (int *) realloc(arkadas[i], x);
//real allocating here
}
It gives error and shut downs.There is nothing wrong. What i want is adjanceny is too big to search so i will easily search the "1" ones with this matrix.
**arkadas = (int **)malloc( t*sizeof( int* ));
should be
arkadas = malloc( t*sizeof( int* ));
**arkadas dereferences an uninitialised pointer, resulting in you trying to write to an unpredictable address. You don't own the memory at this address so it isn't safe to try and write to it.
The second form assigns the address of an array of pointers to the local variable arkadas; this is what need to do.
Later in your program
if(komsu[i][j]==1){
komsuSayisi++;
arkadas[i][x]=j;
x++;
}
arkadas[i] = (int *) realloc(arkadas[i], x);
code inside the if condition attempts to write to arkadas[i] before you allocate it. This also invokes undefined behaviour and will likely crash. You can avoid the crash by removing the line arkadas[i][x]=j; and swapping your realloc call for malloc (you need the address of a previous allocation before you can call realloc)
if(komsu[i][j]==1){
komsuSayisi++;
x++;
}
arkadas[i] = malloc(x*sizeof(int));
I see
komsuSayisi++;
You didn't paste the whole code but probably thats what is crashing your program... I don't see any initializing previous to that increment....
this plus the deferentiation posted on the other answer
char** removeDuplicateChromosomes(char* input[], int no_of_chromosomes)
{
char** result = (char**) malloc(sizeof(char* )*(no_of_chromosomes));
//some piece of code
result[count] = input[itr];
//some piece of code . I didn't free any pointers here in this function
return result;
}
Can someone help me to identify any dangling pointers (if present) and explain the same pls?
Memory leak - if no pointer points to unfreed memory.
Dangling pointer - a pointer that points to freed memory.
Your code has a significant risk of either / both, though without a complete code sample, it's impossible to tell whether either would occur. I'll just give some possible scenario's of when it could happen.
As an initial note, If you don't free result's memory in the calling function, you'd have a memory leak. Any malloc must have a corresponding free.
If you free input like this:
free(input);
There would not be a dangling pointer.
But then there may be a memory leak if each element of input doesn't have an element of result pointing to the same memory. And if multiple elements of result point to this memory, you'll probably end up with a dangling pointer when you try to free it, along with some undefined behaviour.
If you free input like this:
int i;
for (i = 0; i < inputSize; i++)
free(input[i]);
free(input);
There would be a dangling pointer.
Why?
input[itr]; is a pointer.
result[count] = input[itr]; just makes result[count] point to the same memory as what input[itr] points to.
So if we free input[itr], result[count] would point to freed memory, and thus be dangling.
If we don't free input[itr], result[count] will still point to valid memory.
If you want result[count] to point to its own memory, you'll have to use:
result[count] = malloc(inputItrSize);
memcpy(result[count], input[itr], inputItrSize);
Note - there's no way to tell how much memory input[itr] is pointing to, so you'll have to declare inputItrSize with the appropriate size yourself.
A dangling pointer is a pointer to a memory area that is no-longer allocated.
char* dangleMeBaby(char* obj) {
free(obj);
return obj;
}
int* localDangle() {
int i = 10;
return &i;
}
#define NUM_POINTERS 8
char** wholeLottaDangle() {
char* ptr = malloc(sizeof(char*) * NUM_POINTERS);
size_t i;
void* data = malloc(NUM_POINTERS);
for (i = 0; i < NUM_POINTERS; ++i) {
ptr[i] = data + i;
}
free(data); // all the pointers in ptr now dangle.
free(ptr); // and ptr itself is now a dangle
return ptr;
}
If you have allocated input as one big block of pointers + data, then freeing input before result will turn result into an array of dangling pointers.
size_t indexSize = sizeof(char*) * numChromosomes;
size_t chromosomeSize = (MAX_CHROMOSOME_LEN) * numChromosomes;
char* data = malloc(indexSize + chromosomeSize);
char** input = (char**)data;
char* chromosome = data + indexSize;
for (size_t i = 0; i < numChromosomes; ++i, chromosome += MAX_CHROMOSOME_LEN) {
input[i] = chromosome;
}
// no dangling pointers in result until you free input.
If you have allocated chromosomes individually and then allocated "input" to house all the pointers, then freeing a chromosome without removing it from "result" will cause a dangling pointer
result = removeDuplicateChromosomes(input, 64);
free(input[0]); // result still points to it, result is dangling.
But if input and the list of chromoes remain intact until you free input() and/or any chromosomes, you have no dangling pointers.
Why does it crash while trying to printf() after having free()?
I've created dyanmic array. Displayed elements. Filled each elements with value. Then freed memory using free(). And then trying to display elements again.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int *p;
p = (int *)malloc(10 * sizeof(int));
for ( i = 0; i < 10; i++ )
printf("%d ", p[i]);
printf("\n");
for ( i = 0; i < 10; i++ )
p[i] = i;
for ( i = 0; i < 10; i++ )
printf("%d ", p[i]);
printf("\n");
free(p);
p = NULL;
for ( i = 0; i < 10; i++ ) /* App crashes around here. */
printf("%d ", p[i]);
printf("\n");
return 0;
}
P.S. I'm new to C.
Let me know what is wrong, please.
Because you reference memory pointing to NULL.
This is actually undefined behavior so it might work, but dereferencing a NULL pointer most likely will cause a crash.
Even if you don't set the pointer to NULL it's still undefined behavior to derreference unallocated memory, and although it most likely won't crash it's still a bad thing to do.
When you free any memory, its gone. You can not use it any more.
You should free the after you are done with it.
You are using the pointer p after you have freed it. The system assumes you do not need the memory once you free it. So it does not reserve it for you. It may work some times if the memory is still unused. But in this case you are assigning NULL to the pointer p and then trying to print the value present there, which is definitely not going to work.
One thing always to be remembered.. A freed memory can return the expected result (it sometimes does). Me too sometimes suffered with the problem.. U can finde useful insight here:
Can a local variable's memory be accessed outside its scope?
Now come to your code:
free(p);
Here you may get your expected things..but u r not guaranteed and r not permitted to use this. It is undefined behaviour. But now
p = NULL;
is something that is crashing your program. Because the pointer now points to NULL, and it is not permitted to de-reference a NULL pointer. Do not point to NULL if you don't actually need it. And never ever de-reference a NULL pointer.