如何更改C ++引用(以任何必要的方式)

时间:2016-06-23 03:45:44

标签: c++

C ++语言不允许在分配引用后更改引用。但是,我有调试需要/希望更改引用以帮助调试某些东西。是否存在基本上用新指针覆盖引用实现的hacky方法?获得要更改的对象的地址后,可以将其转换为您想要的任何内容并覆盖它。我无法弄清楚如何获取底层引用实例的内存地址;使用&取消引用引用并不会为您提供引用的地址,而是引用所指向的对象的地址。

我意识到这显然会调用未定义的行为,这只是一个实验。第三方库有一个全局引用的错误,在执行代码之前没有构造,我想看看我是否可以通过自己设置引用来修复它。在这一点上,看看它是否可能成为一个挑战。如果您可以直接引用符号表,我知道您可以用汇编语言执行此操作。

我想象这样的事情。这些是全局范围的变量。

Apple a;
Apple& ref = a;

稍后我希望ref引用新的对象实例b并单独留下a

Apple b;

ref = b; // that doesn't work. that justs sets a=b.

&ref = &b; // that doesn't work. the compiler complains.

uint64_t addr  = find_symbol_by_any_means_necessary(ref);
*(Apple**)addr = &b; // this should work if I could get addr

请不要提醒我这是一个坏主意。我知道这是一个坏主意。把它想象成一个挑战。这仅用于调试,以快速测试假设。我想了解一下C ++二进制代码的内部结构。 (请告诉我,由于系统页面保护是不可能的......如果引用放在圣地,我想你可能会遇到段错误)。

(系统是CentOS 7,编译器是Intel,虽然我可以使用gcc进行此实验)。

2 个答案:

答案 0 :(得分:4)

我认为没有办法重定向独立引用变量引用的对象。

如果引用包含在struct中作为成员变量,则可以轻松更改引用变量引用的对象。它很可能是UB,但它适用于我当前版本的g ++,g ++ 4.8.4。

这是一个演示方法的示例程序。

#include <iostream>
#include <cstring>

struct Foo
{
   int& ref;
};

int main()
{
   int a = 10;
   int b = 20;

   Foo foo = {a};  // foo.ref is a reference to a
   std::cout << foo.ref << std::endl;

   // Use memcpy to change what foo.ref references
   int* bPtr = &b;
   std::memcpy(&foo, &bPtr, sizeof(bPtr));

   // Now, foo.ref is a reference to b
   std::cout << foo.ref << std::endl;

   // Changing foo.ref changes b
   foo.ref = 30;
   std::cout << b << std::endl;
}

输出:

10
20
30

答案 1 :(得分:0)

通常不可能,因为引用不可重载的事实允许大量优化。

例如,引用通常实现为指针,但编译器也可能注意到您经常使用固定偏移量。因此,除了存储指针之外,编译器还可以决定存储指针加上偏移量。它甚至可能决定只存储指针和偏移量。

另一个优化是将引用存储为CPU寄存器中的地址。由于它无法更改,编译器无需重新加载它。

所以你的声明,你可以在汇编中改变它是相当误导。您不知道在优化之后引用的表示是什么,并且此优化将在情境上依赖。