Come verificare quale limite è stato superato? (Processo terminato a causa di ulimit.)


11

Supponiamo che il processo venga eseguito in un ambiente limitato:

(
ulimit  ... -v ... -t ... -x 0 ...
./program
)

Il programma è terminato.

Potrebbero esserci molte ragioni: limite di memoria / tempo / file superato; solo un semplice segfault; o anche la normale chiusura con codice di ritorno 0.

Come verificare qual è stato il motivo della conclusione del programma, senza modificare il programma?

PS intendo "quando viene dato il binario". Forse qualche wrapper (ptrace-ing ecc.) Potrebbe aiutare?

Risposte:


6

In generale, non penso che tu possa purtroppo. (Alcuni sistemi operativi potrebbero provvedere, ma non sono a conoscenza di quelli che conosco supportando questo.)

Documento di riferimento per i limiti delle risorse: getrlimitda POSIX 2008.

Prendiamo ad esempio il limite della CPU RLIMIT_CPU.

  • Se il processo supera il limite software, viene inviato a SIGXCPU
  • Se il processo supera il limite massimo, diventa chiaro SIGKILL

Se puoi wait()sul tuo programma, potresti dire se è stato ucciso da SIGXCPU. Ma non potevi differenziare un SIGKILLmandato per violazione del limite rigido da una vecchia uccisione normale dall'esterno. Inoltre, se il programma gestisce il XCPU, non lo vedrai nemmeno dall'esterno.

Stessa cosa per RLIMIT_FSIZE. Puoi vedere SIGXFSZdallo wait()stato se il programma non lo gestisce. Ma una volta superato il limite della dimensione del file, l'unica cosa che succede è che ulteriori I / O che tentano di testare nuovamente quel limite riceveranno semplicemente EFBIG- questo sarà gestito (o sfortunatamente) dal programma internamente. Se il programma gestisce SIGXFSZ, come sopra - non lo saprai.

RLIMIT_NOFILE? Bene, non ricevi nemmeno un segnale. opene gli amici sono appena tornati EMFILEal programma. Altrimenti non è disturbato, quindi fallirà (o meno) in qualunque modo sia stato programmato per fallire in quella situazione.

RLIMIT_STACK? Buon vecchio SIGSEGV, non si può distinguere dal punteggio di altri motivi per essere consegnato uno. (Saprai che quello è stato ciò che ha ucciso il processo dallo waitstato.)

RLIMIT_ASe RLIMIT_DATAfarà solo malloc()e alcuni altri inizieranno a fallire (o riceveranno SIGSEGVse il limite AS viene raggiunto mentre si tenta di estendere lo stack su Linux). A meno che il programma non sia scritto molto bene, probabilmente a quel punto fallirà in modo abbastanza casuale.

Quindi in breve, in generale, i guasti non sono visibilmente diversi dagli altri motivi di morte del processo, quindi non si può essere sicuri, o possono essere gestiti interamente dal programma nel qual caso decide se / quando / come procede, non tu da fuori.

Il meglio che puoi fare per quanto ne so è scrivere un po 'di codice che forks del tuo programma, aspetta su di esso e:

  • controllare lo stato di uscita per rilevare SIGXCPUe SIGXFSZ(AFAIK, quei segnali saranno generati dal sistema operativo solo per problemi di limite delle risorse). A seconda delle vostre esigenze, si potrebbe supporre che SIGKILLe SIGSEGVsono stati anche in relazione ai limiti di risorse, ma questo è un po 'di un tratto.
  • guarda cosa puoi ottenere dalla getrusage(RUSAGE_CHILDREN,...)tua implementazione per avere un suggerimento sugli altri.

Potrebbero esistere strutture specifiche del sistema operativo per aiutare qui (forse cose come ptracesu Linux o Solaris dtrace), o forse tecniche di tipo debugger, ma questo sarà ancora più legato alla tua specifica implementazione.


(Spero che qualcun altro risponda con qualcosa di magico di cui non sono completamente a conoscenza.)


Ok. Che dire solo di questi tre: (Mem) che supera il limite di memoria, (Time) limite di tempo, (Err) altro errore? So di creare wrapper mallocma sfortunatamente non risolve il problema di memoria in generale, perché in generale si tratta di una chiamata di sistema brk(ho ragione?).
Grzegorz Wierzowiecki,

1
Il wrapping di malloc non ti aiuterà se non controlli il programma. Se stai parlando di hack come LD_PRELOADing quel confine per il vostro "non modificare il processo di" vincolo, e vi aiuterà un po ', ma non realmente - malloc, brk, sbrke mmapnon riuscirà con ENOMEM, esattamente come se fossi veramente in una situazione di memoria insufficiente (ma molto al di sotto dei limiti di memoria). Il limite di tempo è RLIMIT_CPUche non conosco un limite di tempo per l'orologio da parete.
Mat,

Grazie per avermi assicurato brk. Come vedo, il requisito 'il programma non gestisce i segnali X, Y, Z ...' risolverà i problemi di SIGXCPU, SIGXFSZ, SIGSEGV, grazie a waitpid (se sbaglio, per favore correggimi).
Grzegorz Wierzowiecki,

1
SIGSEGV può essere sollevato in situazioni che non sono violazioni del limite di risorse (la dereferenza del puntatore null è la cosa più comune che lo solleva) - non si può essere sicuri che sia un colpo ulimit che lo causa.
Mat

Grazie per avermi assicurato brk. Come vedo, il requisito "il programma non gestisce i segnali X, Y, Z ..." risolverà i problemi di SIGXCPU, SIGXFSZ, SIGSEGV, grazie a waitpid. Ho ragione?
Grzegorz Wierzowiecki,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.