Skip to content

Commit eadb56b

Browse files
committed
[sancov] Document -fsanitize-coverage=stack-depth
Add documentation to detail the behaviors of the stack-depth tracer, including the new -fsanitize-coverage-stack-depth-callback-min=N argument.
1 parent b252941 commit eadb56b

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

clang/docs/SanitizerCoverage.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,50 @@ Users need to implement a single function to capture the CF table at startup:
385385
// the collected control flow.
386386
}
387387
388+
Tracing Stack Depth
389+
===================
390+
391+
With ``-fsanitize-coverage=stack-depth`` the compiler will track how much
392+
stack space has been used for a function call chain. Leaf functions are
393+
not included in this tracing.
394+
395+
The maximum depth of a function call graph is stored in the thread-local
396+
``__sancov_lowest_stack`` variable. Instrumentation is inserted in every
397+
non-leaf function to check the frame pointer against this variable,
398+
and if it is lower, store the current frame pointer. This effectively
399+
inserts the following:
400+
401+
.. code-block:: c++
402+
403+
extern thread_local uintptr_t __sancov_lowest_stack;
404+
405+
uintptr_t stack = (uintptr_t)__builtin_frame_address(0);
406+
if (stack < __sancov_lowest_stack)
407+
__sancov_lowest_stack = stack;
408+
409+
If ``-fsanitize-coverage-stack-depth-callback-min=N`` (where
410+
``N > 0``) is also used, the tracking is delegated to a callback,
411+
``__sanitizer_cov_stack_depth``, instead of adding instrumentation to
412+
update ``__sancov_lowest_stack``. The ``N`` of the argument is used
413+
to determine which functions to instrument. Only functions estimated
414+
to be using ``N`` bytes or more of stack space will be instrumented to
415+
call the tracing callback. In the case of a dynamically sized stack,
416+
the callback is unconditionally added.
417+
418+
The callback takes no arguments and is responsible for determining
419+
the stack usage and doing any needed comparisons and storage. A roughly
420+
equivalent implementation of ``__sancov_lowest_stack`` using the callback
421+
would look like this:
422+
423+
.. code-block:: c++
424+
425+
void __sanitizer_cov_stack_depth(void) {
426+
uintptr_t stack = (uintptr_t)__builtin_frame_address(0);
427+
428+
if (stack < __sancov_lowest_stack)
429+
__sancov_lowest_stack = stack;
430+
}
431+
388432
Gated Trace Callbacks
389433
=====================
390434

llvm/include/llvm/Transforms/Utils/Instrumentation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ struct SanitizerCoverageOptions {
158158
bool PCTable = false;
159159
bool NoPrune = false;
160160
bool StackDepth = false;
161-
int StackDepthCallbackMin = 0;
162161
bool TraceLoads = false;
163162
bool TraceStores = false;
164163
bool CollectControlFlow = false;
165164
bool GatedCallbacks = false;
165+
int StackDepthCallbackMin = 0;
166166

167167
SanitizerCoverageOptions() = default;
168168
};

llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
11081108
for (auto &I : BB) {
11091109
if (auto *AI = dyn_cast<AllocaInst>(&I)) {
11101110
// Move potential insertion point past the "alloca".
1111-
InsertBefore = I.getNextNode();
1111+
InsertBefore = AI->getNextNode();
11121112

11131113
// Make an estimate on the stack usage.
11141114
if (AI->isStaticAlloca()) {

0 commit comments

Comments
 (0)