I'm experimenting with a quadtree implementation found online, but am receiving "pointer being freed was not allocated" errors intermittently as part of the following (stripped down) _node_release function:
static void _node_release(node* node)
{
if(node->subnodes[0])
{
for(size_t i=0;i<4;i++)
{
_node_release(node->subnodes[i]);
free(node->subnodes[i]); // this causes "pointer being freed was not allocated" errors
}
}
// ...
free(node); // the node passed to _node_release is free'd here
}
Would I be correct to assume that node is being incorrectly free'd twice here? The _node_release function free's the node passed to it, but the code is also attempting to free each subsequent subnode after making a recursive call to _node_release.
Yes you are correct with this assumption.
The problem is in your recursive call. Suppose I am a subnode in the recursive call. When I am done calling free on my subnodes, i then execute my last line, free(node) to free myself.
Now i'm the parent of this node. I do the same routine. One of my subnodes, however, was the guy who just freed himself. So when I call free(node->subnodes[i]) I get the error that you see
Yes you are freeing your nodes twice.
1: static void _node_release(node* node)
2: {
3: if(node->subnodes[0])
4: {
5: for(size_t i=0;i<4;i++)
6: {
7: _node_release(node->subnodes[i]);
8: free(node->subnodes[i]); // this causes "pointer being freed was not allocated" errors
9: }
10: }
11: // ...
12:
13: free(node); // the node passed to _node_release is free'd here
14: }
Lets say you have NodeB as a child of NodeA
_free_release(NodeA)
_free_release(NodeB) – line 7
free(NodeB) - line 14
free(NodeB) - line 8
To fix this just remove the free on line 8
static void _node_release(node* node)
{
if(node->subnodes[0])
{
for(size_t i=0;i<4;i++)
{
_node_release(node->subnodes[i]);
}
}
// ...
free(node); // the node passed to _node_release is free'd here
}
Related
I am working on a C program which has a linked list. I need to remove the last element from the linked list and it is mostly working except when it hits particular part of my code it then has a segmentation fault.
The code that I have is as follows:
int clearOutboundLegFromList(callLogSearchOutboundStruct ** outboundLeg, int dataCol, int rowTargets)
{
//callLogSearchOutboundStruct *currentStruct = *outboundLeg;
//callLogSearchOutboundStruct *temp;
if (*outboundLeg == NULL)
{
return 0;
}
SL_DebugAll(DBG_ALWAYS, "DEBUG: Clearing outbound legs: DataCol: %i RowTargets: %i",
dataCol, rowTargets);
callLogSearchOutboundStruct *legToRemove = NULL;
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
while (legToRemove->nextLeg != NULL)
{
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
if (legToRemove->target != NULL)
{
free(legToRemove->target);
legToRemove->target = NULL;
}
if (legToRemove->cleardownCause)
{
free(legToRemove->cleardownCause);
legToRemove->cleardownCause = NULL;
}
free(legToRemove);
if (last != NULL)
{
last->nextLeg = NULL;
}
legToRemove = NULL;
}
It crashes on the line of free(legToRemove->target);.
In the core dump I have the following:
Program terminated with signal 11, Segmentation fault.
#0 0x00b01336 in _int_free () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install cyrus-sasl-lib-2.1.23-13.el6_3.1.i686 glibc-2.12-1.132.el6_5.2.i686 keyutils-libs-1.4-4.el6.i686 krb5-libs-1.10.3-15.el6_5.1.i686 libcom_err-1.41.12-18.el6.i686 libcurl-7.19.7-37.el6_5.3.i686 libidn-1.18-2.el6.i686 libselinux-2.0.94-5.3.el6_4.1.i686 libssh2-1.4.2-1.el6.i686 mysql-libs-5.1.73-3.el6_5.i686 nspr-4.9.2-1.el6.i686 nss-3.14.0.0-12.el6.i686 nss-softokn-freebl-3.12.9-11.el6.i686 nss-util-3.14.0.0-2.el6.i686 openldap-2.4.23-31.el6.i686 openssl-1.0.1e-16.el6_5.14.i686 zlib-1.2.3-29.el6.i686
(gdb) bt
#0 0x00b01336 in _int_free () from /lib/libc.so.6
#1 0x0805cd0b in clearOutboundLegFromList (outboundLeg=0xb5de7984, dataCol=9, rowTargets=11) at performreport.c:6731
#2 0x08058f33 in processDrilldownData (reportParameterArray=..., csvFile=0x8e3fc78, HandleDB=0xbfca7a14, resultReport=0x8e457a8,
If I print from the core dump legToRemove->target gdb outputs the following:
$1 = 0x99235d8 ""
Now that looks like its a properly allocated memory space, it just contains an empty string so I don't understand why this would cause a segfault.
You don't show how your struct looks like or how you add legs to your linked list, but you have an error in your removal function that occurs if you remove the last node: In that case, your list head should be set to NULL.
This special case is the reason to pass the list head as pointer to pointer to leg: The function must be able to update the head when the first node is removed. If you don't do that, the value of the head in the calling function will be the same and it will refer to memory that you have just freed. It is illegal to access such memory.
So, an updated version of your code could look like this:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
if (legToRemove == NULL) return;
while (legToRemove->nextLeg) {
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
free(legToRemove->target);
free(legToRemove->cleardownCause);
free(legToRemove);
if (last) {
last->nextLeg = NULL;
} else {
*outboundLeg = NULL;
}
}
You need the explicit assignment at the end, because once you have initialised legToRemove, you are operating only with that local pointer.
If you are feeling more confident with double indirections via pointers to pointers, you could iterate to the end without local variabes:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
if (*outboundLeg == NULL) return;
while (*outboundLeg) {
outboundLeg = &(*outboundLeg)->nextLeg;
}
free((*outboundLeg)->target);
free((*outboundLeg)->cleardownCause);
free(*outboundLeg);
*outboundLeg = NULL;
}
This will update the head pointer automatically when the first element is removed. The idea here ist that outboundLeg points to the head node at the beginning and to the previous node's nextLeg pointer on subsequent iterations. The additional indirection via (*outboundLeg) is more or less the same as accessing a node via the nextLeg member, except for the first node, in which you access the pointer through the head node pointer.
(Distraction: Your code is overly cautious when freeing the member pointers. It is legal to free a null pointer; this doesn't do anything, but means that you don't have to check for NULL in client code. Such a check might still be good practice, because many functions won't take null pointers. Setting the member pointers to NULL is a good idea if these pointers were still around for some time. But you are going to free the containing struct anyway soon. Setting the pointers to NULL is a bit like cleaning the bathroom just before you tear down the house. Setting legToRemove to NULL at the end of the function doesn't do anything: The pointer will go out of scope anyway. That's just an aside and retionale for my shorter code. Your checks aren't wrong and it is better to be cautious.)
I'm implementing an AVL tree in C. I've posted my tree rotations below, as well as the valgrind errors I get when I try to test them.
Why am I getting these errors? I understand that the valgrind errors stem from the fact that I'm using null pointers, but I can't pinpoint exactly what I'm doing wrong. (I've commented on the lines of the Valgrind errors)
Tree rotateRight(Tree t)
{
Tree temp = t->L;
t->L=temp->R;
temp->R=t;
temp->height=maximum(heightT(temp->L), heightT(temp->R));
t->height=maximum(heightT(t->L), heightT(t->R));
return t;
}
Tree rotateLeft(Tree t)
{
Tree temp = t->R; //This is line 226
t->R=temp->L;
temp->L=t;
temp->height=maximum(heightT(temp->L), heightT(temp->R));
t->height=maximum(heightT(t->L), heightT(t->R));
return t;
}
Tree rotateLeftRight(Tree t)
{
t->L=rotateLeft(t->L); //Line 235
t=rotateRight(t);
return t;
}
Tree rotateRightLeft(Tree t)
{
t->R=rotateRight(t->R);
t=rotateLeft(t);
return t;
}
Valgrind errors(I'm getting the same thing for rotateLeft):
==20073== Invalid read of size 8
==20073== at 0x40196F: rotateLeft (bst.c:226)
==20073== by 0x401A11: rotateLeftRight (bst.c:235)
==20073== by 0x4013A9: insertT (bst.c:69)
==20073== by 0x400E77: addin (Spell13.c:96)
==20073== by 0x400CBE: main (Spell13.c:59)
==20073== Address 0x10 is not stack'd, malloc'd or (recently) free'd
==20073==
==20073==
==20073== Process terminating with default action of signal 11 (SIGSEGV)
Taking the code that you have + the error report, it appears as though Tree would look something like this:
typedef struct Tree_s
{
struct Tree_s *L;
struct Tree_s *R;
} Tree;
It would also appear that Tree->L that was passed to rotateLeftRight was NULL
I've been trying to set a pointer to a part of a data structure in C, but valgrind is giving me an error. I recognize this error as one where I'm trying to make a non-pointer into a NULL pointer, but that's not what's happening here. What's wrong?
struct node {
int data;
struct node *before;
struct node *after;
};
struct deque {
struct node *front;
struct node *rear;
};
int createD (Deque *d)
{
printf ("Y\n");
(*d) = malloc(100*sizeof(struct deque));
(*d)->front=NULL;
(*d)->rear=NULL;
return 0;
}
int remD (Deque *d, char **s)
{
struct node *temp;
temp=malloc(100*sizeof(struct node));
int data;
if (isEmptyD(d)==0)
{
printf ("Why?");
return 1;
}
else
{
temp = (*d)->front;
data = temp->data;
(*d)->front=temp->after;
(*d)->front->before=NULL;
if((*d)->front==NULL)
{
(*d)->rear=NULL;
}
(*s)=malloc(100);
(**s)=data;
free(temp);
}
return 0;
}
==30983== Invalid write of size 8
==30983== at 0x4010B5: remD (Deque.c:101)
==30983== by 0x400C98: assign (Merge13.c:134)
==30983== by 0x400BFB: mergesort (Merge13.c:113)
==30983== by 0x400B03: queues (Merge13.c:64)
==30983== by 0x400995: main (Merge13.c:26)
==30983== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==30983==
==30983==
==30983== Process terminating with default action of signal 11 (SIGSEGV)
(The valgrind error is in reference to the line (*d)->front->before=NULL; in remD()).
temp->after is not set to anything useful before you use it. So temp->after->before dereferences garbage.
Initialize *temp before you use it.
You expect temp->after to be not NULL, because the line after (the line valgrind complains about), you assign something to the ->front of it. Are you sure it will never be NULL, but always a valid value?
A question regarding the linked lists in C. Suppose, we have the following structures, that define the nodes in a linked list and a badly written free_list function, that (in my opinion) should cause an error:
typedef struct node *nodeT;
typedef struct node
{
int* elem;
nodeT next;
} *nodeT;
void free_list(nodeT list)
{
nodeT node;
for (node = list; node; node = node->next)
{
free(node->elem);
free(node);
}
}
As you see above, we have defined node as nodeT and a function to free the list free_list. For me, the obvious error is that inside free_list function inside for we do not have a temporary pointer to store the node value.
However, when I compile the code (on Linux), in which I create a linked list with few elements, the program doesn't crash, it seems that everything works fine.
My question is: Is there a simple way to prove that this function (free_list) is badly written? By simple I mean setting up some compiler flags (-Wall doesn't show any errors) or using such tools as Valgrind (used it with memcheck, that didn't help much)?
Update: Test case as requested:
int main()
{
nodeT myType;
nodeT tmpPtr;
myType = malloc(sizeof(nodeT));
myType->item = malloc(sizeof(int));
*(myType->item) = 0;
myType->next = malloc(sizeof(nodeT));
tmpPtr = myType->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 1;
tmpPtr->next = malloc(sizeof(nodeT));
tmpPtr = tmpPtr->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 2;
tmpPtr->next = malloc(sizeof(nodeT));
tmpPtr = tmpPtr->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 3;
tmpPtr->next = NULL;
free_list(myType);
return 0;
}
and here is the Valgrind output:
valgrind --tool=memcheck ./a.out
...
==4318== Invalid read of size 8
==4318== at 0x400579: free_list (in /home/melon/a.out)
==4318== by 0x40069E: main (in /home/melon/a.out)
==4318== Address 0x51f1048 is 0 bytes after a block of size 8 free'd
==4318== at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4318== by 0x400574: free_list (in /home/melon/a.out)
==4318== by 0x40069E: main (in /home/melon/a.out)
...
I'm not sure how you did the test with valgrind, but with default parameters it detects this issue just fine:
==4464== Invalid read of size 8
==4464== at 0x400571: free_list (list.c:15)
==4464== by 0x4005DF: main (list.c:30)
==4464== Address 0x51e0048 is 8 bytes inside a block of size 16 free'd
==4464== at 0x4C2AD3C: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4464== by 0x40056C: free_list (list.c:18)
==4464== by 0x4005DF: main (list.c:30)
I just added this to the program to make it testable:
int main() {
nodeT head = malloc(sizeof(struct node));
nodeT node1 = malloc(sizeof(struct node));
head->next = node1;
head->elem = NULL;
node1->next = NULL;
node1->elem = NULL;
free_list(head);
return 0;
}
You can memset the node to zero before freeing the memory. Then it'll crash for sure.
You don't need any proof other than fact that the code dereferences a pointer to memory that was freed. That's undefined behavior. Invoking undefined behavior is bad.
So there's your proof.
The following deleteNode function when I run the program gets these:
* glibc detected free(): invalid next size (normal): 0x000000000103dd90 **
Even i make the ' free(here); ' a comment,i get the above message.
I dont think that the other 'free' calls provokes a problem like that. But I cant see why this would be wrong. :/
struct List *deleteNode(int Code,int i,char* Number)
{
struct List *here;
here=Head;
for (here; here!=Tail; here=here->next)
{
if ( (here->number==Number) && (here->code==Code) )//found node on the List
{
if (here->previous==Head) //delete from beginning
{
Head=here->next;
here->next->previous=Head;
}
else if (here->next==Tail) //delete from the end
{
here->previous->next=Tail;
Tail=here->previous;
}
else //delete from the middle of the list
{
here->previous->next=here->next;
here->next->previous=here->previous;
}
break;
}
}
free (here);
}
EDIT:
if i used and understand valgring well then the problem is on my main function.
i have also there some 'free' but i changed deleteNode before this message so i thought that the problem was on the deleteNode function.
Now,there is no free() invalid next size.... but unfortunately this:
glibc detected * : double free or corruption (out): 0x00007fff1aae9ae0 *
:(
A part of the main:
FILE *File;
if ( ( File=fopen("File.txt","r")) !=NULL )
{
int li = 0;
char *lin = (char *) malloc(MAX_LINE * sizeof(char));
while(fgets(lin, MAX_LINE, eventFile) != NULL)
{
token = linetok(lin, " ");
if(token != NULL)
{
int i,code,nodeID;
char *number;
char *event;
for(i = 0; token[i] != NULL; i += 1)
{
code=atoi(token[0]);
strcpy(event,token[1]);
nodeID=atoi(token[2]);
strcpy(number,token[3]) ;
int i;
if (!strcmp(event,"add"))
{
add_to_List(code,i,number);
}
else if(!strcmp(event,"delete"))
{
deleteNode(eventNo,i,number);
}
free(event);
free(phoneNumber);
}
free(token);
}
else
{
printf("Error reading line %s\n", lin);
exit(1);
}
}
}
else
{
printf("Error opening file with the events.\nEXIT!");
exit(0);
}
debugging it...
multiple definition of main'
pro:(.text+0xce0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/4.4.1/crtend.o:(.dtors+0x0): multiple definition ofDTOR_END'
pro:(.dtors+0x8): first defined here
/usr/bin/ld: warning: Cannot create .eh_frame_hdr section, --eh-frame-hdr ignored.
/usr/bin/ld: error in pro1(.eh_frame); no .eh_frame_hdr table will be created.
collect2: ld returned 1 exit status
"Invalid next size" means that glibc has detected corruption in your memory arena.
You have overwritten valuable accounting information that's stored in between your allocated blocks.
With each block that malloc gives you, there is some accounting information stored close by. When you overwrite this information by, for example, writing 128 characters to a 20-character buffer, glibc may detect this the next time you try to free (or possibly allocate) some memory.
You need to find the root cause of this problem - it's not the free itself, that's just where the problem is being detected. Somewhere, some of your code is trashing memory and a memory analysis tool like valgrind will be invaluable here.
If the node is not found in the list, you will free the Tail node at the end of the function, without updating Tail to point to anything valid again.
Further using the list and the now deallocated Tail can easily result in memory corruption that might later be detected by glibc with a message like the one you got.
Also note that in (here->number==Number) you are comparing two pointers, not the values those pointers point to. I'm not sure if that's what you want.