stringtranslate.com

Трассировки стека

В вычислительной технике трассировка стека (также называемая обратной трассировкой стека [1] или обратной трассировкой стека [2] ) представляет собой отчет об активных кадрах стека в определенный момент времени во время выполнения программы . При запуске программы память часто динамически распределяется в двух местах: в стеке и в куче . Память постоянно выделяется в стеке, а не в куче, что отражает их имена. Стек также относится к программной конструкции, поэтому, чтобы отличить его, этот стек называется стеком вызовов функций программы . Технически, как только блок памяти был выделен в стеке, его невозможно легко удалить, поскольку до него могут быть выделены другие блоки памяти. Каждый раз, когда в программе вызывается функция, поверх стека вызовов выделяется блок памяти, называемый записью активации . Обычно запись активации хранит аргументы функции и локальные переменные. Что именно он содержит и как он расположен, определяется соглашением о вызовах .

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

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

Языковая поддержка

Многие языки программирования, включая Java [3] и C# , [4], имеют встроенную поддержку получения текущей трассировки стека с помощью системных вызовов. До того, как std::stacktraceон был добавлен в стандартную библиотеку в качестве контейнера для std::stacktrace_entry, версия до C++23 не имела встроенной поддержки для этого, но пользователи C++ могут получать трассировки стека с помощью (например) библиотеки stacktrace . В JavaScript исключения содержат свойство , stackсодержащее стек из того места, где он был создан.

Питон

Например, следующая программа Python содержит ошибку.

защита  а (): я  =  0 j  знак равно  б ( я ) вернуть  jзащита  б ( г ): к  =  5 если  г  ==  0 : в () вернуть  k  +  zзащита  c (): ошибка ()а ()

Запуск программы под стандартным интерпретатором Python приводит к следующему сообщению об ошибке.

Traceback (последний последний вызов): Файл «tb.py» , строка 15 , в <module> a () Файл «tb.py» , строка 3 , в a j = b ( i ) Файл «tb.py» , строка 9 , в b c () Файл «tb.py» , строка 13 , в c , ошибка () NameError : имя «ошибка» не определено      

Трассировка стека показывает, где возникает ошибка, а именно в cфункции. Это также показывает, что cфункция была вызвана b, которая была вызвана a, которая, в свою очередь, была вызвана кодом в строке 15 (последняя строка) программы. Записи активации для каждой из этих трех функций будут расположены в стеке таким образом, чтобы функция aзанимала нижнюю часть стека, а cфункция - верхнюю часть стека.

Джава

В Java трассировку стека можно сбросить вручную с помощью Thread.dumpStack()[5]. Введите следующие данные:

общественный класс Main {    public static void main ( String args [] ) {      демо (); } статическая пустота демо () {    демо1 (); } статическая пустота demo1 () {    демо2 (); } статическая пустота demo2 () {    демо3 (); } статическая пустота demo3 () {    Нить . дампСтек (); }}

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

Джава . язык . Исключение : трассировка стека в Java . язык . Нить . dumpStack ( Thread.java:1336 ) в Main . _ _ _ _ demo3 ( Main . java : 15 ) в Main . demo2 ( Main . java : 12 ) в Main . demo1 ( Main . java : 9 ) в Main . демо ( Main.java:6 ) в Main . _ _ _ _ основной ( Main . java : 3 )              

С и С++

И C , и C++ (до C++23 ) не имеют встроенной поддержки получения трассировки стека, но такие библиотеки, как glibc и boost , предоставляют эту функциональность. [6] [7] В этих языках некоторые оптимизации компилятора могут мешать информации стека вызовов, которую можно восстановить во время выполнения. Например, встраивание может привести к отсутствию кадров стека, оптимизация хвостового вызова может заменить один кадр стека другим, а удаление указателя кадра может помешать инструментам анализа стека вызовов правильно интерпретировать содержимое стека вызовов. [6]

Например, функция glibc backtrace()возвращает выходные данные с функцией программы и адресом памяти.

. / а . выход () [ 0x40067f ] . / а . выход () [ 0x4006fe ] . / а . out () [ 0x40070a ] / lib / x86_64 - linux - gnu / libc . итак .6 ( __libc_start_main + 0xf5 ) [ 0x7f7e60738f45 ] . / а . выход () [ 0x400599 ]     

Начиная с C++23 , трассировки стека можно сбрасывать вручную, печатая значение, возвращаемое статической функцией-членом std::stacktrace::current(): [8]

std :: cout << std :: stacktrace :: current () << '\n' ;    

Ржавчина

В Rust есть два типа ошибок. Функции, использующие макрос паники , «невосстановимы», и текущий поток станет отравленным из-за разматывания стека. Функции, возвращающие a, std::result::Resultявляются «восстанавливаемыми», и их можно корректно обрабатывать. [9] Однако исправимые ошибки не могут генерировать трассировку стека, поскольку они добавляются вручную, а не являются результатом ошибки во время выполнения.

По состоянию на июнь 2021 года в Rust имеется экспериментальная поддержка трассировки стека при неисправимых ошибках. Rust поддерживает вывод на stderr , когда поток паникует, но это необходимо включить, установив RUST_BACKTRACE переменную среды . [10]

Когда эта функция включена, такие обратные трассировки выглядят так, как показано ниже: сначала самый последний вызов.

поток ' main ' запаниковал при ' execute_to_panic ' , main . rs : 3 stack backtrace : 0 : std :: sys :: imp :: backtrace :: tracing :: imp :: unwind_backtrace 1 : std :: паника :: default_hook :: {{ замыкание }} 2 : std :: паника : : default_hook 3 : std :: паника :: Rust_panic_with_hook 4 : std :: паника :: Begin_panic 5 : Futures :: Task_impl :: with 6 : Futures :: Task_impl :: Park .. .            

Смотрите также

Рекомендации

  1. ^ «Руководство по libc: обратные трассировки» . gnu.org . Проверено 8 июля 2014 г.
  2. ^ «обратная трассировка — Распечатайте или получите обратную трассировку стека». python.org . Проверено 8 июля 2014 г.
  3. ^ «Тема (Java SE 16 и JDK 16)» . Стандартная версия платформы Java и спецификация API версии 16 пакета разработки Java . 04.03.2021 . Проверено 4 июля 2021 г.
  4. ^ «Свойство Environment.StackTrace (система)» . Документы Майкрософт . 07.05.2021 . Проверено 4 июля 2021 г.
  5. ^ «Тема (платформа Java SE 8)» . docs.oracle.com . Проверено 15 июня 2021 г.
  6. ^ ab «Обратные трассировки (Библиотека GNU C)». www.gnu.org . Проверено 15 июня 2021 г.
  7. ^ «Начало работы — 1.76.0» . www.boost.org . Проверено 15 июня 2021 г.
  8. ^ «Рабочий проект стандарта языка программирования C++» (PDF) . open-std.org . ИСО/МЭК. 2021-10-23. п. 766.
  9. ^ "Размотка рустономикона - Ржавчина" . doc.rust-lang.org .
  10. ^ "std::backtrace - Rust". doc.rust-lang.org . Проверено 15 июня 2021 г.