Method call after invalid C-style cast works - c++

So I'm trying to learn a bit more about the differences between C-style-casts, static_cast, dynamic_cast and I decided to try this example which should reflect the differences between C-style-casts and static_cast pretty good.
class B
{
public:
void hi() { cout << "hello" << endl; }
};
class D: public B {};
class A {};
int main()
{
A* a = new A();
B* b = (B*)a;
b->hi();
}
Well this code snippet should reflect that the C-style-cast goes very wrong and the bad cast is not detected at all. Partially it happens that way. The bad cast is not detected, but I was surprised when the program, instead of crashing at b->hi();, it printed on the screen the word "hello".
Now, why is this happening ? What object was used to call such a method, when there's no B object instantiated ? I'm using g++ to compile.

As others said it is undefined behaviour.
Why it is working though? It is probably because the function call is linked statically, during compile-time (it's not virtual function). The function B::hi() exists so it is called. Try to add variable to class B and use it in function hi(). Then you will see problem (trash value) on the screen:
class B
{
public:
void hi() { cout << "hello, my value is " << x << endl; }
private:
int x = 5;
};
Otherwise you could make function hi() virtual. Then function is linked dynamically, at runtime and program crashes immediately:
class B
{
public:
virtual void hi() { cout << "hello" << endl; }
};

This only works because of the implementation of the hi() method itself, and the peculiar part of the C++ spec called undefined behaviour.
Casting using a C-style cast to an incompatible pointer type is undefined behaviour - literally anything at all could happen.
In this case, the compiler has obviously decided to just trust you, and has decided to believe that b is indeed a valid pointer to an instance of B - this is in fact all a C-style cast will ever do, as they involve no runtime behaviour. When you call hi() on it, the method works because:
It doesn't access any instance variables belonging to B but not A (indeed, it doesn't access any instance variables at all)
It's not virtual, so it doesn't need to be looked up in b's vtable to be called
Therefore it works, but in almost all non-trivial cases such a malformed cast followed by a method call would result in a crash or memory corruption. And you can't rely on this kind of behaviour - undefined doesn't mean it has to be the same every time you run it, either. The compiler is perfectly within its rights with this code to insert a random number generator and, upon generating a 1, start up a complete copy of the original Doom. Keep that firmly in mind whenever anything involving undefined behaviour appears to work, because it might not work tomorrow and you need to treat it like that.

Now, why is this happening ?
Because it can happen. Anything can happen. The behaviour is undefined.
The fact that something unexpected happened demonstrates well why UB is so dangerous. If it always caused a crash, then it would be far easier to deal with.
What object was used to call such a method
Most likely, the compiler blindly trusts you, and assumes that b does point to an object of type B (which it doesn't). It probably would use the pointed memory as if the assumption was true. The member function didn't access any of the memory that belongs to the object, and the behaviour happened to be the same as if there had been an object of correct type.
Being undefined, the behaviour could be completely different. If you try to run the program again, the standard doesn't guarantee that demons won't fly out of your nose.

Related

What is the effect of calling a virtual method by a base class pointer bound to a derived object that has been deleted

The fllowing questions are:
p->test() should not work after b is destroyed. However, the code is running without any issue, the dynamic binding still works;
when the destructor of A is defined, the dynamic binding doesnot work anymore. What is the logic behind it?
#include <iostream>
using namespace std;
struct A {
//~A() {}
virtual void test() { cout << 0 << endl; }
};
class B :public A {
void test() { cout << 1 << endl; }
};
int main() {
A* p;
{
B b;
p = &b;
}
p->test(); // the method called will be different if the destructor of A is removed
}
p->test() should not work after b is destroyed. However, the code is running without any issue, the dynamic binding still works;
It does not "work". p->test() invokes undefined behavior.
when the destructor of A is defined, the dynamic binding doesnot work anymore. What is the logic behind it?
There is no logic behind it, other than implementation details of the compiler you are using, because the C++ standard does not mandate what a compiler should do with code that has undefined behavior.
For more details on undefined behavior I refer you to https://en.cppreference.com/w/cpp/language/ub
Compilers cannot detect all undefined behavior, but some of it. With gcc you can try -fsanitize=address to see the issue more clearly: https://godbolt.org/z/qxTs4sxcW.
Welcome to the world of Undefined Behaviour! Any access to a deleted object, including calling a method on it invokes undefined behaviour.
That means that the languages requires no specific behaviour, and depending on the internals of the compiler and possibly on any apparently unrelated thing on the computer anything can happen from the expected behaviour (you experienced it) to an immediate crash or unexpected results occuring immediately or later.
Never try to test the result of an UB operation: it can change from one compilation to a new one even with the same configuration or even from one run to the other if it depends on uninitialized memory.
Worse: if the compiler can detect UB in a portion of code, it can optimize out that portion because the language allows it to assume that a program should never invoke UB.
TL/DR: you are invoking UB here. Don't. Just don't.

I accidentally called a member function without own class object. But how does this work?

Here is my code.
class IService {
};
class X_Service {
public:
void service1() {
std::cout<< "Service1 Running..."<<std::endl;
}
};
int main() {
IService service;
auto func = reinterpret_cast<void (IService::*)()>(&X_Service::service1);
(service.*(func))();
return 0;
}
I don't understand how this works. I didn't inherit IService and didn't create a X_Service object but it works.
Can someone explain this?
Your confusion probably comes from the misunderstanding that because something compiles and runs without crashing, it "works". Which is not really true.
There are many ways you can break the rules of the language and still write code that compiles and runs. By using reinterpret_cast here and making an invalid cast you have broken the rules of the language, and your program has Undefined Behaviour.
That means it can seem to work, it can crash or it can just do something completely different from what you intended.
In your case it seems to work, but it's still UB and the code is not valid.
Under the hood your compiler will turn all these functions into machine code that is basically just jumps to certain addresses in memory and then executing commands stored there.
A member function is just a function that has in addition to local variables and parameters, a piece of memory that stores the address of the class object. That piece of memory holds the address you are accessing when you use the this keyword.
If you call a member function on a wrong object or nullptr, then you basically just make the this pointer point to something invalid.
Your function doesn't access this, which is the reason your program doesn't blow up.
That said, this is still undefined behavior, and anything could happen.
So, I had some fun and manipulated the code a bit. This is also an empirical answer. There are a lot of pitfalls that risk stack corruption with this way of doing things, so I changed the code a bit to make it to where stack corruption does not occur but kind of show what it happening.
#include <iostream>
class IService {
public:
int x;
};
class X_Service {
public:
int x;
void service1() {
this->x = 65;
std::cout << this->x << std::endl;
}
};
int main() {
IService service;
auto func = reinterpret_cast<void (IService::*)()>(&X_Service::service1);
(service.*(func))();
std::cout << service.x << std::endl;
std::cin.get();
X_Service derp;
(derp.service1)();
std::cout << derp.x << std::endl;
return 0;
}
So from the outset, auto gave you the power to make a none type safe pointer void (IService::*)()also the instance of the object itself is this-> regardless of what member function of whatever class you are stealth inheriting from. The only issue is that the first variable of the instance is interpreted based on the first variable of the class you are stealth inheriting from, which can lead to stack corruption if the type differs.
Ways to get cool output but inevitably cause stack corruption, you can do the following fun things.
class IService {
public:
char x;
};
Your IDE will detect stack corruption of your IService object, but getting that output of
65
A
is kind of worth it, but you will see that issues will arise doing this stealth inheritance.
I'm also on an 86x compiler. So basically my variable are all lined up. Say for instance if I add an int y above int x in Iservice, this program would output nonsense. Basically it only works because my classes are binary compatible.
When you reinterpret_cast a function or member function pointer to a different type, you are never allowed to call the resulting pointer except if you cast it back to its original type first and call through that.
Violating this rule causes undefined behavior. This means that you loose any language guarantee that the program will behave in any specific way, absent additional guarantees from your specific compiler.
reinterpret_cast is generally dangerous because it completely circumvents the type system. If you use it you need to always verify yourself by looking at the language rules, whether the cast and the way the result will be used is well-defined. reinterpret_cast tells the compiler that you know what you are doing and that you don't want any warning or error, even if the result will be non-sense.

Strange results with object creation and binding

Mistakenly I wrote something daft, which to my surprise worked.
class A
{ public:
void print()
{
std::cout << "You can't/won't see me !!!" << std::endl;
}
A* get_me_the_current_object()
{
return this;
}
};
int main()
{
A* abc = dynamic_cast<A*>(abc);
abc->print();
}
Here, A* abc = dynamic_cast<A*>(abc), I am doing dynamic_cast on a pointer, which isn't declared. But, it works, so I assumed that the above statement is broken as:
A* abc;
abc = dynamic_cast<A*>(abc);
and therefore, it works. However, on trying some more weird scenarios such as:
A* abc;
abc->print();
and, further
A* abc = abc->get_me_the_current_object();
abc->print();
I was flabbergasted, looking at how these examples worked and the mapping was done.
Can someone please elaborate on how these are working? Thanks in advance.
You've made the common mistake of thinking that undefined behaviour and C++ bugs mean you should expect to see a dramatic crash or your computer catching fire. Sometimes nothing happens. That doesn't mean the code "works", because it's still got a bug, it's just that the symptoms haven't shown up ... yet.
But, it works, so I assumed that the above statement is broken as:
Yes, all you're doing is converting an uninitialized pointer to the same type, i.e. no conversion needed, so the compiler does nothing. Your pointer is still the same type and is still uninitialized.
This is similar to this:
int i = i;
This is valid according to the grammar of C++, because i is in scope at that point, but is undefined because it copies an uninitialized object. It's unlikely to actually set your computer on fire though, it appears to "work".
Can someone please elaborate on how these are working?
Technically you're dereferencing an invalid pointer, which is undefined behaviour, but since your member functions don't actually use any members of the object, the invalid this pointer is not dereferenced, so the code "works" (or at least appears to.)
This is similar to:
void function(A* that)
{
std::cout << "Hello, world!\n";
}
A* p;
function(p);
Because the that pointer is not used (like the this pointer is not used in your member functions) this doesn't necessarily crash, although it might do on implementations where even copying an uninitialized pointer could cause a hardware fault. In your example it seems that your compiler doesn't need to dereference abc to call a non-static member function, and passing it as the hidden this parameter does not cause a hardware fault, but the behaviour is still undefined even though it doesn't fail in an obvious way such as a segfault..
abc is uninitialized and points to an undefined location in memory, but your methods don't read anything from *this so they won't crash.
The fact that they won't crash is almost certainly implementation defined behavior though.

C++ Memory access in Xcode behaves differently than eclipse

while writing native c++ code and i see same programme works fine in xcode(iOS), though crashes in eclipse(android). I could find the problem code and that was due a bad memory access. I wonder why xcode(iOS) didn't hit the same bad access hence crash.
Actually i created a class say "class_A" which inherits other class say class_B. Later in the code i created the same class instance pointer and assigned the return object of function foo() (belongs to class_B) which returns the object of type super class i.e class_B.
code snippet ...
class class_A : public class_B
{
public:
};
class_A *tempPart = (class_A *)class_A::foo("abc.png");
if(tempPart)
{
-------------------
--------------------
}
Now, while accessing _tempPart the programme crashes for android (eclipse), however xcode(iOS) always works fine. I could figure out that as fn foo() returns the object of type class_B hence i was assigning a super class(smaller size object) class_B's object to inherited class (a bigger size object) Class_A's object hence it was causing a bad memory access.
But i couldn't figure out why the same issue is not seen on xcode(iOS).
i am new to xcode and c++, so please help me to understand this.
Undefined behavior is undefined.
Doing things like accessing invalid memory results in undefined behavior in C++. The result may often be a crash, but C++ doesn't guarantee such things. Instead the program may simply behave oddly, or even exactly as you intended with no indication of an error. Different implementations may do different things.
Here's some info that may help explain why C++ has undefined behavior (as opposed to languages like Java which work very hard to rule out undefined behavior).
What Every C Programmer Should Know About Undefined Behavior
Part 1
Part 2
Part 3
It's not entirely clear from your description what's really going wrong. You say something about assigning a bigger object to a smaller object causing bad memory access, however that's not the way assignment in C++ works, and the example code is using pointers anyway. The following code is completely legal and well defined, for example:
struct B {};
struct D : B {
int i;
void foo() { i = 100; }
};
B b = D(); // works fine, does not overwrite anything outside b. Slicing occurs.
B *bar() {
return new D;
}
D *d = (D*)bar(); // works fine because the dynamic type matches.
Where a problem occurs is:
B *baz() { return new B; }
D *d = (D*)baz(); // not okay, undefined behavior. Anything can happen now, later, or even before this point.
d->foo(); // might crash, might not.
So, assuming this is what your program is doing, the same error in Java is well defined to cause an exception. In Objective-C the message passing machinery will try to find an implementation for the selector at runtime and if it does not find anything then an 'unrecognized selector' exception occurs.
As #Bames53 has answered, this is undefined behavior. A quick fix would be to make class_B::foo a template function and rewrite it as follows
template <class ReturnClassType>
ReturnClassType *foo(std::string str){
You would then call it as
class_A::foo<class_A>("abc.png");
If you use public/protected functions to init the returned object, this should work.
You can't safely upcast B to A. B doesn't have a _useShader member. You can only do vice versa: B* = A*, but not A* = B*. You may want to create a separate factory method for A objects.

static_cast doubt

#include <iostream>
class A
{
public:
A()
{
std::cout << "\n A_Constructor \t" << this <<std::endl;
}
void A_Method()
{
std::cout <<"\n A_Method \t" << this <<std::endl;
}
};
class B:public A
{
public:
B()
{
std::cout <<"\n B_Constructor \n";
}
void B_Method()
{
std::cout <<"\n B_Method \t" << this <<std::endl;
}
};
int main()
{
A *a_obj = new A;
B *b_obj = static_cast<B*> (a_obj); // This isn't safe.
b_obj->B_Method();
getchar();
return 0;
}
OUTPUT :
A_Constructor 001C4890
B_Method 001C4890
As no run-time check isn't involved in type conversion, static_cast isn't safe. But in this example, I got what I didn't even expect. Since there is no call to B::B(), any of it's members should not be able to get called by b_obj. Despite that I got the output.
In this simple case, I might have succeeded though it is known unsafe. My doubts are -
Though there is no call to B::B(), how was I able to access class B member functions.
Can some one please provide an example, where this is unsafe and might get wrong( though what I given before might serve as a bad example, but even better).
I did it on Visual Studio 2010 and with \Wall option set.
This is Undefined Behavior. Sometimes UB causes crashes. Sometimes it seems to "work". You are right that you shouldn't do this, even though in this case less bad things happened.
What you are trying is undefined behaviour so ANYTHING could happen. This seems to work (and probably works) fine as you don't try to access any data members (you don't have any). Try to add some data members to both classes and access it from methods, you will see that behaviour will change to completely unpredictable.
I doubt that this particular case is UB. First, it just casts a pointer from one type to another. Since there is no virtual/multiple inheritance involved, no pointer adjustment is performed, so basically the pointer value stays the same. Surely it points to an object of a wrong type, but who cares, as long as we don't access any B members, even if there were some? And even if there was pointer adjustment involved, it would still be okay if we didn't access any memory pointed by it, which we don't.
Then, the example calls a method of B. Since it is not virtual, it just a normal function call with the hidden argument this (think B::B_Method(this)). Now, this points to an object of a wrong type, but again, who cares? The only thing it does is print it, which is always a safe thing to do.
In fact, you can even call methods using a NULL pointer. It works as long as the method isn't virtual and doesn't try to access anything pointed by this. I once had a library used by many programs. This library had a singleton-like class which had to be constructed explicitly, but none of the programs actually did it. The instance pointer was initialized to NULL by default, as it was global. It worked perfectly since the class had no data members at all. Then I added some and all the programs suddenly started to crash. When I found out the reason, I had a really good laugh. I've been using an object that didn't even exist.