Как я могу ограничить память, полученную с помощью `malloc()` без ограничения стека?
Я пытаюсь заставить код студента работать с распределением и перетащить мою тестовую машину на остановку. Я пробовал
setrlimit(RLIMIT_DATA, r);
где r
- структура, удерживающая пределы. Но, к сожалению, хотя этот предел останавливает выделение brk
и sbrk
, библиотека C просто терпит неудачу до mmap
и сохраняет право на выделение.
Я также пробовал
setrlimit(RLIMIT_AS, r)
и это останавливает процесс на своих дорожках, но это средство слишком тяжелое: невозможно восстановить процесс из ошибки ENOMEM
, потому что нет места стека для вызовов, которые код создает при встрече с NULL
значение, возвращаемое из malloc()
.
У меня ограниченный контроль над двоичными файлами, поэтому, если это возможно сделать с системным вызовом, я бы предпочел это. Но мне нужно какое-то средство укупорки, не разрушая способность процесса к восстановлению. У кого-нибудь есть предложения?
ОБНОВЛЕНИЕ. Я нашел что-то под названием failmalloc, но он не очень сложный, и хотя я могу вызвать с ним сбой, Я всегда получаю segfault, который gdb не может диагностировать.
ДАЛЬНЕЙШЕЕ ОБНОВЛЕНИЕ. Я обнаружил, что setrlimit(RLIMIT_AS, r)
, похоже, выполняет задание, которое я хочу, по крайней мере, в некоторых случаях: segfaults, которые произошли после этого, были вызваны ошибкой в несвязанном модуле. Если кто-то не придумает что-то интересное (или повод оставить вопрос), я, вероятно, удалю вопрос.
Ответы
Ответ 1
Основываясь на идее, используемой failmalloc, вы можете использовать LD_PRELOAD *
переменная среды и интерполяция функций, чтобы создать обертку вокруг malloc()
и наложить там какие-либо ограничения.
Вам нужно будет динамически загрузить указатель на исходный malloc()
с помощью dlsym()
. Вы не можете напрямую вызывать исходный 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, чтобы предотвратить проблемы безопасности.
An альтернатива для использования dlsym()
будет использовать GNU linker --wrap symbol
.
Ответ 2
Можете ли вы наложить макрос на ничего не подозревающих студентов?: -)
#define malloc(bytes) limited_malloc(bytes)
а также определение для limited_malloc
, которое ограничивает то, что можно сделать.