C-код на Linux под GDB работает по-другому, если запустить автономно? - PullRequest
3 голосов
/ 01 марта 2010

Я создал простой C-код в Linux (Fedora), используя цепочку инструментов code-sorcery. Это для цели ARM Cortex-A8. Этот код работает на плате Cortex A8, работает под управлением встроенного Linux.

Когда я запускаю этот код для некоторого тестового примера, который выполняет динамическое выделение памяти (malloc) для некоторого большого размера (10 МБ), он через некоторое время выдает сообщение об ошибке, как показано ниже:

select 1 (init), adj 0, size 61, to kill
select 1030 (syslogd), adj 0, size 64, to kill
select 1032 (klogd), adj 0, size 74, to kill
select 1227 (bash), adj 0, size 378, to kill
select 1254 (ppp), adj 0, size 1069, to kill
select 1255 (TheoraDec_Corte), adj 0, size 1159, to kill
send sigkill to 1255 (TheoraDec_Corte), adj 0, size 1159
Program terminated with signal SIGKILL, Killed.

Затем, когда я отлаживаю этот код для того же тестового примера с использованием gdb, созданного для цели, в момент, когда происходит такое динамическое выделение памяти, код не может выделить эту память и malloc возвращает NULL. Но во время обычного автономного запуска я считаю, что malloc не удается выделить, но странным образом может не возвращаться NULL, но происходит сбой, и ОС убивает мой процесс.

  1. Почему это поведение отличается при работе под GDB и без отладчика?
  2. Почему malloc терпит неудачу, но не возвращает NULL. Возможно ли это, или причина сообщения об ошибке - другое?
  3. Как мне это исправить?

спасибо,

-AD

Ответы [ 2 ]

6 голосов
/ 01 марта 2010

Итак, для этой части вопроса есть верный ответ:

Почему malloc не работает, но не возвращает NULL. Возможно ли это, или причина сообщения об ошибке, которое я получаю, в другом?

В Linux по умолчанию интерфейсы ядра для выделения памяти почти никогда не выходят из строя напрямую. Вместо этого они настраивают вашу таблицу страниц таким образом, чтобы при первом обращении к запрошенной вами памяти ЦП сгенерировал ошибку страницы , после чего ядро ​​обрабатывает это и ищет физическую память, которая будет использоваться для этой (виртуальной) страницы. Таким образом, в ситуации нехватки памяти вы можете спросить ядро ​​о памяти, оно будет «успешным», и при первой попытке прикоснуться к той памяти, которую оно вернуло обратно, это , когда происходит выделение на самом деле терпит неудачу, убивая ваш процесс. (Или, может быть, какая-то другая несчастная жертва. Для этого есть некоторая эвристика, с которой я не очень знаком. См. " oom-killer ".)

На некоторые другие ваши вопросы ответы для меня менее понятны.

Почему это поведение отличается при запуске под GDB и без отладчика?
Может быть (на самом деле, просто догадка), что GDB имеет свой собственный malloc и каким-то образом отслеживает ваши выделения. В некотором родстве я часто обнаруживал, что куча ошибок в моем коде часто не воспроизводится при отладчиках. Это расстраивает и заставляет меня почесать голову, но в основном это то, с чем я, по-моему, должен жить ...
Как мне это исправить?

Это решение с кувалдой (то есть оно меняет поведение всех процессов, а не только ваше собственное, и вообще не рекомендуется, чтобы ваша программа изменяла глобальное состояние таким образом ), но вы можете написать строку от 2 до /proc/sys/vm/overcommit_memory. См. эту ссылку , которую я получил из поиска Google.

Если это не удастся ... Я бы просто удостоверился, что вы не выделяете больше, чем ожидаете.

2 голосов
/ 01 марта 2010

По определению работа в отладчике отличается от работы в автономном режиме. Отладчики могут и действительно скрывают многие ошибки. Если вы компилируете для отладки, вы можете добавить изрядное количество кода, аналогично компиляции совершенно неоптимизированной (например, позволяя вам выполнять пошаговые действия или наблюдать за переменными). В то время как компиляция для релиза может удалить опции отладки и удалить нужный код, существует множество ловушек оптимизации, в которые вы можете попасть. Из вашего поста я не знаю, кто контролирует параметры компиляции или что они собой представляют.

Если вы не планируете поставлять продукт для запуска под отладчиком, вам следует проводить тестирование в автономном режиме. В идеале, делать свою разработку без отладчика, избавляет вас от необходимости делать все дважды.

Звучит как ошибка в вашем коде, медленно перечитывайте ваш код, используя новые взгляды, как если бы вы объясняли это кому-то или, возможно, фактически объясняли это кому-то построчно. Там может быть что-то, что вы не можете видеть, потому что вы смотрели на это одинаково слишком долго. Удивительно, сколько раз и насколько хорошо это работает.

Я также мог быть ошибкой компилятора. Такие вещи, как распечатка возвращаемого значения или нет, могут привести к тому, что компилятор сгенерирует другой код. Добавление другой переменной и сохранение результата в этой переменной может заставить компилятор сделать что-то другое. Попробуйте изменить параметры компилятора, уменьшить или удалить любые параметры оптимизации, уменьшить или удалить параметры компилятора отладчика и т. Д.

Это проверенная система или вы разрабатываете новое оборудование? Попробуйте запустить, например, без включенного кэша. Работая в отладчике, а не в автономном режиме, если не ошибка компилятора, то это может быть проблемой синхронизации, одношаговое изменение очищает линию, смешивает кэш по-разному, дает системе кеша и памяти вечность, чтобы получить результат, которого у него нет в режиме реального времени.

Короче говоря, существует очень длинный список причин, по которым работа под отладчиком скрывает ошибки, которые вы не можете найти, пока не протестируете в окончательной среде, подобной конечному результату. Я затронул лишь несколько из них. Работать в отладчике, а не в автономном режиме, не является неожиданностью, это просто то, как работают инструменты. Вероятно, это ваш код, аппаратное обеспечение или ваши инструменты, основанные на описании, которое вы дали.

Самый быстрый способ устранить это, используя ваш код или инструменты, - это разобрать раздел и проверить, как обрабатываются переданные и возвращаемые значения. Если возвращаемое значение оптимизировано, есть ваш ответ.

Вы компилируете для общей библиотеки C или статической? Возможно скомпилировать для статики ...

...