Поиск по сайту:

Что такое разрушение стека? Можно ли это исправить?


Каждая минута простоя производства, как правило, стоит компании денег. Если в вашем приложении есть серьезная проблема, которая приводит к разрушению стека, вас ждет поездка. Узнайте, что такое разгром стека и что с этим можно сделать!

Что такое разрушение стека?

Работая инженером по обеспечению качества, вы рано или поздно столкнетесь с термином разгром стека. Как разработчик, вы, вероятно, обнаружите этот термин еще раньше, особенно если вы внесли в код ошибку, которая приводит к разрушению стека. Для разработчика относительно легко (как в «несколько легко») совершить ошибку, которая приводит к разрушению стека. Как пользователь, когда вы узнаете о разрушении стека, ущерб, скорее всего, уже нанесен.

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

Разрушение стека — это довольно расплывчатый термин, который может указывать на различные проблемы и может исходить из разных источников. Две наиболее важные проблемы, которые могут привести к разрушению стека: 1) записывать/перераспределять слишком много данных в данной части стека, тем самым перезаписывая другую часть стека, и 2) когда какой-то внешний источник (вредоносный или нет) перезаписывал стек другой программы, хотя это гораздо реже .

Так что же такое стек? Это тоже расплывчатый термин. Вообще говоря, стек относится к стеку обработки программы, стеку функций, определенных в данной программе/коде программного обеспечения.

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

Представьте себе, что каждая сложенная плитка — это функция в компьютерной программе. Самая основная функция находится внизу и может быть, например, функцией main() в программе C или C++. C и C++ — это два языка программирования, которые широко используют стек.

Каждая из этих функций в программе C/C++ будет иметь имя и, вероятно, набор входящих и исходящих переменных. Проще говоря, представьте, если бы одна из этих переменных имела длину 10 символов, а какая-то другая функция случайно записала в эту переменную 100 символов. Это может повредить весь стек.

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

Аналогия работает, потому что так же, как все фрагменты в нашем фиктивном образе памяти теперь сломаны, разбитый стек приведет к «сломанным функциям», если хотите. Каждое смещение плитки — это функция, вложенная глубже — подробнее о сломанных функциях в следующем разделе.

Отладка разбитых стеков

Принимая во внимание, что технически ссылка на «сломанные функции» может быть не совсем корректной, т. е., вероятно, существует только одна сломанная функция, а при внешней атаке или неисправной программе может даже не быть сломанной функции, это отличный способ подумать о разбитом стеке.

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

Вообще говоря, когда мы смотрим на обратную трассировку, она будет иметь четкий поток функций, которые были вызваны. Хотя сбойную программу нельзя сразу назвать «исправной», с точки зрения трассировки/отладки «исправная» трассировка выглядит следующим образом:

Однако когда стек поврежден, отладка становится намного сложнее. Стек может выглядеть так:

Это пример проблемы с разрушением стека, которая произошла в MySQL, сервере базы данных (см. вложение log.txt к ошибке MySQL 37815 для полного вывода) в 2008 году, что вызвало демон сервера базы данных ( mysqld) для завершения.

В то время как библиотека операционной системы libc.so.6 в этом случае, по-видимому, достаточно хорошо справилась с разрушением стека (используя некоторые функции укрепления в функции __fortify_fail), проблема существовала где-то в коде и с тех пор была исправлена.

Также обратите внимание, что в этом случае мы не видим разрешенных имен функций, нам показывают только двоичное имя (что интересно, проблема, похоже, была в клиенте (mysql), что вызывало сервер (mysqld) для завершения), который является mysql, вместе с адресом памяти функции: mysql[0x8051565], mysql[0x80525c7] и mysql(main+0x4f8)[0x8053198].

Обычно, когда мы используем отладочные символы (см. ниже статью о GDB, в которой подробно объясняется, что такое отладочные символы), мы видим имена функций с переменными, и даже с некоторыми уровнями бинарной оптимизации/минификации мы бы, по крайней мере, см. имена функций, точно так же, как мы видим в первой «здоровой» трассировке выше.

Однако в случае разбитого стека вывод имен функций, имен переменных или значений никогда не гарантируется и часто является полной чепухой :) Мы можем даже увидеть другие имена функций или полностью искаженный стек (еще один жаргон, часто используемый ИТ-специалистами) различных имен функций, которые не имеют особого смысла (и, вероятно, являются вымышленными/неверными, поскольку стек каким-то образом был перезаписан).

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

Что делать, если вы столкнулись с разгромом стека?

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

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

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

Внимательно прочитайте каждый бит файлов журнала до, во время и после возникновения проблемы. Сделайте несколько резервных копий и повторите операцию. Опять провал или нет? Исследуйте ошибки, части стека и даже фреймы (т. е. показанные отдельные функции стека, такие как функция do_the_maths в нашей исходной «здоровой» трассировке стека), которые можно поместить в ваши любимые поисковые системы.

Объединение (с пробелом) наиболее отобранных (верхних) кадров сбоев и поиск таких же в Интернете часто приводит к обнаружению существующего отчета об ошибке для проблемы, с которой вы столкнулись. Тем не менее, в случае разрушения стека, вероятно, эти фреймы (имена функций) исказились и поэтому больше не могут использоваться таким же образом. Если вы видите сообщение об утверждении (установленное разработчиком утверждение в коде) любого рода, найдите и его.

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

Вам также может быть интересно прочитать нашу следующую статью Отладка с помощью GDB: Начало работы, так как она строится на том, как программы C и C++ (и другие) можно отлаживать с помощью отладчика GDB. Он также подробно объясняет концепции стека.