This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new d063f470 [FFI][FIX] Backtrace: refresh DbgHelp modules, tolerate bad
TVM_TRACEBACK_LIMIT, match object_is_not_callable exactly (#763)
d063f470 is described below
commit d063f470b4973bda02da85b7d7e61b8de927acd0
Author: Tianqi Chen <[email protected]>
AuthorDate: Mon Sep 7 20:54:22 2026 -0400
[FFI][FIX] Backtrace: refresh DbgHelp modules, tolerate bad
TVM_TRACEBACK_LIMIT, match object_is_not_callable exactly (#763)
Four small fixes from the follow-up report on #727:
- `backtrace_win.cc`: `SymRefreshModuleList` before `StackWalk64`. The
session is created once, so a DLL loaded after the first backtrace was
unknown to DbgHelp; `StackWalk64` needs its unwind tables, so the trace
truncated at that frame.
- `backtrace_win.cc`: the explicit caller frame goes through
`ShouldExcludeFrame`, as `backtrace.cc` already does.
- `backtrace_utils.h`: `TVM_TRACEBACK_LIMIT` parsed with `strtol`,
default on invalid input. `std::stoi` threw inside the error reporter
and terminated the process.
- `backtrace_utils.h`: full-identifier match for
`object_is_not_callable`; the 11-character prefix also matched other
`object_is_n...` symbols.
No behaviour change for valid inputs.
---
src/ffi/backtrace_utils.h | 12 ++++++++++--
src/ffi/backtrace_win.cc | 9 ++++++++-
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/ffi/backtrace_utils.h b/src/ffi/backtrace_utils.h
index 346d51c7..16135c35 100644
--- a/src/ffi/backtrace_utils.h
+++ b/src/ffi/backtrace_utils.h
@@ -26,6 +26,8 @@
#include <tvm/ffi/base_details.h>
+#include <climits>
+#include <cstdlib>
#include <cstring>
#include <sstream>
#include <string>
@@ -41,7 +43,13 @@ namespace ffi {
inline int32_t GetBacktraceLimit() {
if (const char* env = std::getenv("TVM_TRACEBACK_LIMIT")) {
- return std::stoi(env);
+ char* end = nullptr;
+ long value = std::strtol(env, &end, 10); // NOLINT(runtime/int)
+ // An empty, non-numeric, negative, or out-of-range value falls back to the
+ // default rather than throwing from inside the error reporter.
+ if (end != env && *end == '\0' && value >= 0 && value <= INT32_MAX) {
+ return static_cast<int32_t>(value);
+ }
}
return 512;
}
@@ -120,7 +128,7 @@ inline bool DetectFFIBoundary(const char* filename, const
char* symbol) {
if (strncmp(symbol, "slot_tp_call", 12) == 0) {
return true;
}
- if (strncmp(symbol, "object_is_not_callable", 11) == 0) {
+ if (strncmp(symbol, "object_is_not_callable", 22) == 0) {
return true;
}
// Python interpreter stack frames
diff --git a/src/ffi/backtrace_win.cc b/src/ffi/backtrace_win.cc
index 6f782b90..9fc2ad53 100644
--- a/src/ffi/backtrace_win.cc
+++ b/src/ffi/backtrace_win.cc
@@ -89,7 +89,9 @@ const TVMFFIByteArray* TVMFFIBacktrace(const char* filename,
int lineno, const c
// need to skip TVMFFIBacktrace and the caller function
// which is already included in filename and func
backtrace.skip_frame_count = 2;
- backtrace.Append(filename, func, lineno);
+ if (!tvm::ffi::ShouldExcludeFrame(filename, func)) {
+ backtrace.Append(filename, func, lineno);
+ }
}
HANDLE thread = GetCurrentThread();
@@ -105,6 +107,11 @@ const TVMFFIByteArray* TVMFFIBacktrace(const char*
filename, int lineno, const c
backtrace_array.size = backtrace_str.size();
return &backtrace_array;
}
+ // Register modules loaded since the session was created. StackWalk64 needs a
+ // module's unwind tables to step through it, so a DLL DbgHelp does not know
+ // truncates the walk at its first frame rather than just losing the name.
+ SymRefreshModuleList(process);
+
CONTEXT context = {};
RtlCaptureContext(&context);