Sto eseguendo pdftoppm
per convertire un PDF fornito dall'utente in un'immagine a 300 DPI. Funziona alla grande, a meno che l'utente non fornisca un PDF con una dimensione della pagina molto grande. pdftoppm
allocherà memoria sufficiente per contenere un'immagine a 300 DPI di quella dimensione in memoria, che per una pagina quadrata da 100 pollici è 100 * 300 * 100 * 300 * 4 byte per pixel =3,5 GB. Un utente malintenzionato potrebbe semplicemente darmi un PDF di grandi dimensioni e causare tutti i tipi di problemi.
Quindi quello che mi piacerebbe fare è porre una sorta di limite all'utilizzo della memoria per un processo figlio che sto per eseguire:basta che il processo muoia se tenta di allocare più di, diciamo, 500 MB di memoria. È possibile?
Non credo che ulimit possa essere utilizzato per questo, ma esiste un equivalente a un processo?
Risposta accettata:
Ci sono alcuni problemi con ulimit. Ecco una lettura utile sull'argomento:Limitare il tempo e il consumo di memoria di un programma in Linux, che porta allo strumento di timeout, che ti consente di ingabbiare un processo (e i suoi fork) in base al tempo o al consumo di memoria.
Lo strumento di timeout richiede Perl 5+ e /proc
filesystem montato. Dopodiché copi lo strumento ad es. /usr/local/bin
così:
curl https://raw.githubusercontent.com/pshved/timeout/master/timeout |
sudo tee /usr/local/bin/timeout && sudo chmod 755 /usr/local/bin/timeout
Successivamente, puoi "ingabbiare" il tuo processo in base al consumo di memoria come nella tua domanda in questo modo:
timeout -m 500 pdftoppm Sample.pdf
In alternativa puoi usare -t <seconds>
e -x <hertz>
per limitare rispettivamente il processo in base al tempo o ai vincoli della CPU.
Il modo in cui funziona questo strumento è controllare più volte al secondo se il processo generato non ha superato i limiti impostati. Ciò significa che esiste effettivamente una piccola finestra in cui un processo potrebbe potenzialmente sottoscrivere in eccesso prima che venga notificato un timeout e interrompa il processo.
Un approccio più corretto quindi probabilmente coinvolgerebbe cgroups, ma è molto più complicato da configurare, anche se useresti Docker o runC, che tra le cose, offrono un'astrazione più user-friendly attorno a cgroups.