阿里笔试题-修改虚函数表指针
https://www.zhihu.com/question/29256578/answer/43725188
一道阿里实习生笔试题的疑惑?
解答:
作者:RednaxelaFX
链接:https://www.zhihu.com/question/29256578/answer/43725188
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这几句不应该用int*,而应该用intptr_t*才对。这样才能保证拷贝的是一个指针宽度的数据,而不是一个int宽度的数据。
链接:https://www.zhihu.com/question/29256578/answer/43725188
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
首先
大大的答案已经把思路说得很清楚了。这是个hack,不是C++语言规范所保证的行为,而是某些C++编译器采用的C++ ABI的行为。
放个传送门:为什么bs虚函数表的地址(int*)(&bs)与虚函数地址(int*)*(int*)(&bs) 不是同一个? - RednaxelaFX 的回答
其次,这代码不但依赖某些C++编译器的行为,还依赖平台的指针宽度是32位。int * p = (int *)(&kitty);
int * q = (int *)(&jd);
p[0] = q[0];
- 在32位平台上,int通常是32位,而指针是32位,所以正好匹配了,程序能正常运行;
- 在64位平台上,如果是流行的LP64模型,int是32位而指针是64位,这里实际上只拷贝了指针的一半,程序能否正常运行就看运气了。
如果是在一个64位且小端(little endian)的平台上,那这代码拷贝的是指针的低32位。很可能会运气好能正常运行,因为dog类与cat类的vtable可能正好在内存里处于很近的位置,它们的地址的高32位可能正好相同,地址不同的地方都在低32位,这样这个程序就运气好能正常运行。
如果是在一个64位且大端(big endian)的平台上,那这段代码拷贝的是指针的高32位,那就完全达不到效果了。
不知道谁出的这种题⋯
或者题主把题目的细节记错了。
后面有回答说原本的笔试题不是p[0] = q[0],而是p[1] = q[1]。如果是这样的话那仍然只能在32位平台上能行,在64位平台上就纱布了。
#include <iostream>
using namespace std;
class animal
{
protected:
int age_;
animal(int age): age_(age) { }
public:
virtual void print_age(void) = 0;
virtual void print_kind() = 0;
virtual void print_status() = 0;
};
class dog : public animal
{
public:
dog(): animal(2) { }
~dog() { }
virtual void print_age(void) {
cout << "Woof, my age = " << age_ << endl;
}
virtual void print_kind() {
cout << "I'm a dog" << endl;
}
virtual void print_status() {
cout << "I'm barking" << endl;
}
};
class cat : public animal
{
public:
cat(): animal(1) { }
~cat() { }
virtual void print_age(void) {
cout << "Meow, my age = " << age_ << endl;
}
virtual void print_kind() {
cout << "I'm a cat" << endl;
}
virtual void print_status() {
cout << "I'm sleeping" << endl;
}
};
void print_random_message(void* something) {
cout << "I'm crazy" << endl;
}
int main(void)
{
cat kitty;
dog puppy;
animal* pa = &kitty;
intptr_t* cat_vptr = *((intptr_t**)(&kitty));
intptr_t* dog_vptr = *((intptr_t**)(&puppy));
intptr_t fake_vtable[] = {
dog_vptr[0