Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I limit memory acquired with `malloc()` without also limiting stack?

I'm trying to keep student code from running wild with allocations and dragging my test machine to a halt. I've tried

setrlimit(RLIMIT_DATA, r);

where r is a struct holding the limits. But unfortunately although this limit stops brk and sbrk from allocating, the C library just fails over to mmap and keeps right on allocating.

I've also tried

setrlimit(RLIMIT_AS, r)

and this stops the process in its tracks, but this remedy is too severe—it is impossible for the process to recover from the ENOMEM error because there's no stack space for the calls the code makes on encountering a NULL value returned from malloc().

I have limited controls over the binaries, so if it's possible to do with a system call, I'd prefer that. But I need some means of capping allocation without destroying the process's ability to recover. Does anyone have suggestions?

UPDATE: I found something called failmalloc, but it is not very sophisticated, and although I can cause a failure with it, I always get a segfault that gdb cannot diagnose.

FURTHER UPDATE: I found that setrlimit(RLIMIT_AS, r) does seem to do the job I want, at least in some cases—the segfaults that were occurring afterward were caused by a fault in an unrelated module. Unless somebody comes up with something interesting (or a reason to keep the question), I will probably delete the question.

like image 384
Norman Ramsey Avatar asked Oct 06 '10 00:10

Norman Ramsey


People also ask

What is the maximum memory that I can allocate using malloc?

What is the maximum memory that can be allocated using malloc()? In order to represent the size internally, malloc() uses 32-bit signed integers. Because of this, in a single allocation, malloc() cannot be used to allocate more than 2 GB of memory.

Does malloc consume physical memory?

TL;DR: malloc returns a virtual address and does NOT allocate physical memory.

Should malloc be avoided?

Of course, like ALL engineering/software design, it is not "you MUST NOT USE malloc", but "avoid malloc if there is a simple/suitable alternative".

How much memory can a program allocate?

This is data for which memory is being allocated while executing the program. In C++, this allocation is usually performed by the malloc function or new operator. In 32-bit programs the size of dynamically allocated memory is restricted to 2 Gbytes, in 64-bit programs to 8 Tbytes.


1 Answers

Building on the idea used by failmalloc, you could use the LD_PRELOAD* environment variable and function interposition to build a wrapper around malloc() and impose any limitations there.

You would need to dynamically load a pointer to the original malloc() using dlsym(). You cannot directly call the original malloc() from the wrapper because it will be interpreted as a recursive call to the wrapper itself.

#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;
}

* Note that LD_PRELOAD must specify the full path to the interposer library, and that library interposition is disabled for setuid programs in order to prevent security problems.


An alternative to using dlsym() would be to use the GNU linker --wrap symbol option.

like image 133
jschmier Avatar answered Sep 22 '22 13:09

jschmier