LINUX.ORG.RU

История изменений

Исправление wandrien, (текущая версия) :

Я как-то долго пытался понять, что не так с кодом, который работает на более новых компиляторах, но на gcc 4.x.x (сколько-то там, не помню точную версию) валит программу абсолютно без видимой причины. Дело под 32-битной системой было.

Код был приблизительно такой, схематически изображаю:

static int foo_real_impl(int* a, int* b, int c, int d /* тут на самом деле несколько разных типов, включая указатели на разные структуры */)
{
  /* тут куча логики с вызовами разных функции,
     которые вызывают еще кучу функций.
     довольно глубокий уровень вложенности вызовов на стеке.

     И где-то в глубине этого кода программа падала из-за обращения по битому указателю.
  */
}

int foo(int* a, int* b, int d)
{
  return foo_real_impl(a, b, 0, d); 
}

Так вот когда я пытался анализировать стек после падения, там были видны функции которые были глубже, чем foo(), и также были видны те, который ближе к верхушке стека, чем foo(). А самой foo() не было.

Аргументы функций в глубине стека были частично бредовыми, было ясно, что там битые указатели и мусор.

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

В итоге я выписал хекс-дамп стека в текстовый файлик и пошел вручную из самой глубины расставлять комменты в нём, где какой фрейм, где какой аргумент и какая переменная.

В итоге пришел к тому, что что-то не так с кодом foo(), потому что именно она портит аргументы. Дизассемблировал функцию и обнаружил что да - что-то не так.

Компилятор, видя что, что foo_real_impl() - это static, решил присвоить ей соглашение о вызове fastcall и передать часть аргументов в регистрах. Далее при генерации кода для foo() он применяет оптимизацию, аналогичную хвостовой рекурсии, когда он не вызывает вложенную функцию, а замещает ею текущую функцию на стеке.

Поэтому foo() на стеке и не видна была.

Но генерируемый код, который аргументы должен в правильном порядке разложить, содержал ошибку, из-за которой в один из указателей попадало неверное значение.

В общем, на ошибку в компиляторе наткнулся.

Исправление wandrien, :

Я как-то долго пытался понять, что не так с кодом, который работает на более новых компиляторах, но на gcc 4.x.x (сколько-то там, не помню точную версию) валит программу абсолютно без видимой причины. Дело под 32-битной системой было.

Код был приблизительно такой, схематически изображаю:

static int foo_real_impl(int* a, int* b, int c, int d /* тут на самом деле несколько разных типов, включая указатели на разные структуры */)
{
  /* тут куча логики с вызовами разных функции,
     которые вызывают еще кучу функций.
     довольно глубокий уровень вложенности вызовов на стеке.

     И где-то в глубине этого кода программа падала из-за обращения по битому указателю.
  */
}

int foo(int* a, int* b, int d)
{
  return foo_real_impl(a, b, 0, d); 
}

Так вот когда я пытался анализировать стек после падения, там были видны функции которые были глубже, чем foo(), и также были видны те, который ближе к верхушке стека, чем foo(). А самой foo() не было.

Аргументы функций в глубине стека были частично бредовыми, было ясно, что там битые указатели и мусор.

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

В итоге я выписал хекс-дамп стека в текстовый файлик и пошел вручную из самой глубины расставлять комменты в нём, где какой фрейм, где какой аргумент и какая переменная.

В итоге пришел к тому, что что-то не так с кодом foo(), потому что именно она портит аргументы. Дизассемблировал функцию и обнаружил что да - что-то не так.

Компилятор, видя что, что foo_real_impl() - это static, решил присвоить ей соглашение о вызове fastcall. далее при генерации кода для foo() он применяет оптимизацию, аналогичную хвостовой рекурсии, когда он не вызывает вложенную функцию, а замещает ею текущую функцию на стеке.

Поэтому foo() на стеке и не видна была.

Но генерируемый код, который аргументы должен в правильном порядке разложить, содержал ошибку, из-за которой в один из указателей попадало неверное значение.

В общем, на ошибку в компиляторе наткнулся.

Исправление wandrien, :

Я как-то долго пытался понять, что не так с кодом, который работает на более новых компиляторах, но на gcc 4.x.x (сколько-то там, не помню точную версию) валит программу абсолютно без видимой причины. Дело под 32-битной системой было.

Код был приблизительно такой, схематически изображаю:

static int foo_real_impl(int* a, int* b, int c, int d /* тут на самом деле несколько разных типов, включая указатели на разные структуры */)
{
  /* тут куча логики с вызовами разных функции,
     которые вызывают еще кучу функций.
     довольно глубокий уровень вложенности вызовов на стеке.

     И где-то в глубине этого кода программа падала из-за обращения по битому указателю.
  */
}

int foo(int* a, int* b, int d)
{
  return foo_real_impl(a, b, 0, d); 
}

Так вот когда я пытался анализировать стек после падения, там были видны функции которые были глубже, чем foo(), и также были видны те, который ближе к верхушке стека, чем foo(). А самой foo() не было.

Аргументы функций в глубине стека были частично бредовыми, было ясно, что там битые указатели и мусор.

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

В итоге я выписал хекс-дамп стека в текстовый файлик и пошле вручную из самой глубины расставлять комменты в нём, где какой фрейм, где какой аргумент и какая переменная.

В итоге пришел к тому, что что-то не так с кодом foo(), потому что именно она портит аргументы. Дизассемблировал функцию и обнаружил что да - что-то не так.

Компилятор, видя что, что foo_real_impl() - это static, решил присвоить ей соглашение о вызове fastcall. далее при генерации кода для foo() он применяет оптимизацию, аналогичную хвостовой рекурсии, когда он не вызывает вложенную функцию, а замещает ею текущую функцию на стеке.

Поэтому foo() на стеке и не видна была.

Но генерируемый код, который аргументы должен в правильном порядке разложить, содержал ошибку, из-за которой в один из указателей попадало неверное значение.

В общем, на ошибку в компиляторе наткнулся.

Исходная версия wandrien, :

Я как-то долго пытался понять, что не так с кодом, который работает на более новых компиляторах, но на gcc 4.x.x (сколько-то там, не помню точную версию) валит программу абсолютно без видимой причины. Дело под 32-битной системой было.

Код был приблизительно такой, схематически изображаю:

static int foo_real_impl(int* a, int* b, int c, int d /* тут на самом деле несколько разных типов, включая указатели на разные структуры */)
{
  /* тут куча логики с вызовами разных функции,
     которые вызывают еще кучу функций.
     довольно глубокий уровень вложенности вызовов на стеке.

     И где-то в глубине этого кода программа падала из-за обращения по битому указателю.
  */
}

int foo(int* a, int* b, int d)
{
  return foo_real_impl(a, b, 0, d); 
}

Так вот когда я пытался анализировать стек после падения, там были видны функции которые были глубже, чем foo(), и ближе к верхушке стека, чем foo(). А самой foo() не было.

Аргументы функций в глубине стека были частично бредовыми, было ясно, что там битые указатели и мусор.

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

В итоге я выписал хекс-дамп стека в текстовый файлик и пошле вручную из самой глубины расставлять комменты в нём, где какой фрейм, где какой аргумент и какая переменная.

В итоге пришел к тому, что что-то не так с кодом foo(), потому что именно она портит аргументы. Дизассемблировал функцию и обнаружил что да - что-то не так.

Компилятор, видя что, что foo_real_impl() - это static, решил присвоить ей соглашение о вызове fastcall. далее при генерации кода для foo() он применяет оптимизацию, аналогичную хвостовой рекурсии, когда он не вызывает вложенную функцию, а замещает ею текущую функцию на стеке.

Поэтому foo() на стеке и не видна была.

Но генерируемый код, который аргументы должен в правильном порядке разложить, содержал ошибку, из-за которой в один из указателей попадало неверное значение.

В общем, на ошибку в компиляторе наткнулся.