Как проверить, какой лимит превышен? (Процесс прерван из-за ulimit.)

11

Давайте предположим, что процесс выполняется в неограниченной среде:

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

Программа прекращена.

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

Как проверить, что послужило причиной завершения программы, без внесения изменений в программу?

PS я имею ввиду "когда бинарный дан". Может быть, какая-нибудь обертка (ptrace-ing и т. Д.) Может помочь?

Гжегож Вежовецкий
источник

Ответы:

6

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

Справочный документ по ограничениям ресурсов: getrlimitс POSIX 2008.

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

  • Если процесс превышает мягкое ограничение, он получает 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,...)своей реализации, чтобы получить подсказку о других.

Здесь могут быть полезны специфические для ОС средства (возможно, такие как ptraceв Linux или Solaris dtrace) или, возможно, методы типа отладчика, но это будет еще более привязано к вашей конкретной реализации.


(Я надеюсь, что кто-то другой ответит магией, о которой я не подозреваю.)

Мат
источник
ОК. Как насчет этих трех: (Mem) превышение лимита памяти, (Time) ограничение по времени, (Err) другая ошибка? Я знаю о создании обертки, mallocно, к сожалению, это не решает проблему с памятью в целом, потому что в целом речь идет о системном вызове brk(я прав?).
Гжегож Вежовецкий
1
Обертывание malloc не поможет, если вы не управляете программой. Если вы говорите о взломах , как LD_PRELOADING , что это пограничное для «не модифицирующего процесса» ограничения, и это поможет немного, но на самом деле не - malloc, brk, sbrkи mmapбудет завершаться ENOMEM, точно так , как если бы вы действительно были в ситуации низкой памяти (но намного ниже пределов памяти). Ограничение по времени RLIMIT_CPU, я не знаю ограничения по времени настенных часов.
Мат
Спасибо за предоставление мне о brk. Как я вижу, требование «программа не обрабатывает сигналы X, Y, Z ...» решит проблемы SIGXCPU, SIGXFSZ, SIGSEGV, благодаря waitpid (Если я ошибаюсь, пожалуйста, исправьте меня).
Гжегож Вежовецкий
1
SIGSEGV может быть вызван в ситуациях, которые не являются нарушениями ограничения ресурса (разыменование нулевого указателя является наиболее распространенной причиной, вызывающей его) - вы не можете быть уверены, что это удар ulimit, который его вызывает.
Мат
Спасибо за предоставление мне о brk. Как я вижу, требование «программа не обрабатывает сигналы X, Y, Z ...» решит проблемы SIGXCPU, SIGXFSZ, SIGSEGV, благодаря waitpid. Я прав?
Гжегож Вежовецкий
3

В настоящее время я работаю над тем же вопросом. Я был в состоянии иметь частичное решение этого. Я использовал аудит системы . Вы можете отслеживать работу на [1].

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

PaulDaviesC
источник