`<stacktrace>`: investigate sporadic failure of `CaptureStackBackTrace`
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 11.1k
- Forks
- 1.7k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 22
Description
When trying to solve #3859, I find that stacktrace::current can fail sporadically.
Repro (benchmark)
#include <benchmark/benchmark.h>
#include <iostream>
#include <stacktrace>
using namespace std;
#pragma optimize("", off)
stacktrace get_current(int extra_depth) {
if (extra_depth > 0) {
return get_current(extra_depth - 1);
}
else {
return stacktrace::current(1);
}
}
#pragma optimize("", on)
void BM_bef(benchmark::State& state) {
const int extra_depth = state.range(0);
for (auto _ : state) {
stacktrace cur = get_current(extra_depth);
if (cur.size() < extra_depth) {
cout << extra_depth << "->" << cur.size() << endl;
terminate();
}
}
}
BENCHMARK(BM_bef)->Arg(0)->Arg(100)->Arg(150)->Arg(300);
BENCHMARK_MAIN();
Potential result
After investigation, it turns out the failure is not due to memory exception in current. The function rely on CaptureStackBackTrace to catch frames, which just can fail sporadically:
https://github.com/microsoft/STL/blob/f51733ca5352c712165e46fdbc5d0d395971f0e7/stl/src/stacktrace.cpp#L252
Repro (CaptureStackBackTrace)
#include <Windows.h>
#include <iostream>
void* frames[1024];
#pragma optimize("", off)
long catch_some_frames(int extra_depth) {
if (extra_depth > 0) {
return catch_some_frames(extra_depth - 1);
}
else {
return CaptureStackBackTrace(0, 1024, frames, nullptr);//sporadic crash: "300->0"
}
}
#pragma optimize("", on)
int main() {
for (;;) {
auto caught = catch_some_frames(300);
if (caught < 300) {
std::cout << 300 << "->" << caught << std::endl;
terminate();
}
else {
std::cout << "*";
}
}
}
Potential result
CaptureStackBackTrace is a macro for RtlCaptureStackBackTrace. As to it randomly returning 0, I find these similar issues:
https://github.com/milostosic/MTuner/issues/66
https://developercommunity.visualstudio.com/t/capturestackbacktrace-randomly-fails-after-initial/1383213
And there might be other problems with it:
https://developercommunity.visualstudio.com/t/passing-framestoskip-greater-than-254-to-rtlcaptur/548661
Both the sporadic fail and skip-clamp behavior is not documented in its (documentation) (2).
And its API design is the root case for basic_stacktrace::current's efficiency problem.
We need to investigate what's going on with CaptureStackBackTrace when it returns 0. Also, we might be better off exploring other ways to capture stack frames, including implementing our own capture function in STL library. If possible, this will also give a chance to solve #3859 as a by-catch.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the CaptureStackBackTrace reproducer in the issue and inspect stl/src/stacktrace.cpp around line 252. Compare the sporadic zero-frame result and skip behavior against the linked Windows API documentation and reports. Done requires a documented root cause and an agreed direction for addressing the failure or replacing the capture approach.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- operating-systems, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100