-
-
Notifications
You must be signed in to change notification settings - Fork 31k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-127604: Add C stack dumps to faulthandler
#128159
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some PEP-7 nits but I don't know if this was done to be aligned with the rest of the code so you can freely ignore those nits.
@ZeroIntensity If you ever use the web UI, don't forget to replace my tabs with spaces... hopefully your IDE does it but I see that I have tabs instead of spaces on my suggestions (I've corrected them but just double-check) |
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
…thon into c-faulthandler
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
…thon into c-faulthandler
🤖 New build scheduled with the buildbot fleet by @ZeroIntensity for commit e79e661 🤖 If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! I did start playing around with an implementation myself, and looks like we made a couple different implementation decisions:
Instead of adding a dump_c_stack
function, I added a kwarg to dump_traceback
. I think I prefer your approach here, since a user may want to see the c backtrace but doesn't care about the python traceback. Though that does clash somewhat with it being a kwarg to enable
(and register
/dump_traceback_later
).
I named my kwarg c_backtrace
, though I think I prefer c_stack
to avoid backtrace/traceback confusion.
I also added a kwarg to register()
, and dump_traceback_later
could also get it.
I made all functions raise an exception if passed c_stack=True
and it wasn't available, and added a global faulthandler.HAS_C_BACKTRACE
. I'm not sure what the best approach is here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard to review it on a small screen. Will do a more precise review in 2 weeks when I'm back if the PR is still open.
Modules/faulthandler.c
Outdated
{ | ||
static volatile int reentrant = 0; | ||
|
||
if (reentrant) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some missing PEP-7 here (on mobile so not sure if this is consistent with the rest of the file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm just keeping consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PEP 7 should be respected for new code.
@@ -264,6 +283,32 @@ faulthandler_dump_traceback_py(PyObject *self, | |||
Py_RETURN_NONE; | |||
} | |||
|
|||
static PyObject * | |||
faulthandler_dump_c_stack_py(PyObject *self, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not using clinic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but faulthandler doesn't have anything in AC yet. I'd be happy to do it in a follow-up, but for now lets keep it as-is.
Python/traceback.c
Outdated
} | ||
for (int i = 0; i < frames; ++i) { | ||
char entry_str[TRACEBACK_ENTRY_MAX_SIZE]; | ||
snprintf(entry_str, TRACEBACK_ENTRY_MAX_SIZE, " %s\n", strings[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we do I in general, but you can suppress the return value of snprintf. I have been suppressing unused return values when used in a void function or if it's an inline call, but only for some function (ideally I'd like to do it everywhere but since we don't have a compiler warning because of this for now, I don't do it for old code that I'm not modifying).
OTOH, isn't the return value the number of characters that were written to the buffer? (excluding the null byte) why can't you use it instead of recomputing strlen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYM suppress it, like a (void)
cast? (Speaking of this though, we should use PyOS_snprintf
.)
OTOH, isn't the return value the number of characters that were written to the buffer?
I vaguely remember looking this up when I wrote it. I think it only returns the full length if the passed string was NULL
, and then otherwise returns the number of missing characters if the string wasn't big enough. From IBM's docs: "The return value is the number of characters (not counting the terminating null character) that would have been written if n had been large enough."
Python/traceback.c
Outdated
for (int i = 0; i < frames; ++i) { | ||
char entry_str[TRACEBACK_ENTRY_MAX_SIZE]; | ||
snprintf(entry_str, TRACEBACK_ENTRY_MAX_SIZE, " %s\n", strings[i]); | ||
size_t length = strlen(entry_str) + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed it previously but we would also replace the last characters for formatted strings that fitted perfectly right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but I'm not sure it's worth the extra effort to add a case for it.
Python/traceback.c
Outdated
char entry_str[TRACEBACK_ENTRY_MAX_SIZE]; | ||
snprintf(entry_str, TRACEBACK_ENTRY_MAX_SIZE, " %s\n", strings[i]); | ||
size_t length = strlen(entry_str) + 1; | ||
if (length == TRACEBACK_ENTRY_MAX_SIZE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could extract this in a function as this could perhaps improve readability although you're not forced to
This only adds it for glibc right now. I think it's possible to implement it for Windows with
StackWalk64
, but I'd prefer to get a solid working implementation for other systems before I dive into that.faulthandler
#127604📚 Documentation preview 📚: https://cpython-previews--128159.org.readthedocs.build/en/128159/library/faulthandler.html#dumping-the-c-stack