如何限制使用`malloc()`获取的内存而不限制堆栈?

12

我试图限制学生的代码不要进行过多的内存分配,以免拖慢我的测试机。我已经尝试过:

setrlimit(RLIMIT_DATA, r);

这里的r是一个保存限制的结构体。但遗憾的是,尽管这个限制可以阻止brksbrk进行分配,但C库会切换到使用mmap并继续分配内存。

我还尝试过其他方法。

setrlimit(RLIMIT_AS, r)

这将导致进程停止,然而这种解决方法过于严厉—由于没有栈空间来处理从malloc()返回的NULL 值时代码调用的函数,因此进程无法从ENOMEM错误中恢复。

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

更新:我找到了一个叫做failmalloc的东西,但它并不是很复杂,尽管我可以用它引发故障,但我总是得到一个gdb无法诊断的段错误。

进一步更新:我发现setrlimit(RLIMIT_AS, r)似乎可以做到我想要的工作,至少在某些情况下—之后出现的段错误是由与问题无关的模块中的错误引起的。除非有人提供一些有趣的东西(或者有理由保留问题),否则我可能会删除这个问题。


如果你只是试图防止滥用/有错误的程序导致系统崩溃,那就不要费心让它们从失败的malloc中恢复。只需让操作系统终止它们并结束掉。一个正确的程序本来就不应该超过限制的。 - R.. GitHub STOP HELPING ICE
许多学生提交了错误的程序。如果他们崩溃了,他们就会得到零分。如果他们恢复并中止,他们将获得部分学分。 - Norman Ramsey
2个回答

5

借鉴了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程序禁用库插入。
使用GNU链接器的--wrap symbol选项是一种替代方案,而不是使用dlsym()函数。

1
我猜valgrind源代码应该包含类似的方法。 - Jens Gustedt

3
你能强制让毫不知情的学生使用宏吗? :-)
#define malloc(bytes) limited_malloc(bytes)

同时还需要定义一个limited_malloc函数,限制其可执行的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接