Как эта инструкция Intel Xeon MOV повреждает память моего приложения? - PullRequest
0 голосов
/ 13 марта 2019

У меня есть приложение, созданное с помощью gcc v7.3.0 и выполняющееся на микросхеме Intel(R) Xeon(R) CPU E3-1220 v6, которое детерминирует повреждение стековой памяти и получает SEGV из-за выполнения инструкции mov. Я запустил valgrind, и о повреждениях памяти не сообщалось.

У меня в стеке struct SolutionPattern, а его переменная-член типа const float * const & забивается, когда я начинаю вызывать функцию-член inline void RoleToEquation(float threshold). В GDB при вводе функции-члена четвертая инструкция mov %rdi,-0x18(%rbp) вызывает повреждение, как показано в отладчике:

Dump of assembler code for function SolutionPattern::RoleToEquation(float):
   0x00007fff9556b684 <+0>: push   %rbp
   0x00007fff9556b685 <+1>: mov    %rsp,%rbp
   0x00007fff9556b688 <+4>: sub    $0x20,%rsp
=> 0x00007fff9556b68c <+8>: mov    %rdi,-0x18(%rbp)
   0x00007fff9556b690 <+12>:    movss  %xmm0,-0x1c(%rbp)
   0x00007fff9556b695 <+17>:    mov    -0x18(%rbp),%rax
   0x00007fff9556b699 <+21>:    pxor   %xmm0,%xmm0
   0x00007fff9556b69d <+25>:    movss  %xmm0,0x88(%rax)
   0x00007fff9556b6a5 <+33>:    mov    -0x18(%rbp),%rax
   [...]
End of assembler dump.
(gdb) si
Hardware watchpoint 99: *$285

Old value = (const float * const) 0x7fffafb6087a <fflush+106>
New value = (const float * const) 0x7fffffff9ac0
0x00007fff9556b690 in SolutionPattern::RoleToEquation (this=0x7fffffff9ac0, threshold=4.59163468e-41) at calculate_edge.h:250
(gdb) disas
Dump of assembler code for function SolutionPattern::RoleToEquation(float):
   0x00007fff9556b684 <+0>: push   %rbp
   0x00007fff9556b685 <+1>: mov    %rsp,%rbp
   0x00007fff9556b688 <+4>: sub    $0x20,%rsp
   0x00007fff9556b68c <+8>: mov    %rdi,-0x18(%rbp)
=> 0x00007fff9556b690 <+12>:    movss  %xmm0,-0x1c(%rbp)
   0x00007fff9556b695 <+17>:    mov    -0x18(%rbp),%rax
   0x00007fff9556b699 <+21>:    pxor   %xmm0,%xmm0
   0x00007fff9556b69d <+25>:    movss  %xmm0,0x88(%rax)
   0x00007fff9556b6a5 <+33>:    mov    -0x18(%rbp),%rax
   [...]
End of assembler dump.

Исходный код функции-члена начинается так:

inline void RoleToEquation(float threshold) {
    A = B = 0.f;
    C = threshold;
    D = E = 0.f;
    F = threshold;

    [...]
}

A, B, C, D, E и F являются float переменными-членами структуры, которые появляются через несколько переменных-членов после повреждения памяти.

Я не до конца разбираюсь в разборке, но похоже, что настройка функции все еще выполняется, а настройка от A и B до 0.f еще не началась. Я замечаю в отладчике, что аргумент threshold не инициализируется до тех пор, пока не будет выполнена пятая инструкция movss. Как код, устанавливающий переменную аргумента threshold в стеке, приводит к повреждению структуры, расположенной в памяти стека вызывающего фрейма?

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

1 Ответ

1 голос
/ 13 марта 2019

mov %rdi,-0x18(%rbp) просто проливает первую функцию arg. (Указатель this, так как это функция-член.)

Это ничего не «портит», вы просто скомпилировали с отключенной оптимизацией, поэтому все попадает в память между операторами C ++, включая все аргументы функции (неявные и явные) при входе в функцию.

-0x18(%rbp) находится внутри 0x20 байтов собственного стекового фрейма этой функции, зарезервировано с помощью sub $0x20,%rsp (после mov %rsp, %rbp установите указатель фрейма так, чтобы он указывал на qword ниже адреса возврата).

Как код, устанавливающий пороговое значение переменной аргумента в стеке, приводит к повреждению структуры, находящейся в памяти стека вызывающего фрейма?

Это не так. movss %xmm0,-0x1c(%rbp) также хранит внутри собственного стекового фрейма этой функции . Это 4-байтовое хранилище прямо под пролитым указателем this. (Это отрицательные смещения, и 0x1c - 0x18 = 4 = ширина магазина.)


Если вы нашли это, установив точку наблюдения HW , возможно, это был адрес локального. Функция, содержащая этот local, вернулась, и теперь эта память стека используется повторно в качестве фрейма стека для другого вызова другой функции.

...