Книга: Разработка приложений в среде Linux. Второе издание
7.2.1. Поиск повреждений кучи
7.2.1. Поиск повреждений кучи
Когда память распределяется в куче, функциям управления памятью необходимо место для хранения информации о распределениях. Таким местом является сама куча; это значит, что куча состоит из чередующихся областей памяти, которые используются программами и самим функциями управления памятью. Это означает, что переполнения или недополнение буфера может фактически повредить структуру данных, которую отслеживают функции управления памятью. В такой ситуации есть много шансов, что сами функции управления памятью, в конце концов, приведут к сбою программы.
Если вы установили переменную окружения MALLOC_CHECK_
, выбирается другой, несколько более медленный набор функций управления памятью. Этот набор более устойчив к ошибкам и может обнаруживать ситуации, когда free()
вызывается более одного раза для одного и того же указателя, а также когда происходят однобайтные переполнения буфера. Если MALLOC_CHECK_
установлена в 0
, функции управления памятью просто более устойчивы к ошибкам, но не выдают никаких предупреждений. Если MALLOC_CHECK_
установлена в 1
, функции управления памятью выводят предупреждения о стандартных ошибках при замеченной проблеме. Если MALLOC_CHECK_
установлена в 2
, функции управления памятью вызывают abort()
, когда замечают проблемы.
Установка MALLOC_CHECK_
в 0
может оказаться полезной, если вам мешает найти ошибку в памяти другая ошибка, которую в этот момент исправить нет возможности; эта установка позволяет работать с другими средствами отслеживания ошибок памяти.
Установка MALLOC_CHECK_
в 1
полезна в случае, когда никаких проблем не видно, поэтому определенные уведомления могут помочь.
Установка MALLOC_CHECK_
в 2
наиболее полезна при работе в отладчике, поскольку при возникновении ошибки он позволяет выполнить обратную трассировку вплоть до функций управления памятью. В результате вы максимально приблизитесь к месту возникновения ошибки.
$ MALLOC_CHECK_=1 ./broken
malloc: using debugging hooks
malloc: используются отладочные функции
1: 12345
free(): invalid pointer 0x80ac008!
free(): недопустимый указатель 0x80ac008!
2: 12345678
3: 12345678
4: 12345
5: 12345
6: 12345
7: 12345
$ MALLOC_CHECK_=2 gdb ./broken
...
(gdb) run
Starting program: /usr/src/lad/code/broken
Запуск программы: /usr/src/lad/code/broken
1: 12345
Program received signal SIGABRT, Aborted.
Программа получила сигнал SIGABRT, прервана.
0x00 с 64 с 32 in _dl_sysinfo_int80() from/lib/ld-linux.so.2
(gdb) where
#0 0x00c64c32 in _dl_sysinfo_int80() from /lib/ld-linux.so.2
#1 0x00322969 in raise() from /lib/tls/libc.so.6
#2 0x00324322 in abort() from /lib/tls/libc.so.6
#3 0x0036d9af in free_check() from /lib/tls/libc.so.6
#4 0x0036afa5 in free() from /lib/tls/libc.so.6
#5 0x0804842b in broken() at broken.c:17
#6 0x08048520 in main() at broken.с:47
Другой способ заставить glibc
проверить кучу на непротиворечивость — воспользоваться функцией mcheck()
:
typedef void(*mcheck Callback)(enummcheck_status status);
void mcheck(mcheck Callback cb) ;
В случае вызова функции mcheck()
, функция malloc()
размещает известные последовательности байтов перед и после возвращенной области памяти, чтобы можно было обнаружить переполнение или недогрузку буфера, free()
ищет эти сигнатуры и, если они были повреждены, вызывает функцию, указанную аргументом cb
. Если cb
равен NULL
, выполняется выход. Запуск программы, связанной с mcheck()
, в gdb может показать, какие именно области памяти были повреждены, если только они явно освобождаются с помощью free()
. Однако метод mcheck()
не может точно определить место ошибки; лишь программист может вычислить это, основываясь на понимании логики работы программы.
Компоновка нашей тестовой программы с mcheck
дает следующие результаты:
$ gcc -ggdb -о broken broken.с -lmcheck
$ ./broken
1: 12345
memory clobbered past end of allocated block
память разрушена после конца распределенного блока
Вследствие того, что mcheck
всего лишь выдает сообщения об ошибках и завершает работу, найти ошибку невозможно. Для точного обнаружения ошибки потребуется запустить программу внутри gdb
и заставить mcheck
вызывать abort()
при обнаружении ошибки. Можно просто вызвать mcheck()
внутри gdb
или поместить mcheck(1)
в первой строке вашей программы (веред вызовом malloc()
). (Следует отметить, что mcheck()
можно вызвать в gdb
без необходимости компоновки программы с библиотекой mcheck
.)
$ rm -f broken; make broken
$ gdb broken
...
(gdb) break main
Breakpoint 1 at 0x80483f4: file broken.c, line 14.
Точка прерывания 1 по адресу 0x80483f4: файл broken, с, строка 14.
(gdb) command 1
Type commands for when Breakpoint 1 is hit, one per line.
End with a line saying just "end".
Наберите команды, которые выполнятся при достижении точки прерывания 1, по одной в строке.
Завершите строкой, содержащей только "end".
> call mcheck(&abort)
> continue
> end (gdb) run
Starting program: /usr/src/lad/code/broken
Запуск программы: /usr/src/lad/code/broken
Breakpoint 1, main () at broken.с: 14
47 return broken();
$1 = 0
1: 12345
Program received signal SIGABRT, Aborted.
Программа получила сигнал SIGABRT, прервана.
0x00e12c32 in _dl_sysinfo_int80() from /lib/ld-linux.so.2
(gdb) where
#00x00el2c32 in _dl_sysinfo_int80() from /lib/ld-linux.so.2
#1 0x0072c969 in raise() from /lib/tls/libc.so.6
#2 0x0072e322 in abort() from /lib/tls/libc.so.6
#3 0x007792c4 in freehook() from /lib/tls/libc.so.6
#4 0x00774fa5 in free() from /lib/tls/libc.so.6
#5 0x0804842b in broken() at broken.c:17
#6 0x08048520 in main() at broken.с:47
Важной частью этого кода является обнаруженная ошибка в строке 17 файла broken.с
. Видно, что ошибка была обнаружена во время первого вызова free(), который указал на наличие проблемы в области памяти dyn
. (freehook()
представляет собой ловушку, с помощью которой mcheck
выполняет проверки.)
Библиотека mcheck
не может помочь в обнаружении переполнения или недогрузки буфера в локальных или глобальных переменных, а только в областях памяти, распределенных с помощью malloc()
.
- Профилактика повреждений баз данных InterBase
- 13.3.4. Поиск и замена текста
- Фильтры и поиск
- 1.3.1. Индексирование сайта в поисковых системах
- Глава 4 Поиск и выбор идеи
- Глава 1 Поиск (Найдется всё!)
- Нормально ли воспринимается поисковыми системами маскировка партнерских ссылок?
- Общие рекомендации поиска неисправностей
- Поиск и устранение неисправностей модулей памяти
- Поиск источников информации
- Как указать направление поиска в Microsoft Word?
- 1.2.3. Поисковый механизм