【问题标题】:How can I limit memory acquired with `malloc()` without also limiting stack?如何在不限制堆栈的情况下限制使用“malloc()”获取的内存?
【发布时间】:2010-10-06 00:20:51
【问题描述】:

我正在努力防止学生代码在分配中乱跑并将我的测试机器拖到停止状态。我试过了

setrlimit(RLIMIT_DATA, r);

其中r 是一个包含限制的结构。但不幸的是,虽然这个限制阻止了brksbrk 的分配,但C 库只是故障转移到mmap 并继续分配。

我也试过

setrlimit(RLIMIT_AS, r)

这会使进程停止运行,但这种补救措施太严重了——进程不可能从ENOMEM错误中恢复,因为没有堆栈空间用于代码在遇到NULL时进行的调用从malloc() 返回的值。

我对二进制文件的控制有限,所以如果可以使用系统调用,我更愿意这样做。但是我需要一些限制分配的方法,而不会破坏进程的恢复能力。有人有建议吗?

更新:我发现了一个叫failmalloc 的东西,但它不是很复杂,虽然我可以用它导致失败,但我总是得到一个 gdb 无法诊断的段错误。

进一步更新:我发现 setrlimit(RLIMIT_AS, r) 确实 似乎完成了我想要的工作,至少在某些情况下——之后发生的段错误是由不相关模块中的故障。除非有人提出一些有趣的事情(或保留问题的理由),否则我可能会删除该问题。

【问题讨论】:

  • 如果您只是想防止滥用/错误程序关闭系统,请不要费心让它们从失败的malloc 中恢复。让操作系统杀死它们并完成它。一个正确的程序大概不应该达到极限。
  • 许多学生提交了错误的程序。如果他们转储核心,他们会得到零。如果他们恢复并中止,则获得部分功劳。

标签: c malloc setrlimit


【解决方案1】:

基于failmalloc 使用的想法,您可以使用LD_PRELOAD* 环境变量和函数插入以围绕 malloc() 构建包装器并在那里施加任何限制。

您需要使用dlsym() 动态加载指向原始malloc() 的指针。您不能直接从包装器中调用原始的malloc(),因为它将被解释为对包装器本身的递归调用。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>

void * malloc(size_t size)
{
   static void * (*func)(size_t) = NULL;
   void * ret;

   if (!func)
   {
      /* get reference to original (libc provided) malloc */
      func = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc");
   }

   /* impose any necessary restrictions before calling malloc */
   ...

   /* call original malloc */
   ret = func(size);

   /* impose any necessary restrictions after calling malloc */
   ...

   return ret;
}

* 请注意,LD_PRELOAD 必须指定插入器库的完整路径,并且对于 setuid 程序禁用库插入以防止出现安全问题。


使用dlsym()alternative 将使用GNU 链接器--wrap symbol 选项。

【讨论】:

  • 我猜 valgrind 的源代码应该包含类似于该方法的内容。
【解决方案2】:

你能对毫无戒心的学生强制使用宏吗? :-)

#define malloc(bytes) limited_malloc(bytes)

还有limited_malloc 的定义,它限制了可以做什么。

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 2011-02-16
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多