0x08086550 0x3 at /home/arnold/Gnu/gawk/gawk-3.1.3/node.с:337
0x08086560 0x3 at /home/arnold/Gnu/gawk/gawk-3.1.3/node.c:337
0x080865e0 0x4 at /home/arnold/Gnu/gawk/gawk-3.1.3/field.c:76
0x08086670 0x78 at /home/arnold/Gnu/gawk/gawk-3.1.3/awkgram.y:1369
0x08086700 0xe at /home/arnold/Gnu/gawk/gawk-3.1.3/node.c:337
0x08086718 0x1f at /home/arnold/Gnu/gawk/gawk-3.1.3/awkgram.y:1259
Вывод представляет собой список мест, в которых gawk
выделяет память, которая в дальнейшем не освобождается. Обратите внимание, что постоянное подвешивание к динамической памяти является замечательным, если это сделано намеренно. Все показанные здесь случаи являются выделениями такого рода.
15.5.2.2. Electric Fence
В разделе 3.1 «Адресное пространство Linux/Unix» мы описали, как динамическая память выделяется из кучи, которая может расти и сокращаться (с помощью вызовов brk()
или sbrk()
, описанных в разделе 3.2.3 «Системные вызовы: brk()
и sbrk()
»).
Ну, картина, которую мы там представили, является упрощением действительности. Более развитые системные вызовы (не рассматриваемые в данной книге) позволяют добавлять в адресное пространство процесса дополнительные, необязательно смежные сегменты памяти. Многие отладчики malloc()
работают с использованием этих системных вызовов для добавления новых областей адресного пространства при каждом выделении. Преимуществом этой схемы является то, что операционная система и аппаратное обеспечение защиты памяти компьютера взаимодействуют для обеспечения недействительности доступа к памяти за пределами этих изолированных сегментов, генерируя сигнал SIGSEGV
. Эта схема изображена на рис. 15.1.
Рис. 15.1. Адресное пространство Linux/Unix, включая специальные области
Первым пакетом отладки, реализовавшим эту схему, был Electric Fence. Electric Fence является вставляемым заместителем для malloc()
и др. Он работает на многих системах Unix и GNU/Linux; он доступен с FTP архива его авторов.[178] Он поставляется также со многими дистрибутивами GNU/Linux, хотя, возможно, вам придется выбрать ею явным образом при установке системы.
После компоновки программы с Electric Fence любой доступ за пределами выделенной памяти генерирует SIGSEGV
. Electric Fence также перехватывает попытки использования уже освобожденной памяти. Вот простая программа, которая иллюстрирует обе проблемы.
1 /* ch15-badmem1.с --- плохо обращается с памятью */
2
3 #include
4 #include
5
6 int main(int argc, char **argv)
7 {
8 char *p;
9 int i;
10
11 p = malloc(30);
12
13 strcpy(p, "not 30 bytes");
14 printf("p = <%s>\n", p);
15
16 if (argc ==2) {
17 if (strcmp(argv[1], "-b") == 0)
18 p[42] = 'a'; /* коснуться за пределами границы */
19 else if (strcmp(argv[1], "-f") == 0) {
20 free(p); /* освободить память, затем использовать ее */
21 p[0] = 'b';
22 }
23 }
24
25 /* освобождение (p); */
26
27 return 0;
28 }
Эта программа осуществляет простую проверку опций командной строки, чтобы решить, как вести себя плохо: -b
вызывает доступ к памяти за ее выделенными страницами, а -f
пытается использовать освобожденную память. (Строки 18 и 21 являются соответственно опасными.) Обратите внимание, что без опций указатель никогда не освобождается (строка 25), Electric Fence не перехватывает этот случай.
Одним из способов использования Electric Fence, способом, который гарантированно работает на различных системах Unix и GNU/Linux, является статическая компоновка с ним вашей программы. Затем программа должна быть
$ cc -g ch15-badmem1.c -lefence -о ch15-badmem1 /* Откомпилировать; компоновка статическая */
$ gdb ch15-badmem1 /* Запустить из отладчика */
GNU gdb 5.3
...