Як перевірити, яку межу перевищено? (Процес припиняється через недозволення.)


11

Припустимо, що процес працює в необмеженому середовищі:

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

Програма припиняється.

Причин може бути багато: перевищено обмеження на пам'ять / час / файл; просто простий segfault; або навіть нормальне припинення з кодом повернення 0.

Як перевірити, що було причиною припинення програми, не змінюючи програму?

PS Я маю на увазі "коли двійкові дані". Можливо, якась обгортка (переклад тощо) може допомогти?

Відповіді:


6

Взагалі кажучи, я, на жаль, не можу. (Деякі операційні системи можуть це забезпечити, але я не знаю тих, кого я знаю, що підтримують це.)

Довідковий документ щодо обмеження ресурсів: getrlimitвід POSIX 2008.

Візьмемо для прикладу ліміт процесора RLIMIT_CPU.

  • Якщо процес перевищує м'який ліміт, йому надсилається a SIGXCPU
  • Якщо процес перевищує жорстку межу, він отримує звичайну SIGKILL

Якщо ви можете wait()у своїй програмі, ви можете сказати, чи її вбив SIGXCPU. Але ви не змогли відрізнити SIGKILLвідправленого за порушення жорсткої межі від простого старого вбивства ззовні. Більше того, якщо програма обробляє програму XCPU, ви її навіть не побачите ззовні.

Те саме для RLIMIT_FSIZE. Ви можете бачити статус SIGXFSZзі wait()статусом, якщо програма його не обробляє. Але як тільки буде перевищено обмеження розміру файлу, єдине, що трапляється, це те, що подальший ввід / вивід, який намагається знову перевірити цей ліміт, просто отримає EFBIG- це буде оброблятися (чи ні, на жаль,) програмою внутрішньо. Якщо програма обробляє так SIGXFSZсамо, як вище, ви не будете знати про неї.

RLIMIT_NOFILE? Ну, ти навіть сигналу не отримуєш. openа друзі просто повертаються EMFILEдо програми. Інакше це не турбує, тому він зазнає невдачі (чи ні) тим, яким способом було б закодовано провал у цій ситуації.

RLIMIT_STACK? Старий добрий SIGSEGV, його не можна відрізнити від кількості інших причин, щоб його доставити. (Ви будете знати, що саме це вбило процес від waitстатусу.)

RLIMIT_ASі RLIMIT_DATAпросто зробить, malloc()а деякі інші почнуть виходити з ладу (або отримуватимуть, SIGSEGVякщо буде досягнуто обмеження AS, намагаючись розширити стек в Linux). Якщо програма не дуже добре написана, вона, ймовірно, вийде досить випадковим чином у цей момент.

Отже, коротко кажучи, як правило, збої або не помітно відрізняються від інших причин смерті процесу, тому ви не можете бути впевнені, або можете вирішуватись цілком з програми, і в цьому випадку він вирішує, чи / коли / як він проходить, а не ви ззовні.

Наскільки я знаю, ви можете написати трохи коду, який розщедрить вашу програму, чекає на неї та:

  • перевірити стан виходу для виявлення SIGXCPUта SIGXFSZ(AFAIK, ці сигнали будуть генеровані ОС лише для проблем з обмеженням ресурсів). В залежності від ваших конкретних потреб, можна припустити , що SIGKILLі SIGSEGVбули пов'язані з обмеженнями ресурсів, але це трохи розтягнути.
  • подивіться на те, що ви можете отримати getrusage(RUSAGE_CHILDREN,...)у своїй реалізації, щоб отримати підказку про інші.

Тут можуть існувати спеціальні засоби для ОС (можливо, такі речі, як ptraceLinux або Solaris dtrace), або, можливо, методи налагодження типу, але це буде ще більше пов'язане з вашою конкретною реалізацією.


(Я сподіваюся, що хтось інший відповість якоюсь магічною річчю, про яку я абсолютно не знаю.)


В порядку. А як щодо цих трьох: (Mem) перевищення межі пам'яті, (Time) обмеження часу, (Err) інша помилка? Я знаю про створення обгортки навколо, mallocале, на жаль, це взагалі не вирішує проблему з пам'яттю, тому що загалом йдеться про системний виклик brk(я прав?).
Grzegorz Wierzowiecki

1
Обгортання malloc не допоможе, якщо ви не контролюєте програму. Якщо ви говорите про зломи , як LD_PRELOADING , що це прикордонне для «не змінюйте процесу» обмеження, і це допоможе трохи, але на самому ділі не - malloc, brk, sbrkі mmapбуде завершуватися ENOMEM, точно так , як якщо б ви дійсно були в ситуації низької пам'яті (але значно нижче меж пам'яті). Межа часу RLIMIT_CPU, я не знаю обмеження настінного годинника.
Мат

Дякуємо, що забезпечили мене brk. Як я бачу, вимога "програма не обробляє сигнали X, Y, Z ..." вирішить проблеми SIGXCPU, SIGXFSZ, SIGSEGV, завдяки неслухняному (якщо я помиляюся, будь ласка, виправте мене).
Grzegorz Wierzowiecki

1
SIGSEGV може бути піднятий у ситуаціях, які не є обмеженням обмеження ресурсів (нульова перенаправлення вказівника є найпоширенішою справою, що викликає його) - ви не можете бути впевнені, що його невдалий хіт викликає це.
мат

Дякуємо, що забезпечили мене brk. Як я бачу, вимога "програма не обробляє сигнали X, Y, Z ..." вирішить проблеми SIGXCPU, SIGXFSZ, SIGSEGV, завдяки неслухняному. Я правий?
Grzegorz Wierzowiecki

3

Зараз я займаюся деякою роботою над тим же питанням. Мені вдалося отримати часткове рішення. Я використовував підсистему аудиту . Ви можете відстежувати роботу за адресою [1].

[1] https://github.com/PaulDaviesC/Logging-limits.conf

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.