In visual studio you can invoke function on already deleted object:
class Foo {
void bar() {
...
}
};
you can actually execute following code without errors:
Foo * foo = new Foo();
delete foo;
foo->bar();
and as long as code in Foo::bar doesn't do anything with this pointer. My first question is, is this undefined behavior that happens to work or is it according to standard?
Second question:
If we alter code to:
Foo * foo = new Foo();
delete foo;
foo = nullptr;
foo->bar();
we can in Foo::bar use following check
if (this == nullptr) {
...
}
in order to determine if we operate on valid object. While it doesn't seem like good idea to do this, is there any architecture/design were this could be useful?
Both uses are just plain UB.
if (this == nullptr) may even be optimized away by the compiler as this is never nullptr in legal code. Clang warns about this btw.
Update: As of gcc 6, gcc actually does optimize based on assuming this != nullptr. They also added a warning. See it live.
If a method do not execute any class member it should be a static one. A static method can be called always without any object and the compiler gives an error if this is not true.
The check
if ( this )
looks very very dirty to me. Only for test purpose a assert sounds helpful. But if I must fear that a method can be called without object, there is no chance to get save that the pointer ( this ) is set valid to nullptr. This is bug shifting and not a solution.
And if the method is a virtual one, the check for this==nullptr comes to late because the vtable ptr could not be found.
The design of a program should handle new/delete in a proper way. Maybe the use of any kind of smart pointers can help.
foo->bar() always dereferences foo.
Dereferencing a pointer after deleting it gives undefined behaviour. If Visual Studio happens to give no error, that is happenstance. Any result is permitted from undefined behaviour, including giving no apparent error.
Setting foo to be nullptr and then calling foo->bar() also gives undefined behaviour, because it dereferences a NULL pointer. Testing this == nullptr inside Foo::bar() does not change that, because it is the caller that has exhibited undefined behaviour even before Foo::bar() has been called.
foo->bar()
this statement means decode the address in foo. and put it into the call stack, and then put the variable content of bar to the call stack. Lastly, execute the function.
If the ::bar() function is completely empty. It is OK.
Otherwise, even you just declare some variable. The address of *foo is already dirty by your function call.
1) If the foo == nullptr. 0x0000000 is a read only section, your program will crash, or throw exception when your main is end.
2) If the foo != nullptr, but it is deleted. The heap will corrupted, and the memory barrier may detect your action, it may crash
3) If the foo != nullptr, and it is stack variable. The stack is dirty and it will crash.
Related
Amazingly people may call it feature but I use to say it another bug of C++ that we can call member function through pointer without assigning any object. See following example:
class A{
public:
virtual void f1(){cout<<"f1\n";}
void f2(){cout<<"f2\n";};
};
int main(){
A *p=0;
p->f2();
return 0;
}
Output:
f2
We have checked this in different compilers & platforms but result is same, however if we call virtual function through pointer without object then there occur run-time error. Here reason is obvious for virtual function when object is checked it is not found so there comes error.
This is not a bug. You triggered an Undefined Behavior. You may get anything including the result you expected.
Dereferencing a NULL pointer is undefined behavior.
BTW, there is no thing such as "bug of C++". The bugs may occur in C++ Compilers not in the language it self.
As pointed out, this is undefined behaviour, so anything goes.
To answer the question in terms of the implementation, why do you see this behaviour?
The non-virtual call is implemented as just an ordinary function call, with the this pointer (value null) passed in as paremeter. The parameter is not dereferenced (as no member variables are used), so the call succeeds.
The virtual call requires a lookup in the vtable to get the adress of the actual function to call. The vtable address is stored in a pointer in the data of the object itself. Thus to read it, a de-reference of the this pointer is required - segmentation fault.
When you create a class by
class A{
public:
virtual void f1(){cout<<"f1\n";}
void f2(){cout<<"f2\n";};
};
The Compiler puts the code of member functions in the text area.
When you do p->MemberFunction() then the compiler just deferences p and tries to find the function MemberFunction using the type information of p which is Class A.
Now since the function's code exists in the text area so it is called. If the function had references to some class variables then while accessing them, you might have gotten a Segmentation Fault as there is no object, but since that is not the case, hence the function executes properly.
NOTE: It all depends on how a compiler implements member function access. Some compiler may choose to see if the pointer of object is null before accessing the member function, but then the pointer may have some garbage value instead of 0 which a compiler cannot check, so generally compilers ignore this check.
You can achieve a lot with undefined behavior. You can even call a function which only takes 1 argument and receive the second one like this:
#include <iostream>
void Func(int x)
{
uintptr_t ptr = reinterpret_cast<uintptr_t>(&x) + sizeof(x);
uintptr_t* sPtr = (uintptr_t*)ptr;
const char* secondArgument = (const char*)*sPtr;
std::cout << secondArgument << std::endl;
}
int main()
{
typedef void(*PROCADDR)(int, const char*);
PROCADDR ext_addr = reinterpret_cast<PROCADDR>(&Func);
//call the function
ext_addr(10, "arg");
return 0;
}
Compile and run under windows and you will get "arg" as result for the second argument. This is not a fault within C++, it is just plain stupid on my part :)
This will work on most compilers. When you make a call to a method (non virtual), the compiler translates:
obj.foo();
to something:
foo(&obj);
Where &obj becomes the this pointer for foo method. When you use a pointer:
Obj *pObj = NULL;
pObj->foo();
For the compiler it is nothing but:
foo(pObj);
i.e.:
foo(NULL);
Calling any function with null pointer is not a crime, the null pointer (i.e. pointer having null value) will be pushed to call stack. It is up to the target function to check if null was passed to it. It is like calling:
strlen(NULL);
Which will compile, and also run, if it is handled:
size_t strlen(const char* ptr) {
if (ptr==NULL) return 0;
... // rest of code if `ptr` is not null
}
Thus, this is very much valid:
((A*)NULL)->f2();
As long as f2 is non-virtual, and if f2 doesn't read/write anything out of this, including any virtual function calls. Static data and function access will still be okay.
However, if method is virtual, the function call is not as simple as it appears. Compiler puts some additional code to perform late binding of given function. The late binding is totally based on what is being pointed by this pointer. It is compiler dependent, but a call like:
obj->virtual_fun();
Will involve looking up the current type of obj by virtual function table lookup. therefore, obj must not be null.
It might be obvious for who knows the background magic, but I could not understand how below code is giving correct output. I expected a runtime error. Please help.
class a
{
public:
void print()
{
cout<<"Hello\n"<<endl;
int d = 100;
cout<<d<<endl;
}
int val;
};
int main()
{
a* ptr;
ptr->print();
return SUCCESS;
}
OUTPUT is as below :
Hello
100
There is no magic - your code has undefined behavior. In your code you do not access ptr which is implicitly passed to print() as this pointer, that is why no error happen.
It may happen in several other cases:
Accessing fields of a instance. It will require to read memory *(this + field_offset) which will cause runtime error.
Accessing virtual methods. Implementations known to me use vtable to do that, which is usually stored as first pointer in object space, so pointer to vtable would be same as this, so: vtable = *this
Other cases, depending on compiler and platform
NOTE: type conversion is omitted from examples with this
a::print is a not a virtual method, hence it is just a normal function that has an extra argument to receive the this pointer. Since the method never uses the this pointer, the fact that it is uninitialized doesn't turn into a memory access error or other failure. Declaring a::print static will still compile in this case since it doesn't use the this pointer. Declaring a::print virtual or accessing this inside the method will likely lead to the program crashing, at least under some circumstances.
The behavior is still undefined and it is an ill-formed program, but as it stands now it is very likely to work deterministically on most systems. In general C++ does not give runtime errors for such cases, but if you compile with e.g. "clang++ -Wall" a warning indicating the uninitialized variable will be given. (And there are tools such as clang's asan which will go further in diagnosing such errors.)
I'm looking for clarification on this bit of code. The call to A::hello() works (I expected a segv). The segfault does come through on the access to member x, so it seems like the method resolution alone doesn't actually dereference bla?
I compiled with optimization off, gcc 4.6.3. Why doesn't bla->hello() blow up? Just wonderin' what's going on. Thanks.
class A
{
public:
int x;
A() { cout << "constructing a" << endl; }
void hello()
{
cout << "hello a" << endl;
}
};
int main()
{
A * bla;
bla = NULL;
bla->hello(); // prints "hello a"
bla->x = 5; // segfault
}
Your program exhibits undefined behavior. "Seems to work" is one possible manifestation of undefined behavior.
In particular, bla->hello() call appears to work because hello() doesn't actually use this in any way, so it just happens not to notice that this is not a valid pointer.
You are dereferencing NULL pointer, i.e. trying to access object stored at address NULL:
bla = NULL;
bla->hello();
bla->x = 5;
which results in undefined behavior, which means that anything can happen, including the seg fault while assigning 5 to the member x and also including deceptive "works as expected" effect while invoking the hello method.
At least in the typical implementation, when you call a non-virtual member function via a pointer, that pointer is not dereferenced to find the function.
The type of the pointer is used to determine the scope (context) in which to search for the name of the function, but that happens entirely at compile time. What the pointer points at (including "nothing", in the case of a null pointer) is irrelevant to finding the function itself.
After the compiler finds the correct function, it typically translates a call like a->b(c); into something roughly equivalent to: b(a, c); -- a then becomes the value of this inside the function. When the function refers to data in the object, this is dereferenced to find the correct object, then an offset is normally applied to find the correct item in that object.
If the member function never attempts to use any of the object's members, the fact that this is a null pointer doesn't affect anything.
If, on the other hand, the member function does attempt to use a member of the object, it'll attempt to dereference this to do that, and if this is a NULL pointer, that won't work. Likewise, calling a virtual function always uses the vtable pointer, which is in the object, so attempting to call a virtual function via a null pointer can be expected to fail (regardless of whether the code in the virtual function refers to data in the object or not).
As I said to start with, I'm talking about the typical implementation here. From the viewpoint of the standard, you simply have undefined behavior, and that's the end of it. In theory, an implementation doesn't have to work the way I've described. In reality, however, essentially all the reasonably popular implementations of C++ (e.g., MS VC++, g++, Clang, and Intel) all work very similarly in these respects.
As long as a member function doesn't dereference this, it's usually "safe" to call it, but you're then in undefined behavior land.
In theory, this is undefined behavior. In practice, you do not use this pointer when calling hello(), it does not reference your class at all, and therefore works and does not generate memory access violation. When you do bla->x, however, you are trying to reference a memory though bla pointer which is uninitialized, and it crashes. Again, even in this case there is no guarantee that it will crash, this is undefined behavior.
I noticed I don't get any compiler errors when I accidentally forget to return from a function that is supposed to return a reference. I wrote some small tests to see what actually happens and I got more confused than anything.
struct Foo
{
int x;
Foo() {
x = 3;
}
};
Foo* foo = new Foo;
Foo& test(bool flag) {
if (flag)
return *foo;
}
If test() doesn't (explicitly) return a value, I will still get something returned. However the Foo object that is returned is not initialized using the default constructor — that's because x is different from 3 in the non-explicitly returned value.
What is actually happening when you don't return a reference? If this is a feature, is it safe to use it as a means to return dummy objects in case errors occur, as opposed to returning a null pointer. (See example below.)
class FooFactory
{
// Return reference...
Foo& createFooRef() {
Foo* foo = new Foo;
bool success = foo->load();
if (success)
return *foo;
// Implicit (and safe?) return value on failure?
}
// ... as opposed to returning a pointer.
Foo* createFooPtr() {
Foo* foo = new foo;
bool success = foo->load();
if (success)
return foo;
else
return 0;
}
// Yes, I am aware of the memory leaks,
// but that's not the point of the example.
Most compilers will give you a warning about this, but you may have to crank up the warning level of the compiler to see it.
No, this is not safe. It is bad. It may lead to stack corruption by just returning whatever happens to be on the stack at the time. As you've already seen, it does not use a constructor for you. If you want a default constructed object, you have to do that yourself (but be careful about returning a reference to a temporary object. That's also bad).
The usual way to lower references in compilers is to pointers. For a reference-returning function, it will mean you get an arbitrary address represented, whatever was in the register or stack slot used for the return value.
Formally in the language, the effects are undefined.
This is undefined behaviour, and infinite bad things may happen, or indeed, may not happen, or might happen sometimes, or might simultaneously happen and not happen if it doesn't like you, or send engineers from Microsoft to your house to beat you over the head with a baseball bat.
The described behaviour is not limited to functions that returns references. The following code will also compile:
int func1( int i )
{
if( i )
return 3; // C4715 warning, nothing returned if i == 0
}
I'm not sure why they generate just a warning, not an error (there might be an option in settings to turn it into error), but you will get undefined behaviour if you call such a function
References are typically just syntactic sugar for pointers, so the return is going to grab a pointer's worth of bytes from the stack for the return value. If you aren't giving it that it will just grab garbage.
I had to use the function and then add -Wall to get g++ to complain:
g++ -Wall foo.cc
foo.cc: In member function 'Foo& FooFactory::createFooRef()':
foo.cc:19: warning: control reaches end of non-void function
Have you tried compiling with /O1 optimisations or greater on and treat warnings as errors? That might fail. I remember something along those lines happening in GCC 4.1. You could forget to return the reference in debug mode, but the reference would return; as soon as you put any optimisations on it would still compile, but not return the reference. When coding in a text editor (as I was in those days) it was a total pain and a huge surprise to me.
Lets say you have something like this:
int& refint;
int* foo =0;
refint = *foo;
How could you verify if the reference is NULL to avoid a crash?
You can't late-initialize a reference like that. It has to be initialized when it's declared.
On Visual C++ I get
error C2530: 'refint' : references
must be initialized
with your code.
If you 'fix' the code, the crash (strictly, undefined behaviour) happens at reference usage time in VC++ v10.
int* foo = 0;
int& refint(*foo);
int i(refint); // access violation here
The way to make this safe is to check the pointer at reference initialization or assignment time.
int* foo =0;
if (foo)
{
int& refint(*foo);
int i(refint);
}
though that still does not guarantee foo points to usable memory, nor that it remains so while the reference is in scope.
You don't, by the time you have a "null" reference you already have undefined behaviour. You should always check whether a pointer is null before trying to form a reference by dereferencing the pointer.
(Your code is illegal; you can't create an uninitialized reference and try and bind it by assigning it; you can only bind it during initialization.)
In general, you can't.
Whoever "creates a null reference" (or tries to, I should say) has already invoked undefined behavior, so the code might (or might not) crash before you get a chance to check anything.
Whoever created the reference should have done:
int *foo = 0;
if (foo) {
int &refint = *foo;
... use refint for something ...
}
Normally it's considered the caller's problem if they've written *foo when foo is null, and it's not one function's responsibility to check for that kind of error in the code of other functions. But you could litter things like assert(&refint); through your code. They might help catch errors made by your callers, since after all for any function you write there's a reasonable chance the caller is yourself.
All the answers above are correct, but if for some reason you want to do this I thought at least one person should provide an answer. I am currently trying to track down a bad reference in some source code and it would be useful to see if someone has deleted this reference and set it to null at some point. Hopefully this wont generate to many down votes.
#include <iostream>
int main()
{
int* foo = nullptr;
int& refint = *foo;
if(&refint == nullptr)
std::cout << "Null" << std::endl;
else
std::cout << "Value " << refint << std::endl;
}
Output:
Null
To make the above code compile, you will have to switch the order:
int* foo =0;
int& refint = *foo; // on actual PCs, this code will crash here
(There may be older processor or runtime architectures where this worked.)
....saying all of the above, if you do want to have a null reference, use boost::optional<>, works like a charm..
You don't need to, references cannot be null.
Read the manual.