stringtranslate.com

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

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

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

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

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

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

Питон

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

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

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

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

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

Ява

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

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

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

java.lang.Exception : трассировка стека в java.lang.Thread.dumpStack ( Thread.java:1336 ) в Main.demo3 ( Main.java:15 ) в Main.demo2 ( Main.java:12 ) в Main.demo1 ( Main.java:9 ) в Main.demo ( Main.java:6 ) в Main.main ( Main.java:3 )              

С и С++

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

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

. / a . out () [ 0x40067f ] . / a . out () [ 0x4006fe ] . / a . out () [ 0x40070a ] / lib / x86_64 - linux - gnu / libc . so .6 ( __libc_start_main + 0xf5 ) [ 0x7f7e60738f45 ] . / a . out () [ 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 стек backtrace : 0 : std :: sys :: imp :: backtrace :: tracing :: imp :: unwind_backtrace 1 : std :: panicking :: default_hook :: { { closure } } 2 : std :: panicking :: default_hook 3 : std :: panicking :: rust_panic_with_hook 4 : std :: panicking :: begin_panic 5 : futures :: task_impl :: with 6 : futures :: task_impl :: park .. .            

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

Ссылки

  1. ^ "libc manual: backtraces". gnu.org . Получено 8 июля 2014 г. .
  2. ^ "traceback — Распечатать или получить трассировку стека". python.org . Получено 8 июля 2014 г. .
  3. ^ "Thread (Java SE 16 и JDK 16)". Спецификация API Java Platform Standard Edition и Java Development Kit версии 16 . 2021-03-04 . Получено 2021-07-04 .
  4. ^ "Environment.StackTrace Property (System)". Microsoft Docs . 2021-05-07 . Получено 2021-07-04 .
  5. ^ "Thread (Java Platform SE 8)". docs.oracle.com . Получено 15.06.2021 .
  6. ^ ab "Backtraces (The GNU C Library)". www.gnu.org . Получено 2021-06-15 .
  7. ^ "Начало работы - 1.76.0". www.boost.org . Получено 15.06.2021 .
  8. ^ «Рабочий проект, стандарт языка программирования C++» (PDF) . open-std.org . ISO/IEC. 2021-10-23. стр. 766.
  9. ^ "rustonomicon unwinding - Rust". doc.rust-lang.org .
  10. ^ "std::backtrace - Rust". doc.rust-lang.org . Получено 15.06.2021 .