【问题标题】:Callback on memory access?回调内存访问?
【发布时间】:2011-09-06 20:58:16
【问题描述】:

当内存被访问(读取或写入)时,是否存在分配一些内存并进行某种回调(无论是指向函数还是信号的指针)的方法?

例如,如果我说分配 1mb 的内存,我希望有一种方法可以在访问任何 1mb 时调用函数。

我正在开发的平台是 x86 Linux,使用 C/C++ 编写。

【问题讨论】:

标签: c++ c linux memory kernel


【解决方案1】:

是的,有。

使用 mprotect(2) 系统调用(请参阅:http://linux.die.net/man/2/mprotect)在页面上设置只读或不访问内存保护,并设置将在访问内存时调用的 SIGEGVsignal 处理程序。

请注意,一旦调用了信号处理程序,您将需要在信号处理程序中使用 mprotect 来实际允许内存访问,并且当您这样做时,您会在不知情的情况下打开一个窗口以访问内存,例如从一个不同的线程。这可能是也可能不是问题,具体取决于您的具体使用情况。

【讨论】:

  • 是的,但这实际上不会阻止访问吗?我认为问题是如何知道访问,而不是如何阻止它。
  • 您的程序会收到一个 SIGSEGV 信号。您可以捕获信号并使用 mprotect 更改内存保护以启用操作,当您从信号处理程序返回时,操作将自动成功,因为程序指针仍指向同一位置。这里隐藏了一个竞争条件,这可能是也可能不是问题。我已经编辑了答案以对此进行扩展。谢谢
  • @gby - 但是一旦您更改了权限 - 您将无法再跟踪它,因为具有相同权限的后续访问不会触发信号。所以这是一种一次性的事情,不是吗?
  • 老实说,mprotect() 并没有被列为异步信号安全,所以以这种方式使用它可能会导致死锁理论上(如果 mprotects 尝试采取锁定在信号命中时已被占用的 C 库中)。在实践中,我怀疑 glibc/linux 下的 mprotect 不会采取任何此类锁定,但我没有对此进行验证。
  • 您可以尝试在读取/写入数据到页面的指令之后修补代码,在此处放置断点(INT3)并在访问后恢复保护,而不是使用计时器。它不是防弹的(记住线程),但比计时器好得多。
【解决方案2】:

嗯....你可以设置一个缓冲区。您甚至可以使用分配设置一个数组。然后设置一个 if 语句,如果有任何东西篡改了该数组部分,例如,如果数组在索引处的默认值为 0,而现在它不是,则调用您想要执行的任何操作。

如果您希望发生很多事情,然后程序中断并响应该分配被篡改,请设置一个布尔值,当值更改时,该布尔值变为真,并发布一个函数来检查该布尔值.

【讨论】:

    【解决方案3】:

    我认为没有这样的 API 可以做到这一点,直到您在分配的内存周围创建一个包装器对象,然后通过此包装器对象完成对内存的访问。然后这个包装器对象将能够看到对底层内存的所有访问。

    【讨论】:

      【解决方案4】:

      您可以使用您自己的“安全指针”类的版本,该类将包装分配的指针,顺便说一下,将实现取消引用运算符。但是,它需要使用它来进行分配。

      以下几行:

      // based on pretty standard auto_ptr
      template <class T> class auto_ptr
      {
          T* ptr;
      public:
          explicit auto_ptr(T* p = 0) : ptr(p) {}
          ~auto_ptr()                 {delete ptr;}
          T& operator*()              {return *ptr;}   // <<--- add your stuff here
          T* operator->()             {return ptr;} // <<--- and here
          // .
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-30
        • 2018-01-11
        • 1970-01-01
        • 1970-01-01
        • 2014-04-24
        • 2020-10-24
        • 1970-01-01
        相关资源
        最近更新 更多