#include <iostream>
#include <string>
using namespace std;
class CExample {
public:
int a,b,c;
void setvalue(int n, int m);
void multiply() {
c = a*b;
cout<< c <<endl;
};
};
void CExample::setvalue(int n, int m){
a = n; b = m;
}
int main( )
{
CExample *d = new CExample[1];
d[0].setvalue(2,30);
d[0].multiply();
d[1].setvalue(2,30);
d[1].multiply();
d[2].setvalue(2,30);
d[2].multiply();
delete[] d;
return 0;
}
Since I have only allocate 1 Memory resource for Array d, I ought to encounter error when manipulating d[2]. However, the compiler didn't report error or warning. And the result is correct.
Can someone explain why it works?
Thanks
Yes, it is the magic of undefined behavior. Thanks for all of you.
The C++ compiler can't and won't catch all the possible way you could write incorrect code.
And while running, a C++ program will usually not throw an error the moment you access memory out of bounds. The language was not designed to protect the programmer from doing bad things.
So when a program does something like this... which is undefined behavior... anything might happen. That "anything" can include appearing to work "correctly". Or weird behavior might appear right away. But either way it's wrong. If it appears to work, that's only by luck.
And in practice it will also likely be corrupting memory somewhere which will lead to other problems eventually. Maybe the problems don't have time to manifest in small example programs. But the larger the program, the more likely some kind of bad symptom will show up.
In the end, C++ puts a significant degree of responsibility on the programmer to write correct code which doesn't do things like going outside of array bounds.
"Can someone explain why it works?" -- You believe the code works.
"I ought to encounter error when manipulating d[2]" -- You believe the code should do something other than what it does.
You are making two conflicting claims. You are saying both that the code works and that it should do something other than what it does. These cannot both be true.
As you know, your code has a bug. So it's not surprising that it doesn't do what you expect.
You operate on a un-alloc memory, it's a undefined behavior.
It's a run-time error, so compiler can't catch it.
With valgrind, a memory check tool, you will get "Invalid write" errors.
Related
In this Quora answer i stumbled upon this piece of code and would like to understand whats happening: How can I print 1 to 100 in C++ without a loop, goto or recursion?
I asked my programming teacher and he said he's not too familiar with alloca(), but he was sure this program had undefined behavior, and that i'd better ask on SO.
Worth to note that the OP of the answer on Quora gave no guarantee this would work on someone else's system.
I have trouble understanding what void(**rptr)() does and how the call in main() works, why * 200?.
#include <iostream>
#include <stdlib.h>
int num;
void(**rptr)();
void foo() {
if(num >= 100) exit(0);
std::cout << ++num << std::endl;
*rptr++ = foo;
}
int main() {
rptr = (void(**)())alloca(sizeof(*rptr) * 200) - 1;
foo();
return 0;
}
This is a horrible hack which leverages undefined behavoir. Analysing undefined behavoir is pretty pointless, but sometimes its interesting to dig in and find out exactly why.
Basically, what is happening is the alloca(...) is allocating enough memory to store 200 function pointers on the stack. So far, unusual but nothing bad. But the key is the -1 at the end - its returning memory which is one before this store. So rptr is pointing to the stack into an unknown location.
Then foo is called. At the end of foo we write the address of foo to rptr. But rptr is one before the valid memory so we're overwriting something else.
What that something else happens to be is the return address for where foo returns to (which should be main). So instead of returning to main, it basically "returns" to the start of foo. And this repeats until we get to the exit.
Its basically moderately controlled stack smashing. And will only work on architectures with calling conventions where the return address is put onto the stack in this manor.
It seems one can pass an array by reference to the first element:
void passMe(int& firstElement)
{
int* p=&firstElement;
cout << p[0] << p[1];
}
Main program:
int hat[]={ 5,2,8 };
passMe(hat[0]);
Usually, instead of the above function definition, I would do void passMe(int* myArray) or void passMe(int[] myArray). But would the method above cause any issues? Knowing the answer would allow me to gain a better understanding of the things at play here, if nothing else.
As far as the language-lawyers and the compiler are concerned, it's fine. The main issue will be with the human programmers (including future versions of yourself). When your standard C++ programmer sees this in a program:
void passMe(int& firstElement); // function declaration (in a .h file)
int hat[]={ 5,2,8 };
passMe(hat[0]);
He is going to expect that passMe() might read and/or modify hat[0]. He is definitely not going to expect that passMe() might read and/or modify hat[1]. And when he eventually figures out what you are doing, he's going to be very upset with you for misleading him via unnecessarily "clever" code. :)
Furthermore, if another programmer (who doesn't know about your trick) tries to call your function from his own code, after seeing only the function declaration in the header, he's likely to try to do something like this:
int cane = 5;
passMe(cane);
... which will lead directly to mysterious undefined behavior at runtime when passMe() tries to reference the second item in the array after cane, which doesn't actually exist because cane is not actually in an array.
I have a couple of questions concerning C++ exceptions. For reference, I am learning C++ through Bjarne Stroustrup's "Programming Principles and Practice using C++".
My first questions I think is simple: around page 147, we are talking about exceptions dealing with referencing an index outside of the range of a vector. So his try catch block is
int main(){
try{
vector<int> v;
int x;
while(cin>>x)
v.push_back(x);
for(int i = 0; i<=v.size();i++)
cout<<"v["<<i<<"] == "<<v[i]<<endl;
} catch (out_of_range_error){
cerr<<"Oops! Range error\n"
return 1;
} catch(...){
cerr<<"Exception: something went wrong\n";
return 2;
}
}
So my question is what is out_of_range_error ?! Early on in the book he mentions the use of a header file to use so new people need not concern themselves with nuances. That file is located here
but out_of_range_error is no where there. Just the standard out_of_range exception you can check for normally (after importing stdexcept). And even when I use that file (which I normally don't) the compiler (g++) tells me it expects an identifier for out_of_range_error. So is this just some typo in this mass-produced book? Or am I missing something?
My second question is on the same topic, if I don't import the file he gives, but instead just do:
#include <iostream>
#include <stdexcept>
#include <vector>
using namespace std;
/*
#include "std_lib_facilities.h"
*/
int main()
{
try
{
vector<int> newVec;
int x;
while(cin>>x)
newVec.push_back(x);
for(int i = 0; i<=newVec.size()+200;i++)
cout<<newVec[i]<<endl;
return 0;
}//try
catch (out_of_range)
{
cerr<<"runtime error: "<<endl;
return 1;
}//catch
}//main()
then my code runs with no call to the catch block, even though I reference newVec[newVec.size()+200] in the end. It just returns a bunch of 0s with other integers randomly strewn about. I expect these are just the next bits of memory that would have been allocated for newVec, Vector is not special here, the same thing happens with arrays.
So why does C++ not do any range checking? Or does it do range checking and just not care?
If I use
vector<int> v(10);
v.at(20) = 100;
then I get an error, but if I just want to reference, or assign to, v[20] I get no problems. Why is this?
Is this common in C++? Do you often need extra code to FORCE C++ to notice array bounds? This seems very hazardous, coming from a java background. Java would immediately alert you to any indexing errors, but C++ seems content to let you carry on with incorrect logic.
Thanks so much for any responses, sorry for a long-winded attempt at asking this question.
Relative to your first question then I am sure that out_of_range_error is a typo. There should be out_of_range(See section 19.4 of the book for additional information).
As for the second question then operator [] for vectors does not throw the exception std::out_of_range it simulates the bahaviour of arrays. So there is simply undefined behaviour. If you want that there would be a check of the range then you have to use member function at
By the way if the book has errate at the site then you should look through it.
One of the most important principles motivating the design of C++ and its standard library is "you don't pay for what you don't need".
Properly written code shouldn't be accessing array (or vector) out of bounds, therefore they don't need bounds checking, and therefore they shouldn't be forced to pay for it. Bounds checking can easily double the cost of an array access. Similar designs can be seen throughout the C++ standard library - for example, std::lock_guard vs. std::unique_lock, std::condition_variable vs. std::condition_variable_any. In each case the latter class adds extra functionality at extra cost, so users who don't need the extra functionality could simply use the more lightweight version.
If you do need bounds checking, then std::vector provides the member function at() for this purpose.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How could pairing new[] with delete possibly lead to memory leak only?
I was always told that it's not safe to call delete on an array allocated with new[]. You should always pair new with delete and new[] with delete[].
So I was surprised to discover that the following code compiles and runs ok, in both Debug and Release mode under VS2008.
class CBlah
{
public:
CBlah() : m_i(0) {}
private:
int m_i;
};
int _tmain(int argc, _TCHAR* argv[])
{
for(;;)
{
CBlah * p = new CBlah[1000]; // with []
delete p; // no []
}
return 0;
}
It took me a while to figure out why this works at all, and I think it's just luck and some undefined behaviour.
BUT... it made me wonder... why doesn't Visual Studio pick this up, at least in the Debug memory manager? Is it because there's lots of code out there that makes this mistake and they don't want to break it, or do they feel it's not the job of the Debug memory manager to catch this kind of mistake?
Any thoughts? Is this kind of misuse common?
It will certainly compile ok, because there is no information in the pointer (compile-time) which will see if pointer points to array or what. For example:
int* p;
cin>>x;
if(x == 0)
p = new int;
else
p = new int [10];
delete p; //correct or not? :)
Now , about running ok. This is called undefined behavior in C++, that is, there is no guarantee what will happen - everything can run OK, you can get a segfault, you can get just wrong behavior, or your computer may decide to call 911. UB <=> no guarantee
It's undefined behavior and everything is fair in love, war and undefined behavior...:)
According to MDSN, it translates delete to delete[] when trying to delete an array. (See there, for instance). Though you should have a warning after compiling.
The reason the Debug Memory Manager does not pick up on this error is probably because it it not implemented at the level of new/delete, but at the level of the memory manager that gets invoked by new/delete to allocate the required memory.
At that point, the distinction between array new and scalar new is gone.
You can read these SO answers and links about delete and delete[]: About delete, operator delete, delete[], ...
I don't know what makes you think it "works ok". It compiles and completes without crashing. That does not mean necessarily there was no leak or heap corruption. Also if you got away with it this time, it doesn't necessarily make it a safe thing to do.
Sometimes even a buffer overwrite is something you will "get away with" because the bytes you have written to were not used (maybe they are padding for alignment). Still you should not go around doing it.
Incidentally new T[1] is a form of new[] and still requires a delete[] even though in this instance there is only one element.
Interesting point.
Once I did a code review and tried to convince programmers to fix new[]-delete mismatch.
I've argumented with "Item 5" from Effective C++ by Scott Meyers. However, they argumented with "What do you want, it works well!" and proved, that there was no memory leakage.
However, it worked only with POD-types. Looks like, MS tries to fix the mismatch as pointed out by Raveline.
What would happen, if you added a destructor?
#include <iostream>
class CBlah
{
static int instCnt;
public:
CBlah() : m_i(0) {++instCnt;}
~CBlah()
{
std::cout <<"d-tor on "<< instCnt <<" instance."<<std::endl;
--instCnt;
}
private:
int m_i;
};
int CBlah::instCnt=0;
int main()
{
//for(;;)
{
CBlah * p = new CBlah[10]; // with []
delete p; // no []
}
return 0;
}
Whatever silly"inteligence" fix is added to VS, the code is not portable.
Remember that "works properly" is within the universe of "undefined behavior". It is quite possible for a particular version of a particular compiler to implement this in such a way that it works for all intents and purposes. The important thing to remember is that this is not guaranteed and you can't really ever be sure it's working 100%, and you can't know that it will work with the next version of the compiler. It's also not portable, since another compiler might work in a different fashion.
This works because the particular C++ runtime library it was linked with uses the same heap for both operator new and operator new[]. Many do, but some don't, which is why the practice is not recommended.
The other big difference is that if CBlah had a non-trivial destructor, the delete p; would only call it for the first object in the array, whereas delete[] p; is sure to call it for all the objects.
I'm studying for a final exam and I stumbled upon a curious question that was part of the exam our teacher gave last year to some poor souls. The question goes something like this:
Is the following program correct, or not? If it is, write down what the program outputs. If it's not, write down why.
The program:
#include<iostream.h>
class cls
{ int x;
public: cls() { x=23; }
int get_x(){ return x; } };
int main()
{ cls *p1, *p2;
p1=new cls;
p2=(cls*)malloc(sizeof(cls));
int x=p1->get_x()+p2->get_x();
cout<<x;
return 0;
}
My first instinct was to answer with "the program is not correct, as new should be used instead of malloc". However, after compiling the program and seeing it output 23 I realize that that answer might not be correct.
The problem is that I was expecting p2->get_x() to return some arbitrary number (whatever happened to be in that spot of the memory when malloc was called). However, it returned 0. I'm not sure whether this is a coincidence or if class members are initialized with 0 when it is malloc-ed.
Is this behavior (p2->x being 0 after malloc) the default? Should I have expected this?
What would your answer to my teacher's question be? (besides forgetting to #include <stdlib.h> for malloc :P)
Is this behavior (p2->x being 0 after malloc) the default? Should I have expected this?
No, p2->x can be anything after the call to malloc. It just happens to be 0 in your test environment.
What would your answer to my teacher's question be? (besides forgetting to #include for malloc :P)
What everyone has told you, new combines the call to get memory from the freestore with a call to the object's constructor. Malloc only does half of that.
Fixing it: While the sample program is wrong. It isn't always wrong to use "malloc" with classes. It is perfectly valid in a shared memory situation you just have to add an in-place call to new:
p2=(cls*)malloc(sizeof(cls));
new(p2) cls;
new calls the constructor, malloc will not. So your object will be in an unknown state.
The actual behaviour is unknown, because new acts pretty the same like malloc + constructor call.
In your code, the second part is missing, hence, it could work in one case, it could not, but you can't say exactly.
Why can't 0 be an arbitrary number too? Are you running in Debug mode? What compiler?
VC++ pre-fills newly allocated memory with a string of 0xCC byte values (in debug mode of-course) so you would not have obtained a zero for an answer if you were using it.
Malloc makes no guarantuee to zero out the memory it allocated and the result of the programm is undefined.
Otherwise there are many other things that keep this program from being correct C++. cout is in namespace std, malloc needs to included through#include <cstdlib> and iostream.h isn't standard compliant either.