Repository navigation
Instrumentation
Instrumentation is applied on LLVM modules in src/compilerlib/instrumentation/. Every hook the
passes insert is declared in include/coretrace/runtime_abi.h: the passes take the callee name
and the LLVM function type from that header, so a pass and the runtime cannot drift apart
silently. See Runtime Library.
| Pass | Entry point | Main inserted hooks |
|---|---|---|
| Allocation | wrapAllocCalls() |
__ct_malloc, __ct_free, __ct_new, __ct_delete, __ct_realloc, __ct_mmap, … |
| Bounds | instrumentMemoryAccesses() |
__ct_check_bounds, __ct_stack_push, __ct_stack_pop
|
| Trace | instrumentModule() |
__ct_trace_enter, typed exit hooks (void/i64/ptr/f64/unknown) |
| VTable | instrumentVirtualCalls() |
__ct_vtable_dump, __ct_vcall_trace
|
| Objective-C | Apple targets only | __ct_objc_track |
The pass rewrites allocator and deallocator calls from a rewrite table rather than from
scattered per-name checks (alloc_names.cpp, with unit coverage in
test/unit/alloc_names_test.cpp). It covers:
-
malloc,calloc,realloc,free; - C++
operator new/delete, scalar and array, as mangled by the Itanium C++ ABI (Linux, macOS) and the Microsoft C++ ABI (Windows x64 and ARM64 mangle them identically); -
posix_memalign,aligned_alloc,mmap/munmap,sbrk/brk; - allocation sites whose result the program provably never uses, rewritten to the
*_unreachablevariant so the runtime can release them at once; - auto-free calls at function exit for allocations proven unreachable at compile time.
| Operator | Rewritten |
|---|---|
operator new, operator new[]
|
plain and nothrow
|
aligned operator new
|
never — the runtime allocates through the unaligned operator |
operator delete, operator delete[]
|
plain, sized, nothrow and destroying-delete |
aligned operator delete
|
Itanium only |
Aligned operator delete is rewritten for Itanium alone, where aligned blocks come from
aligned_alloc and any operator delete may release them. The Microsoft CRT allocates them with
_aligned_malloc, which only the aligned operator delete may release, so rewriting it there
would hand the block to the wrong deallocator.
Some toolchains prefix Itanium names with an extra underscore; the lookup drops it.
Allocations are tracked with an interned file:line:col site string, which is what the reports
name.
Instrumented accesses: loads, stores, atomic memory operations and llvm.mem* intrinsics. Each
check receives the base pointer, the accessed pointer, the access size, the site string and the
read/write mode.
Checks cover heap blocks and the stack objects of running frames; a stack violation is
reported as stack-buffer-overflow.
A local array or struct is registered with __ct_stack_push for the duration of its frame when:
- its address escapes, for instance to a callee, or
- an access to it cannot be proven in bounds at compile time.
Accesses proven in bounds are not checked at all. __ct_stack_pop restores the registry depth
when the frame exits, so an unwind does not leave dead objects registered.
As for heap blocks, an access is checked when its base is the start of the object — or any
address inside it with --ct-shadow-aggressive, which is what makes container_of-style
patterns checkable.
Not tracked: variable-length arrays, and objects beyond the 512 innermost ones each thread
registers (kCtStackObjectCapacity).
Bounds checks rely on allocation metadata. Enabling bounds while alloc is disabled sets
bounds_without_alloc and emits a warning.
Inserts __ct_trace_enter at function entry and a typed exit hook chosen from the return type;
non-user and runtime functions are skipped through shared filtering helpers. Objective-C methods
are reported under their Objective-C name, such as -[Greeter greet:].
Instruments indirect virtual-style calls when it can recover a this pointer pattern:
-
dump_vtable→__ct_vtable_dump(this, site, static_type) -
trace_calls→__ct_vcall_trace(this, callee, site, static_type)
The runtime side resolves the vtable against the Itanium ABI on POSIX and the MSVC ABI on Windows.
On Apple targets the allocation pass also emits __ct_objc_track for objects created with
+alloc, +allocWithZone:, +new or [[X alloc] init]. See Objective-C Support.
include/compilerlib/instrumentation/config.hpp:
| Field | Default |
|---|---|
shadow_enabled |
false |
shadow_aggressive |
false |
bounds_no_abort |
false |
trace_enabled |
true |
alloc_enabled |
true |
bounds_enabled |
true |
vtable_enabled |
false |
vcall_trace_enabled |
false |
vtable_diag_enabled |
false |
autofree_enabled |
false |
alloc_trace_enabled |
true |
bounds_without_alloc |
derived |
optnone_enabled |
false |
extractRuntimeConfig() reads the --ct-* flags out of the argument list;
emitRuntimeConfigGlobals() writes the corresponding weak ODR globals into the module, which is
how the runtime learns the build's configuration. See
Configuration model.
frontend/OptNoneAction wraps frontend actions to force optnone/noinline on user functions.
It is controlled by --ct-optnone and applies even without --instrument.
Start
Architecture
Instrumentation
Platforms
Developer