Edm*_*und 9 compiler-construction closures garbage-collection boehm-gc
在我再次关闭的编译器项目中,我已经将闭包实现为具有可执行前缀的已分配内存.所以闭包是这样分配的:
c = make_closure(code_ptr, env_size, env_data);
Run Code Online (Sandbox Code Playgroud)
c 指向已分配内存块的指针,如下所示:
movl $closure_call, %eax
call *%eax
.align 4
; size of environment
; environment data
; pointer to closure code
Run Code Online (Sandbox Code Playgroud)
closure_call是一个辅助函数,它查看最近放在堆栈上的地址,并使用它来查找闭包数据和代码指针.Boehm GC用于一般内存管理,当不再引用闭包时,它可以由GC解除分配.
无论如何,这个分配的内存需要标记为可执行; 事实上,它跨越的整个页面都被标记出来.随着闭包的创建和释放,进程中越来越多的堆内存将是可执行的.
出于防御性编程的原因,我宁愿最小化可执行堆的数量.我的计划是尝试将所有闭包保存在同一页面上,并根据需要分配和释放可执行页面; 即为闭包实现自定义分配器.(如果所有闭包大小相同,这会更容易;因此第一步是将环境数据移动到可以正常管理的单独的非可执行分配中.这也使得防御性编程有意义.)
但剩下的问题是GC.Boehm已经做到了!我想要的是以某种方式告诉Boehm关于我的自定义分配,并让Boehm告诉我他们什么时候能够进行GC,但要让我自己解除分配.
所以我的问题是,Boehm中是否有钩子提供这样的自定义分配?
您也许可以使用终结器执行您想要的操作 - Boehm GC 仍会释放它,但您将有机会事先使用断点操作(x86 上的 0xCC)来 memset 闭包,并在可能的情况下将其页面标记为不可执行。
然而,终结器会带来性能成本,因此不应轻易使用。Boehm GC 基于标记-清除算法,该算法首先识别所有不应释放的块( mark.c),然后一次性释放所有其他块 (reclaim.c)。在您的情况下,修改回收过程以使用断点操作填充可执行区域中的所有可用空间,并在页面完全变空时将其标记为不可执行是有意义的。这避免了终结器,但以分叉库为代价(我找不到任何可扩展性机制)。
最后,请注意,执行预防是一种深度防御措施,而不应该是您唯一的安全保护。面向返回的编程可用于使用不可修改的可执行区域执行任意代码。