Is there a way to get the stacktrace from an error object?

I have an object with type MethodError. I want to print the stacktrace (ie, backtrace) to see where it occurred. How do I do that? I see a method backtrace but it doesn’t take an argument.

propertynames(err) reveals only one property: :msg.

not really, IIRC the Error object only contains error (what function, what world age, what argument etc.), not the backtrace

Okay. I’m trying to embed Julia. If I run a file of Julia code, from C code, and I get an error back (from jl_exception_occured), it seems I have no way to print the stack trace or useful source location info.

Depending on the precise situation, maybe rethrow can help you out. But yeah the error object doesn’t contain the full stacktrace

Aside from a full stacktrace, does it contain any source location info at all? It seems, no. And if that’s the case, I don’t see how you can embed a non-trivial amount of Julia code.

Julia will scan the current execution stack when encountering errors. The source location and other debug information are allocated and set up with the stack frame. It seems that there’s a experimental function Base.catch_stack which is suitable for your task. But you still need to wrap your code in a try-catch-block to provide an exception handle.

Do you mean wrap in try/catch in C code? Something like this? (not working)

JL_TRY {
    jl_value_t *result = jl_eval_string(code);
    // result in null, catch block does not run
}
JL_CATCH {
    jl_printf((JL_STREAM*)STDERR_FILENO, "ERROR:\n");
    jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception());
    jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
    jl_print_backtrace(); // backtrace(); // written to STDERR_FILENO
}

I copied that use of the JL_TRY and JL_CATCH macros from Julia’s C code.

I guess jl_eval_string already has a try-catch-block and simply ignores the error for you, so you need to dig into jl_eval_string further to find out the actual function.

JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str)
{
    jl_value_t *r;
    JL_TRY {
        const char filename[] = "none";
        jl_value_t *ast = jl_parse_all(str, strlen(str),
                filename, strlen(filename));
        JL_GC_PUSH1(&ast);
        r = jl_toplevel_eval_in(jl_main_module, ast);
        JL_GC_POP();
        jl_exception_clear();
    }
    JL_CATCH {
        jl_current_task->ptls->previous_exception = jl_current_exception();
        r = NULL;
    }
    return r;
}

This is the definition of jl_eval_string. Simply duplicating this function and adding your exception handling code to JL_CATCH should be fine.

1 Like