do
Używając języka programowania C i testowanego z jądrem Linux 2.6.32-49-generic i libc-2.11.1.so.
Jedynym sposobem na zwolnienie pamięci jest zabicie programu w menedżerze zadań lub użycie taskkill / im yourprogram / f lub nawet ponowne uruchomienie komputera.
Osiąga się to poprzez blokowanie wszelkich sygnałów oprócz SIGKILL i SIGSTOP.
Zamknięcie go powinno nadal sprawić, że pamięć będzie świnią.
To mnie faktycznie pomyliło ... Zarówno zabicie, jak i zamknięcie obu powoduje zakończenie procesu, pozwalając systemowi operacyjnemu odzyskać pamięć przydzieloną przez proces. Ale potem pomyślałem, że zamykając go, możesz chcieć zamknąć terminal lub inny proces nadrzędny, który wykonuje proces wycieku pamięci. Jeśli dobrze to zrozumiałem, rozwiązałem ten problem, blokując wszelkie sygnały, które zamieniają proces w demona po zakończeniu procesu nadrzędnego. W ten sposób możesz zamknąć terminal, w którym działa proces, który będzie kontynuował działanie i przejdzie do wycieku pamięci.
Wszelkie bomby widłowe są zakazane. Oznacza to, że niesławny bash: () {: |: &} ;: jest zbanowany!
Proces nie rozwidla się.
Aplikacja musi być tylko jednowątkowa. To implikuje zasadę bomby widelcowej
Nie pojawiają się nowe wątki.
Program nie może uruchamiać innego programu. Oznacza to, że nie można po prostu zrobić czegoś takiego jak uruchom (memoryfiller.exe)
Nie pojawiają się nowe procesy.
Możesz zająć tyle pamięci, ile chcesz. Im więcej tym lepiej.
Tyle, ile może zapewnić system operacyjny.
Kod musi zostać w pełni wyjaśniony.
Dodano komentarze do źródła.
I w końcu oto kod:
#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
/*
set the real, effective and set user id to root,
so that the process can adjust possible limits.
if the process doesn't have the CAP_SETUID capability, terminate the process.
*/
if (setresuid(0, 0, 0) == -1) {
printf("Are you root?!\n");
return 1;
}
/*
block all signals except for kill and stop.
this allows to terminate the parent process (most likely a terminal)
that this process is running in and turn it into a daemon.
additionally this makes it impossible to terminate the process
in a normal way and therefore satisfies the requirement that closing
it should still make it hog memory.
*/
sigset_t mask;
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
/*
allow the process to acquire a virtually unlimited amount of memory
and queue a virtually unlimited amount of signals.
this is to prevent an out of memory error due to a virtual limit for the root user,
which would prevent the process from leaking any more memory
and to prevent the process from getting killed due to too many queued
signals that the process is blocking.
*/
struct rlimit memory = { RLIM_INFINITY, RLIM_INFINITY },
signal = { RLIM_INFINITY, RLIM_INFINITY};
setrlimit(RLIMIT_AS, &memory);
setrlimit(RLIMIT_SIGPENDING, &signal);
/*
allocate a buffer big enough to store a file name into it
that is generated from the process' pid.
if the file can be opened (which should always be the case unless /proc is not mounted)
the file will be opened and the string -17 followed by a new line written to it.
this will cause the oom killer to ignore our process and only kill other,
innocent processes when running out of memory.
*/
char file_name[20];
sprintf(file_name, "/proc/%u/oom_adj", getpid());
FILE* oom_killer_file = fopen(file_name, "w");
if (oom_killer_file) {
fprintf(oom_killer_file, "-17\n");
fclose(oom_killer_file);
}
/*
get the size of virtual memory pages in bytes,
so the process knows the size of chunks that have to be
made dirty to force the kernel to map the virtual memory page into RAM.
*/
long page_size = sysconf(_SC_PAGESIZE);
// allocate a virtually infinite amount of memory by chunks of a page size.
while(1) {
// will overwrite any previous stored address in tmp, leaking that memory.
char* tmp = (char*) malloc(page_size);
if (tmp)
// make the memory page dirty to force the kernel to map it into RAM.
tmp[0] = 0;
}
return 0;
}
Dla każdego, kto jest zainteresowany tym, co się stanie, jeśli ten program będzie nadal działał: Na moim systemie testowym z 2 GB pamięci RAM i 4 GB miejsca wymiany zajęło około 10 minut, aby wypełnić pamięć RAM i wymienić. Zabójca OOM rozpoczął pracę, a trzy minuty później wszystkie procesy zostały zabite. System upuścił nawet mysz, klawiaturę i wyświetlacz. /var/log/kern.log nie pokazuje żadnych użytecznych informacji, z wyjątkiem procesów, które zostały zabite.