【发布时间】:2019-07-08 19:38:11
【问题描述】:
我想编写一个函数 computeWriteSet,它接受任意函数 f 作为参数,并且 (1) 执行函数 f 并且 (2) 返回修改后的 places 集合或在f 执行期间写入(地址/页面/对象)。
writeset computeWriteSet(function f) {
writeset ws = createEmptyWriteset();
// prepare to execute f
startRecordingWrites(&ws);
f();
stopRecordingWrites(&ws);
// post-process the write-set
return ws;
}
- 有哪些实施方案可供选择?
- 它们的权衡是什么(在哪种情况下哪种实现更有效,有什么限制?)
注意事项
函数在运行时指定,可以做任何事情(即可以包含任何指令集,包括循环、分支和函数/系统调用。
应该记录从调用f 到它返回的所有写入(这包括从f 本身调用的函数)。为简单起见,我们假设 computeWriteSet 没有从内部调用。
特定于操作系统的技巧是允许的(并且可能是必需的)。我对 Linux 尤其感兴趣,最好是在用户空间中。
示例
static int x = 0;
static int y = 0;
static int z = 0;
void a() {
if (y) z++;
if (x) y++;
x = (x + 1) % 2;
}
int main() {
computeWriteSet(a); // returns { &x } => {x,y,z} = {1, 0, 0}
computeWriteSet(a); // returns { &x, &y } => {x,y,z} = {0, 1, 0}
computeWriteSet(a); // returns { &x, &z } => {x,y,z} = {1, 1, 1}
return 0;
}
预期输出
输出应该是一组更改。这可以是页面集:
{ <address of x>, <address of y>, …}
或者内存地址集:
{<page of x and y>, <page of z>, …}
或对象集((基于分配函数的插入)
x = malloc(100) // returns address 0xAAA
y = malloc(200) // returns address 0xBBB
…
{ {address, size}, {0xAAA, 100}, {0xBBB, 200}, … }
返回值是有意松散指定的——不同的技术会有不同的空间分辨率和不同的开销。
请注意:
这是一个非常罕见的编程问题,因此,如果您认为应该关闭它,请告诉我为什么,理想情况下,如何措辞/放置它以使其遵循指南。 :-)
【问题讨论】:
-
valgrind/memcheck的源代码可能包含你想要的。 -
我怀疑这些程序的工作方式是使用
mprotect将内存标记为只读。然后任何内存修改都会触发一个信号,并且处理程序会跟踪它试图修改的内存。 -
继续@Barmar 的想法。在检测到写入只读页面后,您需要设置保护以写入并重复操作(这是调试器在监视写入时通常会执行的操作)。不过这会非常慢。
-
没有什么好方法可以满足您的要求。它需要对代码进行检测,类似于 valgrind 或其他工具。权衡将是运行时性能和额外的编译或运行步骤。开发(或重用)此功能也很头疼。
-
如果您正在寻找可以帮助您完成任务的工具,那么您的问题与“软件推荐”问题无关。如果你想收集ideas,那么问题就是“open-ended”。如果你想得到一个完全描述实现你想要的方法的答案,那么对于 Stack Overflow 格式,这样的答案将是 太长。您需要通过选择检测工具来缩小问题的范围,并专门询问如何将此工具应用于特定任务。
标签: c linux memory linux-kernel operating-system