I faced a very interesting problem in a C++ code. The code logic was as follows:
#include<stdio.h>
int main()
{int *p = new int();
int* B[10];for ( int i =0; i<10; i++)
{
delete p;
//p = NULL;
printf(“Address1 = %x\n”, p);int *q = new int();
printf(“Address2 = %x\n”, q);B[i] = q;
i++;
}}
Output:
kanaujia@ubuntu:~/Desktop/ToKeep/cprogs$ ./a.out
Address1 = 96f8008
Address2 = 96f8008
Address1 = 96f8008
Address2 = 96f8008
Address1 = 96f8008
Address2 = 96f8008
Address1 = 96f8008
Address2 = 96f8008
Address1 = 96f8008
Address2 = 96f8008
This code looks pretty simple and with no bug, right? But, it has an interesting problem. The first memory allocation of integer will give us an address from the heap (say, it is 0x12345).
Now inside the loop, with first iteration, we free this memory. ‘new’ will mark this address 0x12345 in free-list. Next , we again ask an integer memory allocation. And ‘new’ returned me same address 0x12345 for this allocation. I save this address in array B. Next and henceforth forth iterations will call ‘delete’ on 0x12345, and again ask an allocation. This request again returns 0x12345. So, we end up with single value of 0x12345 for *all* elements of arrayB.
How to fix this:
Always mark the pointer to NULL after calling ‘delete’. Just mark p as NULL here.
9 for ( int i =0; i<10; i++)
10 {
11 delete p;
12 p = NULL;
13 printf(“Address1 = %x\n”, p);
14
15 int *q = new int();
16 printf(“Address2 = %x\n”, q);
17
18 B[i] = q;
19
20 i++;
21 }
Output:
kanaujia@ubuntu:~/Desktop/ToKeep/cprogs$ ./a.out
Address1 = 0
Address2 = 9265008
Address1 = 0
Address2 = 9265018
Address1 = 0
Address2 = 9265028
Address1 = 0
Address2 = 9265038
Address1 = 0
Address2 = 9265048
That’s it folks! Hope you enjoyed it.
No, the basic premise of this article is incorrect. In the example taken, there was an attempt to free the pointer p for 10 times, though it was allocated only once. Hence the irregularities with further allocations. Rather the code should look like :
int main()
{
int *p = new int();
int* B[10];
for ( int i =0; i<10; i++)
{
if (i==0)
delete p;
//p = NULL;
printf(“Address1 = %x\n”, p);
int *q = new int();
printf(“Address2 = %x\n”, q);
B[i] = q;
i++;
}
}
OR, as mentioned in the article, one can chose to explicitly make the pointer to be NULL after a free operation, something like this :
int main()
{
int *p = new int();
int* B[10];
for ( int i =0; i<10; i++)
{
if(p)
{
delete p;
p = NULL;
}
printf(“Address1 = %x\n”, p);
int *q = new int();
printf(“Address2 = %x\n”, q);
B[i] = q;
i++;
}
}
And here are the results :
p is 0
q is 0x903b008
p is 0
q is 0x903b018
p is 0
q is 0x903b028
p is 0
q is 0x903b038
p is 0
q is 0x903b048
LikeLike
Hey Pavan,
Glad to see your analysis. Yes, you are right that the code is incorrect. But, on a cursory look it is tad oblivious. And it is this bug (which is a real world problem) that this article tries to pinpoint, in fact I solely tried to focus on that singe problem.
Takeaways are:
o) Always keep track of your ‘delete’ statement, as you have right pointed in your solution.
o) Immediately point the pointer to NULL.
–Vishal
LikeLike
oh yeah, its always recommended to memset your ‘alloc’ated memory and make the pointer to Null upon delete.
LikeLike
From the above, looks like the behaviour of ‘new’ and ‘delete’ is somewhat like this :
1) Delete is updating mem address in a stack.
2) Upon subsequent new operation, the same address as in (1) is returned.
Also, the problem presented is similar to usage of uninitialized variable.
Comments are welcomed. 🙂
LikeLike
Hey Vinay,
Ya, the behavior mimic stack-like operation. Though it would depend on what memory allocation scheme glibc uses..?
LikeLike