1

简短的问题:
是否可以将一个已经 malloc 的缓冲区映射为具有两种访问同一缓冲区的方式(两个指针指向同一物理内存)?或者,是否可以临时移动 malloc 接收到的虚拟内存地址?或者是否可以从虚拟空间中的一个位置指向另一个位置?

背景:
我正在使用DirectFB一个表面管理和 2D 图形堆肥库。我正在尝试强制执行锁定协议,即锁定表面,仅在锁定时修改内存(指针指向使用 malloc 分配的系统内存),然后解锁表面。

我目前正在尝试追踪一个应用程序中的一个错误,该错误是锁定一个表面,然后存储像素指针并稍后修改表面。这意味着库不知道何时可以安全地读取或写入表面。我正在尝试找到一种方法来检测是否违反了锁定协议。我想要的是一种在进行解锁调用后使传递给用户的指针无效的方法。更好的是,如果应用程序在锁定后尝试访问内存,我希望应用程序能够分段错误。这将在调试器中停止,并让我们了解涉及哪个表面、涉及哪个例程、谁调用了它等。

可能的解决方案:

  1. 创建一个临时缓冲区,将缓冲区指针传递给用户,解锁时将像素复制到实际缓冲区,删除临时缓冲区。

    • 优点:这是一个可实施的解决方案。
    • 缺点:性能很慢,因为它需要一个昂贵的副本,而且内存可能可用也可能不可用。无法保证一个临时表面与另一个表面重叠,从而允许无效的指针突然再次工作。
  2. 为 malloc 的表面制作额外的地图并将其传递给用户。解锁时,取消映射内存。

    • 优点:非常快,不需要额外的内存。
    • 缺点:不知道这是否可能。
    • 陷阱:需要留出一个保留的地址范围,不会被其他任何东西(包括 malloc 或内核)使用。还需要确保没有两个表面重叠,这可能允许旧指针突然指向有效的东西,而不是在应该的时候出现段错误。
  3. 利用库在被用户锁定时不访问内存这一事实,只需将虚拟地址移动到锁上并在解锁时将其移回。

    • 优点:非常快,不需要额外的内存。
    • 缺点:不知道这是否可能。
    • 陷阱:与上面的“2”相同。

这可行吗?

附加信息:

  • 这是 using Linux 2.6, using stdlib
  • 该库是用C.
  • 库和应用程序在用户空间中运行。
  • 有可能使用内核模块(编写自定义内存分配例程),但在我当前的工作环境中编写模块的难度可能会将我实际实现此解决方案的机会降低到接近零的水平。但如果这是唯一的方法,那就太好了。
  • 底层处理器是x86.
4

1 回答 1

5

您要创建一个页面的多个映射的功能是shm_open

您可能只在一个进程中使用内存,但它仍然是“共享内存” - 也就是说,同一底层物理页面将存在多个虚拟映射。

但是,这不是您想要的。您实际上应该做的是让您的锁定功能使用mprotect系统调用来使内存在解锁时不可读并恢复锁定权限;任何没有持有锁的访问都会导致段错误。当然,这只适用于单个同时访问线程......

跟踪问题的另一种可能更好的方法是在valgrind或其他内存分析工具中运行您的应用程序。这将大大减慢它的速度,但允许您进行非常精细的控制:您可以使用 valgrind 脚本将内存标记/取消标记为可访问,并且当发生违规时,该工具将直接将您踢入调试器。但是对于像这样一次性解决问题,我会说在您的锁定/解锁功能中安装一个#ifdef DEBUG-wrapped调用。mprotect

于 2012-07-23T18:21:20.590 回答