I thought the following code snippets would cause double free, and the program would core dump. But the truth is that there is no error when I run the code?
Similar problem shows that it caused double free!
My Question is why does there have no error show that there is a double free? And why does there have no core dump?
#include <iostream>
using namespace std;
int main()
{
int *p = new int(5);
cout << "The value that p points to: " << (*p) << endl;
cout << "The address that p points to: " << &(*p) << endl;
delete p;
cout << "The value that p points to: " << (*p) << endl;
cout << "The address that p points to: " << &(*p) << endl;
delete p;
cout << "The value that p points to: " << (*p) << endl;
cout << "The address that p points to: " << &(*p) << endl;
delete p;
}
The program's output when I ran this program is shown as followed:
After modifying the code snippet like the following, the core dump occured:
#include <iostream>
using namespace std;
int main()
{
int *p = new int(5);
for (;;)
{
cout << "The value that p points to: " << (*p) << endl;
cout << "The address that p points to: " << &(*p) << endl;
delete p;
}
return 0;
}
And the program output is :
So there is another question that why this program will core dump every time?
Yes, it is a double free (well, triple, really) which puts it into undefined behaviour territory.
But that's the insidious thing about undefined behaviour, it's not required to crash or complain, it's not required to do anything at all(a). It may even work.
I can envisage an implementation that stores the free state of a block in the control information for it so that freeing it twice would have no effect. However, that would be inefficient, and also wouldn't cover the case where it had been reallocated for another purpose (it would prevent double frees, but not a piece of code freeing the block when some other piece still thinks it still has it).
So, given it's not required to work, you would be well advised to steer clear of it since it may also download maniacal_laughter.ogg and play it while erasing your primary drive.
As an aside, modern C++ has smart pointers that are able to manage their own lifetime, and you would be doing yourself a big favour if you started using those instead of raw pointers.And, although the removal of raw pointer from C++ was a joke, there are some that think it's not such a bad idea :-)
(a) The C++20 standard has this to say when describing undefined behaviour in [defns.undefined] (my emphasis):
Behavior for which this document imposes **NO** requirements.
why does there have no error show that there is a double free? And why does there have no core dump?
delete p;
cout << "The value that p points to: " << (*p) << endl;
The moment you referenced to a deleted pointer is when the program entered an undefined behaviour, and then there is no guarantee that there would be an error or a crash.
It's not entirely the same, but the analogy between memory and a hotel room is applicable, which explains well what an undefined behaviour means. Highly recommended reading:
Can a local variable's memory be accessed outside its scope?
Related
I'm new to C++ and currently having a hard time with pointers.
I was wondering if there is a preferred method of coding between the two methods shown below:
#include <iostream>
using namespace std;
int main(){
// method 1
int* n;
*n = 2;
cout << "address of n in main(): " << n << "\n"; //returns 0
cout << "value inside of n in main(): " << *n << "\n"; // returns 2
// method 2
int* m = new int(2);
cout << "address of m in main(): " << m << "\n"; //returns some address
cout << "value insdie of m in main(): " << *m << "\n"; // returns 2
}
The first method returns the following:
address of n in main(): 0
value inside of n in main(): 2
The Second method returns the following:
address of m in main(): 0x6c2cc0
value inside of m in main(): 2
Q1. What would be possible issues with having the address of n in main():0? (it only behaves like this on an online compiler sorry. Nevermind this question.)
Q2. What is the "new" declaration method called?
What would be possible issues with having the "address of n in main():0"?
If you are lucky, crashing the program due to segfault. If you are not, memory corruption, undefined behavior, etc.
The reason is that you are using an effectively random memory address that has not been mapped/reserved/allocated to your process.
What is the "new" declaration method called?
There is no "name" for the "method". new is a keyword and an operator, too. It is the standard way of allocating memory in C++. Although, in almost all cases, you will use a container instead that manages the memory for you, like std::vector or std::unique_ptr.
Im trying to understand the delete operator in c++.
I could understand the logic behind using pointers and new operator, yet I understood that "The delete operator eliminates a dynamic variable and returns the memory that the dynamic variable occupied to the freestone." p517, Problem solving with C++ 9th edition.
which, I think doesn't align with the third cout statement. and I expected that the third cout statement to be sth similar to the first one.
int main() {
int *p1;
cout << "p1 address: " << &p1 << " and points to the address "<< p1 << " which has the value: " << *p1<< endl;
p1 = new int;
cout << "p1 address: " << &p1 << " and points to the address "<< p1 << " which has the value: " << *p1<< endl;
delete p1;
cout << "p1 address: " << &p1 << " and points to the address "<< p1 << " which has the value: " << *p1<< endl;
cout << endl;
return 0;
}
I would appreciate any explanation :))
delete doesn't have to change the memory your pointer points to. What it actually does is implementation specific.
What delete needs to do is to deconstruct any object at the given address and return the associated memory to the allocation pool. Some debugger might overwrite the value of a variable when freed, but for trivial types no special deconstruction needs to take place - the memory can be returned to the pool as-is. The pointer isn't changed either: after delete p we call p a dangling pointer that holds an address to freed memory. All access through that pointer is undefined behaviour.
Since handling raw pointers and especially dangling pointers is error prone, it's good to know the C++ smartpointers, e.g. unique_ptr:
std::unique_ptr<int> p; // initialised to nullptr
p = std::make_unique<int>(13); // new int with value 13
p = std::make_unique<int>(37); // deleted previous int, assigned new int with value 37
// optional (when p goes out of scope its pointee is deleted automatically)
p.reset(); // deleted the int and reset p to nullptr
I'm quite new to the world of pointers in C/C++ so this may be quite an easy question for you:
The following C++-Code works normally
#include <iostream>
int main()
{
int theInt = 1337;
int & theReference = theInt;
int * thePointer = &theInt;
std::cout << "int: " << theInt << "\n";
std::cout << "referenz: " << theReference << "\n";
std::cout << "pointer: " << *thePointer << "\n";
std::cout << "pointer: " << *thePointer << "\n";
//std::cout << "foo" << "\n";
return 0;
}
but stops working when changing
//std::cout << "foo" << "\n";
to
std::cout << "foo" << "\n";
.
By "stops working" I mean: "is blocked by my norton security as a potential threat" (resulting in a return code of "0x76F531AF" if this is any help). Since norton normally doesn't interfere withe my programming I assume the double use of the int pointer in cout somehow results in a segfault...
Thx for your help!
PS:
I use Code::Blocks on Windows 8.1 with the GCC compiler and GDB debugger from TDM-GCC (version 4.7.1, 32 bit).
EDIT: removed deletion of pointer -> problem remains.
You can only delete objects created on the heap (using new or C-style malloc and such).
// allocate on the heap
int *intOnTheHeap = new int;
// do some stuff with it
*intOnTheHeap = 0;
(*intOnTheHeap)++;
std::cout << *intOnTheHeap << std::endl;
// deallocate
delete intOnTheHeap;
If you take a pointer to a local variable, it will point to an entry on the stack. You don't need to and shouldn't deallocate that memory yourself. The memory is "freed" by changing the stackpointer automatically when your variable runs out of scope (at the end of the function).
void myFunction() {
int localVariable;
int *pointerToLocalVariable = &localVariable;
// forbidden and unnecessary:
//delete pointerToLocalVariable;
// here (end of the block) the memory on the stack
// will be freed automatically
}
Since I got the same error after Norton-Interception in totally different contexts, this seems to be a case of Code::Blocks Norton incompatibility.
I have the following code:
#include <iostream>
using namespace std;
int main ()
{
int myvar = 5;
int * p;
cout << "Hello2" << endl;
*p = myvar;
cout << "Hello" << endl;
cout << p << endl;
//cout << &myvar << endl;
}
I know I am not doing the right thing by not initializing the pointer. I was just playing with pointers and noticed this. The issue is when I comment out the last line, the program executes normally. But as soon as I uncomment the line, I get a segmentation fault. I don't know why printing address of myvar is causing this? Has myvar been modified in any way because of pointer dereferencing? I am using C++11.
int* p;
*p = myvar;
You are creating an uninitialized pointer and then derferencing that pointer. This has undefined behavior because p has to point to something for it to be derferenced correctly. Therefore your program's behavior can't be reasoned with.
Segmentation Fault occurs when trying to access a virtual memory address that has no read permissions.
In your case, the local variable p holds uninitialized garbage from the stack.
you are dereferencing a memory address that might not be readable(e.g no read permissions, hence the segmentation fault when trying to access it).
I'm not entirely sure the purpose of your snippet, but the following code will work, and perhaps it will help:
int myvar = 5;
int *p = nullptr;
p = &myvar;
cout << myvar << endl;
cout << &myvar << endl;
cout << p << endl;
cout << *p << endl;
(Note: I used two lines for setting 'p' because that is how you did it in your snippet. You could easily just use: int *p = &myvar; )
Anyway, there are scope issues here as p will only be valid as long as myvar is in scope; however, this does illustrate the basics of pointers. myvar and *p will return the same value (the value being pointed to), and &myvar and p will return the same value (the location of value in memory.)
I'm trying to learn how C++ compilers handle references and pointers, in preparation for a compiler class that I'm taking next semester. I'm specifically interested in how compilers handle references in C++.
The standard specifies that a reference is an "alias," but I don't know exactly what that means at the compiler level. I have two theories:
A non-reference variable has an entry in the symbol table. When a reference to that variable is created, the compiler simply creates another lexeme that "points" to the exact same entry in the symbol table (and not to the non-reference variable's location in memory).
When a reference to that variable is created, the compiler creates a pointer to that variable's location in memory. The limitations on references (no null values, etc.) are handled when parsing the context of the language. In other words, a reference is "syntactic sugar" for a dereferenced pointer.
Both solutions would create an "alias," as far as I can tell. Do compilers use one and not the other? Or is it compiler-dependent?
As an aside, I'm aware that at the machine-language level, both are "pointers" (pretty much everything other than an integer is a "pointer" at the machine level). I'm interested in what the compiler does before the machine code is generated.
EDIT: Part of the reason I am curious is because PHP uses method #1, and I'm wondering if C++ compilers work the same way. Java certainly does not use method #1, and their "references" are in fact dereferenced pointers; see this article by Scott Stanchfield.
I will try to explain how references are implemented by g++ compiler.
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int *ptrToI = &i;
int &refToI = i;
cout << "i = " << i << "\n";
cout << "&i = " << &i << "\n";
cout << "ptrToI = " << ptrToI << "\n";
cout << "*ptrToI = " << *ptrToI << "\n";
cout << "&ptrToI = " << &ptrToI << "\n";
cout << "refToNum = " << refToI << "\n";
//cout << "*refToNum = " << *refToI << "\n";
cout << "&refToNum = " << &refToI << "\n";
return 0;
}
Output of this code is like this
i = 10
&i = 0xbf9e52f8
ptrToI = 0xbf9e52f8
*ptrToI = 10
&ptrToI = 0xbf9e52f4
refToNum = 10
&refToNum = 0xbf9e52f8
Lets look at the disassembly(I used GDB for this. 8,9 and 10 here are line numbers of code)
8 int i = 10;
0x08048698 <main()+18>: movl $0xa,-0x10(%ebp)
Here $0xa is the 10(decimal) that we are assigning to i. -0x10(%ebp) here means content of ebp register –16(decimal).
-0x10(%ebp) points to the address of i on stack.
9 int *ptrToI = &i;
0x0804869f <main()+25>: lea -0x10(%ebp),%eax
0x080486a2 <main()+28>: mov %eax,-0x14(%ebp)
Assign address of i to ptrToI. ptrToI is again on stack located at address -0x14(%ebp), that is ebp – 20(decimal).
10 int &refToI = i;
0x080486a5 <main()+31>: lea -0x10(%ebp),%eax
0x080486a8 <main()+34>: mov %eax,-0xc(%ebp)
Now here is the catch! Compare disassembly of line 9 and 10 and you will observer that ,-0x14(%ebp) is replaced by -0xc(%ebp) in line number 10. -0xc(%ebp) is the address of refToNum. It is allocated on stack. But you will never be able to get this address from you code because you are not required to know the address.
So; a reference does occupy memory. In this case it is the stack memory since we have allocated it as a local variable.
How much memory does it occupy?
As much a pointer occupies.
Now lets see how we access the reference and pointers. For simplicity I have shown only part of the assembly snippet
16 cout << "*ptrToI = " << *ptrToI << "\n";
0x08048746 <main()+192>: mov -0x14(%ebp),%eax
0x08048749 <main()+195>: mov (%eax),%ebx
19 cout << "refToNum = " << refToI << "\n";
0x080487b0 <main()+298>: mov -0xc(%ebp),%eax
0x080487b3 <main()+301>: mov (%eax),%ebx
Now compare the above two lines, you will see striking similarity. -0xc(%ebp) is the actual address of refToI which is never accessible to you.
In simple terms, if you think of reference as a normal pointer, then accessing a reference is like fetching the value at address pointed to by the reference. Which means the below two lines of code will give you the same result
cout << "Value if i = " << *ptrToI << "\n";
cout << " Value if i = " << refToI << "\n";
Now compare this
15 cout << "ptrToI = " << ptrToI << "\n";
0x08048713 <main()+141>: mov -0x14(%ebp),%ebx
21 cout << "&refToNum = " << &refToI << "\n";
0x080487fb <main()+373>: mov -0xc(%ebp),%eax
I guess you are able to spot what is happening here.
If you ask for &refToI, the contents of -0xc(%ebp) address location are returned and -0xc(%ebp) is where refToi resides and its contents are nothing but address of i.
One last thing, Why is this line commented?
//cout << "*refToNum = " << *refToI << "\n";
Because *refToI is not permitted and it will give you a compile time error.
Understanding pointers and references is quite different than implementing the code for them.
I suggest you learn how to use them properly and focus on the core of compiler theory. The fundamental compiler theory class is difficult enough without the concepts of pointers, references and inheritance. Pointers and references are left for a more advanced class.
Simply put: use references when you can, pointers when you must.
Edit 1:
Compilers can implement references and pointers in any way they want as long as their syntax and semantics behave according to the language specification.
A simple implementation is to treat references as pointers with additional attributes.
Everything in memory has a location, i.e. address. The compiler may have to use internal pointers to load from memory into registers and to store register contents into memory. So to refer to a variable in memory, whether by pointer, reference or alias, the compiler needs the address of the variable. (This does not include register variables which are treated differently.) So using pointers for references or aliases saves some coding.