C++ zeigt Stack-Trace bei Ausnahme an

Lesezeit: 6 Minuten

C zeigt Stack Trace bei Ausnahme an
rlbond

Ich möchte eine Möglichkeit haben, dem Benutzer den Stack-Trace zu melden, wenn eine Ausnahme ausgelöst wird. Was ist der beste Weg, dies zu tun? Braucht es riesige Mengen an zusätzlichem Code?

Um Fragen zu beantworten:

Ich möchte, dass es tragbar ist, wenn möglich. Ich möchte, dass Informationen angezeigt werden, damit der Benutzer den Stack-Trace kopieren und mir per E-Mail senden kann, wenn ein Fehler auftritt.

C zeigt Stack Trace bei Ausnahme an
Thomas Tempelmann

Die Antwort von Andrew Grant tut es nicht helfen, einen Stack-Trace der zu erhalten werfen funktionieren, zumindest nicht mit GCC, da eine throw-Anweisung den aktuellen Stack-Trace nicht selbst speichert und der catch-Handler an dieser Stelle keinen Zugriff mehr auf den Stack-Trace hat.

Die einzige Möglichkeit – mit GCC – dies zu lösen, besteht darin, sicherzustellen, dass am Punkt der Throw-Anweisung ein Stack-Trace generiert und mit dem Ausnahmeobjekt gespeichert wird.

Diese Methode erfordert natürlich, dass jeder Code, der eine Ausnahme auslöst, diese bestimmte Ausnahmeklasse verwendet.

Aktualisierung 11. Juli 2017: Für hilfreichen Code werfen Sie einen Blick auf die Antwort von cahit beyaz, die auf verweist http://stacktrace.sourceforge.net – Ich habe es noch nicht benutzt, aber es sieht vielversprechend aus.

  • Leider ist der Link tot. Könnten Sie etwas anderes zur Verfügung stellen?

    – warran

    20. Mai 2015 um 14:29 Uhr

  • Und archive.org weiß es auch nicht. Verdammt. Nun, das Verfahren sollte klar sein: Werfen Sie ein Objekt einer benutzerdefinierten Klasse aus, das den Stack-Trace zum Zeitpunkt des Wurfs aufzeichnet.

    – Thomas Tempelmann

    20. Mai 2015 um 21:21 Uhr

  • Auf der Homepage von StackTrace sehe ich throw stack_runtime_error. Sehe ich richtig, dass diese Bibliothek nur für Ausnahmen funktioniert, die von dieser Klasse abgeleitet sind, und nicht für std::exception oder Ausnahmen von Bibliotheken von Drittanbietern?

    – Thomas

    15. November 2017 um 7:33 Uhr

  • Die Antwort lautet leider “Nein, Sie können keinen Stack-Trace von einer C++-Ausnahme erhalten”. Die einzige Option besteht darin, Ihre eigene Klasse zu werfen, die einen Stack-Trace generiert, wenn sie erstellt wird. Wenn Sie mit Dingen wie, sagen wir, irgendeinem Teil der C++-Bibliothek std:: nicht weiterkommen, haben Sie Pech. Tut mir leid, du zu sein.

    – Code-Abominator

    28. November 2017 um 21:19 Uhr


1646878809 969 C zeigt Stack Trace bei Ausnahme an
Andreas Grant

Es kommt darauf an, welche Plattform.

Auf GCC ist es ziemlich trivial, siehe diesen Beitrag für weitere Details.

Auf MSVC kannst du dann die verwenden StackWalker Bibliothek, die alle zugrunde liegenden API-Aufrufe verarbeitet, die für Windows benötigt werden.

Sie müssen herausfinden, wie Sie diese Funktionalität am besten in Ihre App integrieren können, aber die Menge an Code, die Sie schreiben müssen, sollte minimal sein.

  • Der Beitrag, auf den Sie verlinken, weist hauptsächlich darauf hin, eine Ablaufverfolgung aus einem Segfault zu generieren, aber der Fragesteller erwähnt ausdrücklich Ausnahmen, die ein ganz anderes Tier sind.

    – Schaf

    13. März 2014 um 14:29 Uhr


  • Ich stimme @Shep zu – diese Antwort hilft nicht wirklich dabei, einen Stack-Trace des Wurfcodes auf GCC zu erhalten. Siehe meine Antwort für eine mögliche Lösung.

    – Thomas Tempelmann

    12. November 2014 um 9:17 Uhr

  • Diese Antwort ist irreführend. Der Link verweist auf eine spezifische Antwort auf Linux nicht gcc.

    – fjardon

    2. Mai 2018 um 9:21 Uhr

  • Sie können den Wurfmechanismus von überschreiben libstdc++ (wird von GCC und möglicherweise Clang verwendet), wie in dieser Antwort erläutert.

    – www.ingomueller.net

    5. September 2019 um 8:12 Uhr

1646878810 783 C zeigt Stack Trace bei Ausnahme an
Vasek

Wenn Sie Boost 1.65 oder höher verwenden, können Sie verwenden boost::stacktrace:

#include <boost/stacktrace.hpp>

// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();

  • Die Boost-Dokumente Erklären Sie nicht nur das Erfassen eines Stack-Trace, sondern auch, wie Sie dies für Ausnahmen und Assertionen tun. Tolles Zeug.

    – Stimmungsboom

    14. Januar 2018 um 18:45 Uhr


  • Gibt dieser stacktrace() Quelldatei- und Zeilennummern aus, wie im Handbuch “Erste Schritte” angegeben?

    – Gimhani

    29. Januar 2019 um 5:55 Uhr

Ich möchte eine hinzufügen Standard-Bibliotheksoption (dh plattformübergreifend) wie man Ausnahme-Backtraces generiert, die mit verfügbar geworden sind C++11:

Verwenden std::nested_exception und std::throw_with_nested

Dies wird Ihnen keine Stapelabwicklung geben, aber meiner Meinung nach das nächstbeste. Es ist auf StackOverflow hier und hier beschrieben, wie man das machen kann Holen Sie sich einen Backtrace für Ihre Ausnahmen in Ihrem Code, ohne dass ein Debugger oder umständliches Protokollieren erforderlich ist, indem Sie einfach einen geeigneten Ausnahmehandler schreiben, der verschachtelte Ausnahmen erneut auslöst.

Da Sie dies mit jeder abgeleiteten Ausnahmeklasse tun können, können Sie einem solchen Backtrace viele Informationen hinzufügen! Sie können sich auch gerne meine ansehen MWE auf GitHubwobei ein Backtrace etwa so aussehen würde:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

1646878810 575 C zeigt Stack Trace bei Ausnahme an
bobobobo

Unix: zurückverfolgen

Mac: zurückverfolgen

Fenster: CaptureBackTrace

1646878810 685 C zeigt Stack Trace bei Ausnahme an
sonnentief singh

Wenn Sie C++ verwenden und Boost nicht verwenden möchten/können, können Sie mithilfe des folgenden Codes Backtrace mit entstellten Namen drucken [link to the original site].

Beachten Sie, dass diese Lösung spezifisch für Linux ist. Es verwendet die libc-Funktionen backtrace()/backtrace_symbols() (aus execinfo.h) von GNU, um die Backtraces abzurufen, und verwendet dann __cxa_demangle() (aus cxxabi.h), um die Backtrace-Symbolnamen zu entwirren.

// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0

#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_

#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>

/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
    fprintf(out, "stack trace:\n");

    // storage array for stack trace address data
    void* addrlist[max_frames+1];

    // retrieve current stack addresses
    int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));

    if (addrlen == 0) {
    fprintf(out, "  <empty, possibly corrupt>\n");
    return;
    }

    // resolve addresses into strings containing "filename(function+address)",
    // this array must be free()-ed
    char** symbollist = backtrace_symbols(addrlist, addrlen);

    // allocate string which will be filled with the demangled function name
    size_t funcnamesize = 256;
    char* funcname = (char*)malloc(funcnamesize);

    // iterate over the returned symbol lines. skip the first, it is the
    // address of this function.
    for (int i = 1; i < addrlen; i++)
    {
    char *begin_name = 0, *begin_offset = 0, *end_offset = 0;

    // find parentheses and +address offset surrounding the mangled name:
    // ./module(function+0x15c) [0x8048a6d]
    for (char *p = symbollist[i]; *p; ++p)
    {
        if (*p == '(')
        begin_name = p;
        else if (*p == '+')
        begin_offset = p;
        else if (*p == ')' && begin_offset) {
        end_offset = p;
        break;
        }
    }

    if (begin_name && begin_offset && end_offset
        && begin_name < begin_offset)
    {
        *begin_name++ = '\0';
        *begin_offset++ = '\0';
        *end_offset="\0";

        // mangled name is now in [begin_name, begin_offset) and caller
        // offset in [begin_offset, end_offset). now apply
        // __cxa_demangle():

        int status;
        char* ret = abi::__cxa_demangle(begin_name,
                        funcname, &funcnamesize, &status);
        if (status == 0) {
        funcname = ret; // use possibly realloc()-ed string
        fprintf(out, "  %s : %s+%s\n",
            symbollist[i], funcname, begin_offset);
        }
        else {
        // demangling failed. Output function name as a C function with
        // no arguments.
        fprintf(out, "  %s : %s()+%s\n",
            symbollist[i], begin_name, begin_offset);
        }
    }
    else
    {
        // couldn't parse the line? print the whole line.
        fprintf(out, "  %s\n", symbollist[i]);
    }
    }

    free(funcname);
    free(symbollist);
}

#endif // _STACKTRACE_H_

HTH!

1646878811 940 C zeigt Stack Trace bei Ausnahme an
Nico Brailovsky

AFAIK libunwind ist ziemlich portabel und bisher habe ich nichts einfacher zu bedienendes gefunden.

  • libunwind 1.1 baut nicht auf os x auf.

    – xaxxon

    20. Mai 2016 um 8:19 Uhr

985660cookie-checkC++ zeigt Stack-Trace bei Ausnahme an

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy