Используя очень простой пример, который использует 2 указателя.Указатель 1 (s1_buffer) имеет значение malloc, а затем memset.Указатель 2 (s2_buffer) имеет значение malloc, а затем memset сразу после этого, поэтому мы надеемся, что местоположение будет близко к указателю 1 (что это такое).
Конечно, это не самый предпочтительный метод использования указателей и структур, но он используетсясделано для имитации другого кода.Цель состоит в том, чтобы понять, что происходит за кулисами и что показывает GDB.
Вот код:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
struct
{
int a;
int b;
int c;
int d;
} n_s;
int e;
} struct1;
typedef struct
{
char aa[5];
int bb;
} struct2;
int main () {
struct1 s1;
struct2 s2;
int * s1_buffer = (int*) 0;
int * s2_buffer = (int*) 0;
printf("Size...\n");
printf(" s1 : %d\n", sizeof (struct1));
printf(" s2 : %d\n", sizeof (struct2));
int numOfElements = 1;
s1_buffer = ( int*) malloc((numOfElements * sizeof (struct1)));
memset((int *)s1_buffer, 0, (numOfElements * sizeof (struct1)));
s2_buffer = ( int*) malloc((numOfElements * sizeof (struct2)));
memset((int *)s2_buffer, 0, (numOfElements * sizeof (struct2)));
//The following shows that the memory locations are close to each other.
printf("\nMemory Location... \n");
printf(" s1_buffer : %p\n", s1_buffer);
printf(" s2_buffer : %p\n", s2_buffer);
numOfElements = 2;
//Here a memset is done WITHOUT doing a malloc and since the size is
//now twice as large Pointer 1's area should overwrite Pointer 2's memory.
memset((int *)s1_buffer, 0, (numOfElements * sizeof (struct1)));
printf("\nFreeing Memory... \n");
printf(" s1_buffer\n");
free(s1_buffer);
printf(" s2_buffer\n");
free(s2_buffer);
return(0);
}
При запуске программы выдается следующий вывод.
> ./memFreeTest
Size...
s1 : 20
s2 : 12
Memory Location...
s1_buffer : 0x16a6010
s2_buffer : 0x16a6030
Freeing Memory...
s1_buffer
*** Error in `./memFreeTest': free(): invalid next size (fast): 0x00000000016a6010 ***
======= Backtrace: =========
/usr/lib64/libc.so.6(+0x7c503)[0x2af569904503]
./memFreeTest[0x4007b1]
/usr/lib64/libc.so.6(__libc_start_main+0xf5)[0x2af5698a9b35]
./memFreeTest[0x400589]
======= Memory map: ========
На основе адресов s1_buffer и s2_buffer они находятся в пределах 32байты друг друга.Когда второй набор настроек s1_buffer завершен, он должен наступить на область s2_buffer.
Анализируя файл ядра через gdb, после вызова «disassemble main» и просмотра регистров видно следующее.
0x0000000000400779 <+300>: shl $0x2,%rax
0x000000000040077d <+304>: mov %rax,%rdx
0x0000000000400780 <+307>: mov -0x8(%rbp),%rax
0x0000000000400784 <+311>: mov $0x0,%esi
0x0000000000400789 <+316>: mov %rax,%rdi
Ниже приводится второй набор настроек.
0x000000000040078c <+319>: callq 0x400520 <memset@plt>
Почему он перемещает значение $ 0x4008c9 в значение edi?
0x0000000000400791 <+324>: mov $0x4008c9,%edi
0x0000000000400796 <+329>: callq 0x400500 <puts@plt>
0x000000000040079b <+334>: mov $0x4008dd,%edi
0x00000000004007a0 <+339>: callq 0x400500 <puts@plt>
0x00000000004007a5 <+344>: mov -0x8(%rbp),%rax
0x00000000004007a9 <+348>: mov %rax,%rdi
0x00000000004007ac <+351>: callq 0x4004f0 <free@plt>
Следующая строка гдеэто терпит неудачу.Почему он переносит значение $ 0x4008ea в edi?
Я имею в виду edi, поскольку, похоже, именно там произошел сбой.
=> 0x00000000004007b1 <+356>: mov $0x4008ea,%edi
Проверка edi и, по-видимому, он действителен:
(gdb) info reg edi
edi 0x19569 103785
Выход dgb продолжается здесь:
0x00000000004007b6 <+361>: callq 0x400500 <puts@plt>
0x00000000004007bb <+366>: mov -0x10(%rbp),%rax
0x00000000004007bf <+370>: mov %rax,%rdi
0x00000000004007c2 <+373>: callq 0x4004f0 <free@plt>
0x00000000004007c7 <+378>: mov $0x0,%eax
0x00000000004007cc <+383>: leaveq
0x00000000004007cd <+384>: retq
End of assembler dump.
(gdb) info reg
rax 0x0 0
rbx 0x0 0
rcx 0xffffffffffffffff -1
rdx 0x6 6
rsi 0x19569 103785
rdi 0x19569 103785
rbp 0x7ffdc0b23440 0x7ffdc0b23440
rsp 0x7ffdc0b23400 0x7ffdc0b23400
r8 0x2af5699fe840 47233527441472
r9 0x2af569886000 47233525899264
r10 0x8 8
r11 0x246 582
r12 0x400560 4195680
r13 0x7ffdc0b23520 140727836357920
r14 0x0 0
r15 0x0 0
rip 0x4007b1 0x4007b1 <main+356>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) info reg edi
edi 0x19569 103785
Файл ядра появляется на первом свободном,Как он узнал, что эта память не "принадлежит" s1_buffer?
Если он знает, что не «владеет» им, чтобы освободить его, почему он не знал, что ему не принадлежит область, являющаяся memset?Похоже, ошибка или предупреждение должны были появиться в то время.